From c47cdc0d93726429ee18b418b1f85fae67b82d41 Mon Sep 17 00:00:00 2001
From: Michael Woerister <michaelwoerister@posteo.net>
Date: Thu, 30 Mar 2017 15:27:27 +0200
Subject: [PATCH] Introduce HashStable trait and base ICH implementations on
 it.

This initial commit provides implementations for HIR, MIR, and
everything that also needs to be supported for those two.
---
 src/librustc/hir/map/definitions.rs           |    4 +
 src/librustc/ich/hcx.rs                       |  300 +++++
 src/librustc/ich/impls_const_math.rs          |   71 ++
 src/librustc/ich/impls_hir.rs                 | 1104 ++++++++++++++++
 src/librustc/ich/impls_mir.rs                 |  407 ++++++
 src/librustc/ich/impls_syntax.rs              |  301 +++++
 src/librustc/ich/impls_ty.rs                  |  415 ++++++
 src/librustc/ich/mod.rs                       |   28 +-
 src/librustc/lib.rs                           |    1 +
 src/librustc/macros.rs                        |   79 ++
 src/librustc/mir/cache.rs                     |   11 +-
 src/librustc/mir/mod.rs                       |   18 +
 src/librustc/ty/mod.rs                        |   29 +
 src/librustc_data_structures/lib.rs           |    2 +
 src/librustc_data_structures/stable_hasher.rs |  192 ++-
 src/librustc_incremental/calculate_svh/mod.rs |  197 ++-
 .../calculate_svh/svh_visitor.rs              | 1111 -----------------
 src/librustc_incremental/lib.rs               |    1 -
 src/librustc_trans/assert_module_sources.rs   |    7 +-
 src/libsyntax/ptr.rs                          |   12 +
 src/libsyntax/util/rc_slice.rs                |   13 +
 21 files changed, 3080 insertions(+), 1223 deletions(-)
 create mode 100644 src/librustc/ich/hcx.rs
 create mode 100644 src/librustc/ich/impls_const_math.rs
 create mode 100644 src/librustc/ich/impls_hir.rs
 create mode 100644 src/librustc/ich/impls_mir.rs
 create mode 100644 src/librustc/ich/impls_syntax.rs
 create mode 100644 src/librustc/ich/impls_ty.rs
 delete mode 100644 src/librustc_incremental/calculate_svh/svh_visitor.rs

diff --git a/src/librustc/hir/map/definitions.rs b/src/librustc/hir/map/definitions.rs
index 809d5db3071d7..dca9ebb3397a6 100644
--- a/src/librustc/hir/map/definitions.rs
+++ b/src/librustc/hir/map/definitions.rs
@@ -394,6 +394,10 @@ impl Definitions {
         }
     }
 
+    pub fn node_to_hir_id(&self, node_id: ast::NodeId) -> hir::HirId {
+        self.node_to_hir_id[node_id]
+    }
+
     /// Add a definition with a parent definition.
     pub fn create_def_with_parent(&mut self,
                                   parent: Option<DefIndex>,
diff --git a/src/librustc/ich/hcx.rs b/src/librustc/ich/hcx.rs
new file mode 100644
index 0000000000000..73d81212cd77e
--- /dev/null
+++ b/src/librustc/ich/hcx.rs
@@ -0,0 +1,300 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use hir;
+use hir::def_id::DefId;
+use ich::{self, CachingCodemapView, DefPathHashes};
+use session::config::DebugInfoLevel::NoDebugInfo;
+use ty;
+
+use std::hash as std_hash;
+
+use syntax::ast;
+use syntax::attr;
+use syntax::ext::hygiene::SyntaxContext;
+use syntax::symbol::Symbol;
+use syntax_pos::Span;
+
+use rustc_data_structures::stable_hasher::{HashStable, StableHasher,
+                                           StableHasherResult};
+use rustc_data_structures::accumulate_vec::AccumulateVec;
+
+/// This is the context state available during incr. comp. hashing. It contains
+/// enough information to transform DefIds and HirIds into stable DefPaths (i.e.
+/// a reference to the TyCtxt) and it holds a few caches for speeding up various
+/// things (e.g. each DefId/DefPath is only hashed once).
+pub struct StableHashingContext<'a, 'tcx: 'a> {
+    tcx: ty::TyCtxt<'a, 'tcx, 'tcx>,
+    def_path_hashes: DefPathHashes<'a, 'tcx>,
+    codemap: CachingCodemapView<'tcx>,
+    hash_spans: bool,
+    hash_bodies: bool,
+    overflow_checks_enabled: bool,
+    node_id_hashing_mode: NodeIdHashingMode,
+    // A sorted array of symbol keys for fast lookup.
+    ignored_attr_names: Vec<Symbol>,
+}
+
+#[derive(PartialEq, Eq, Clone, Copy)]
+pub enum NodeIdHashingMode {
+    Ignore,
+    HashDefPath,
+    HashTraitsInScope,
+}
+
+impl<'a, 'tcx: 'a> StableHashingContext<'a, 'tcx> {
+
+    pub fn new(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>) -> Self {
+        let hash_spans_initial = tcx.sess.opts.debuginfo != NoDebugInfo;
+        let check_overflow_initial = tcx.sess.overflow_checks();
+
+        let mut ignored_attr_names: Vec<_> = ich::IGNORED_ATTRIBUTES
+            .iter()
+            .map(|&s| Symbol::intern(s))
+            .collect();
+
+        ignored_attr_names.sort();
+
+        StableHashingContext {
+            tcx: tcx,
+            def_path_hashes: DefPathHashes::new(tcx),
+            codemap: CachingCodemapView::new(tcx),
+            hash_spans: hash_spans_initial,
+            hash_bodies: true,
+            overflow_checks_enabled: check_overflow_initial,
+            node_id_hashing_mode: NodeIdHashingMode::HashDefPath,
+            ignored_attr_names: ignored_attr_names,
+        }
+    }
+
+    #[inline]
+    pub fn while_hashing_hir_bodies<F: FnOnce(&mut Self)>(&mut self,
+                                                          hash_bodies: bool,
+                                                          f: F) {
+        let prev_hash_bodies = self.hash_bodies;
+        self.hash_bodies = hash_bodies;
+        f(self);
+        self.hash_bodies = prev_hash_bodies;
+    }
+
+    #[inline]
+    pub fn while_hashing_spans<F: FnOnce(&mut Self)>(&mut self,
+                                                     hash_spans: bool,
+                                                     f: F) {
+        let prev_hash_spans = self.hash_spans;
+        self.hash_spans = hash_spans;
+        f(self);
+        self.hash_spans = prev_hash_spans;
+    }
+
+    #[inline]
+    pub fn with_node_id_hashing_mode<F: FnOnce(&mut Self)>(&mut self,
+                                                           mode: NodeIdHashingMode,
+                                                           f: F) {
+        let prev = self.node_id_hashing_mode;
+        self.node_id_hashing_mode = mode;
+        f(self);
+        self.node_id_hashing_mode = prev;
+    }
+
+    #[inline]
+    pub fn tcx(&self) -> ty::TyCtxt<'a, 'tcx, 'tcx> {
+        self.tcx
+    }
+
+    #[inline]
+    pub fn def_path_hash(&mut self, def_id: DefId) -> u64 {
+        self.def_path_hashes.hash(def_id)
+    }
+
+    #[inline]
+    pub fn hash_spans(&self) -> bool {
+        self.hash_spans
+    }
+
+    #[inline]
+    pub fn hash_bodies(&self) -> bool {
+        self.hash_bodies
+    }
+
+    #[inline]
+    pub fn codemap(&mut self) -> &mut CachingCodemapView<'tcx> {
+        &mut self.codemap
+    }
+
+    #[inline]
+    pub fn is_ignored_attr(&self, name: Symbol) -> bool {
+        self.ignored_attr_names.binary_search(&name).is_ok()
+    }
+
+    pub fn hash_hir_item_like<F: FnOnce(&mut Self)>(&mut self,
+                                                    item_attrs: &[ast::Attribute],
+                                                    f: F) {
+        let prev_overflow_checks = self.overflow_checks_enabled;
+        if attr::contains_name(item_attrs, "rustc_inherit_overflow_checks") {
+            self.overflow_checks_enabled = true;
+        }
+        let prev_hash_node_ids = self.node_id_hashing_mode;
+        self.node_id_hashing_mode = NodeIdHashingMode::Ignore;
+
+        f(self);
+
+        self.node_id_hashing_mode = prev_hash_node_ids;
+        self.overflow_checks_enabled = prev_overflow_checks;
+    }
+
+    #[inline]
+    pub fn binop_can_panic_at_runtime(&self, binop: hir::BinOp_) -> bool
+    {
+        match binop {
+            hir::BiAdd |
+            hir::BiSub |
+            hir::BiMul => self.overflow_checks_enabled,
+
+            hir::BiDiv |
+            hir::BiRem => true,
+
+            hir::BiAnd |
+            hir::BiOr |
+            hir::BiBitXor |
+            hir::BiBitAnd |
+            hir::BiBitOr |
+            hir::BiShl |
+            hir::BiShr |
+            hir::BiEq |
+            hir::BiLt |
+            hir::BiLe |
+            hir::BiNe |
+            hir::BiGe |
+            hir::BiGt => false
+        }
+    }
+
+    #[inline]
+    pub fn unop_can_panic_at_runtime(&self, unop: hir::UnOp) -> bool
+    {
+        match unop {
+            hir::UnDeref |
+            hir::UnNot => false,
+            hir::UnNeg => self.overflow_checks_enabled,
+        }
+    }
+}
+
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for ast::NodeId {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        match hcx.node_id_hashing_mode {
+            NodeIdHashingMode::Ignore => {
+                // Most NodeIds in the HIR can be ignored, but if there is a
+                // corresponding entry in the `trait_map` we need to hash that.
+                // Make sure we don't ignore too much by checking that there is
+                // no entry in a debug_assert!().
+                debug_assert!(hcx.tcx.trait_map.get(self).is_none());
+            }
+            NodeIdHashingMode::HashDefPath => {
+                hcx.tcx.hir.definitions().node_to_hir_id(*self).hash_stable(hcx, hasher);
+            }
+            NodeIdHashingMode::HashTraitsInScope => {
+                if let Some(traits) = hcx.tcx.trait_map.get(self) {
+                    // The ordering of the candidates is not fixed. So we hash
+                    // the def-ids and then sort them and hash the collection.
+                    let mut candidates: AccumulateVec<[_; 8]> =
+                        traits.iter()
+                              .map(|&hir::TraitCandidate { def_id, import_id: _ }| {
+                                  hcx.def_path_hash(def_id)
+                              })
+                              .collect();
+                    if traits.len() > 1 {
+                        candidates.sort();
+                    }
+                    candidates.hash_stable(hcx, hasher);
+                }
+            }
+        }
+    }
+}
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for Span {
+
+    // Hash a span in a stable way. We can't directly hash the span's BytePos
+    // fields (that would be similar to hashing pointers, since those are just
+    // offsets into the CodeMap). Instead, we hash the (file name, line, column)
+    // triple, which stays the same even if the containing FileMap has moved
+    // within the CodeMap.
+    // Also note that we are hashing byte offsets for the column, not unicode
+    // codepoint offsets. For the purpose of the hash that's sufficient.
+    // Also, hashing filenames is expensive so we avoid doing it twice when the
+    // span starts and ends in the same file, which is almost always the case.
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        use syntax_pos::Pos;
+
+        if !hcx.hash_spans {
+            return
+        }
+
+        // If this is not an empty or invalid span, we want to hash the last
+        // position that belongs to it, as opposed to hashing the first
+        // position past it.
+        let span_hi = if self.hi > self.lo {
+            // We might end up in the middle of a multibyte character here,
+            // but that's OK, since we are not trying to decode anything at
+            // this position.
+            self.hi - ::syntax_pos::BytePos(1)
+        } else {
+            self.hi
+        };
+
+        {
+            let loc1 = hcx.codemap().byte_pos_to_line_and_col(self.lo);
+            let loc1 = loc1.as_ref()
+                           .map(|&(ref fm, line, col)| (&fm.name[..], line, col.to_usize()))
+                           .unwrap_or(("???", 0, 0));
+
+            let loc2 = hcx.codemap().byte_pos_to_line_and_col(span_hi);
+            let loc2 = loc2.as_ref()
+                           .map(|&(ref fm, line, col)| (&fm.name[..], line, col.to_usize()))
+                           .unwrap_or(("???", 0, 0));
+
+            if loc1.0 == loc2.0 {
+                std_hash::Hash::hash(&0u8, hasher);
+
+                std_hash::Hash::hash(loc1.0, hasher);
+                std_hash::Hash::hash(&loc1.1, hasher);
+                std_hash::Hash::hash(&loc1.2, hasher);
+
+                // Do not hash the file name twice
+                std_hash::Hash::hash(&loc2.1, hasher);
+                std_hash::Hash::hash(&loc2.2, hasher);
+            } else {
+                std_hash::Hash::hash(&1u8, hasher);
+
+                std_hash::Hash::hash(loc1.0, hasher);
+                std_hash::Hash::hash(&loc1.1, hasher);
+                std_hash::Hash::hash(&loc1.2, hasher);
+
+                std_hash::Hash::hash(loc2.0, hasher);
+                std_hash::Hash::hash(&loc2.1, hasher);
+                std_hash::Hash::hash(&loc2.2, hasher);
+            }
+        }
+
+        if self.ctxt == SyntaxContext::empty() {
+            0u8.hash_stable(hcx, hasher);
+        } else {
+            1u8.hash_stable(hcx, hasher);
+            self.source_callsite().hash_stable(hcx, hasher);
+        }
+    }
+}
diff --git a/src/librustc/ich/impls_const_math.rs b/src/librustc/ich/impls_const_math.rs
new file mode 100644
index 0000000000000..6d11f2a87a413
--- /dev/null
+++ b/src/librustc/ich/impls_const_math.rs
@@ -0,0 +1,71 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! This module contains `HashStable` implementations for various data types
+//! from `rustc_const_math` in no particular order.
+
+impl_stable_hash_for!(enum ::rustc_const_math::ConstFloat {
+    F32(val),
+    F64(val)
+});
+
+impl_stable_hash_for!(enum ::rustc_const_math::ConstInt {
+    I8(val),
+    I16(val),
+    I32(val),
+    I64(val),
+    I128(val),
+    Isize(val),
+    U8(val),
+    U16(val),
+    U32(val),
+    U64(val),
+    U128(val),
+    Usize(val)
+});
+
+impl_stable_hash_for!(enum ::rustc_const_math::ConstIsize {
+    Is16(i16),
+    Is32(i32),
+    Is64(i64)
+});
+
+impl_stable_hash_for!(enum ::rustc_const_math::ConstUsize {
+    Us16(i16),
+    Us32(i32),
+    Us64(i64)
+});
+
+impl_stable_hash_for!(enum ::rustc_const_math::ConstMathErr {
+    NotInRange,
+    CmpBetweenUnequalTypes,
+    UnequalTypes(op),
+    Overflow(op),
+    ShiftNegative,
+    DivisionByZero,
+    RemainderByZero,
+    UnsignedNegation,
+    ULitOutOfRange(int_ty),
+    LitOutOfRange(int_ty)
+});
+
+impl_stable_hash_for!(enum ::rustc_const_math::Op {
+    Add,
+    Sub,
+    Mul,
+    Div,
+    Rem,
+    Shr,
+    Shl,
+    Neg,
+    BitAnd,
+    BitOr,
+    BitXor
+});
diff --git a/src/librustc/ich/impls_hir.rs b/src/librustc/ich/impls_hir.rs
new file mode 100644
index 0000000000000..fb18f50027e29
--- /dev/null
+++ b/src/librustc/ich/impls_hir.rs
@@ -0,0 +1,1104 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! This module contains `HashStable` implementations for various HIR data
+//! types in no particular order.
+
+use hir;
+use hir::def_id::DefId;
+use ich::{StableHashingContext, NodeIdHashingMode};
+use std::mem;
+
+use syntax::ast;
+
+use rustc_data_structures::stable_hasher::{HashStable, StableHasher,
+                                           StableHasherResult};
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for DefId {
+    #[inline]
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        hcx.def_path_hash(*self).hash_stable(hcx, hasher);
+    }
+}
+
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for hir::HirId {
+    #[inline]
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        let hir::HirId {
+            owner,
+            local_id,
+        } = *self;
+
+        hcx.def_path_hash(DefId::local(owner)).hash_stable(hcx, hasher);
+        local_id.hash_stable(hcx, hasher);
+    }
+}
+
+impl_stable_hash_for!(tuple_struct hir::ItemLocalId { index });
+
+// The following implementations of HashStable for ItemId, TraitItemId, and
+// ImplItemId deserve special attention. Normally we do not hash NodeIds within
+// the HIR, since they just signify a HIR nodes own path. But ItemId et al
+// are used when another item in the HIR is *referenced* and we certainly
+// want to pick up on a reference changing its target, so we hash the NodeIds
+// in "DefPath Mode".
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for hir::ItemId {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        let hir::ItemId {
+            id
+        } = *self;
+
+        hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| {
+            id.hash_stable(hcx, hasher);
+        })
+    }
+}
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for hir::TraitItemId {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        let hir::TraitItemId {
+            node_id
+        } = * self;
+
+        hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| {
+            node_id.hash_stable(hcx, hasher);
+        })
+    }
+}
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for hir::ImplItemId {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        let hir::ImplItemId {
+            node_id
+        } = * self;
+
+        hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| {
+            node_id.hash_stable(hcx, hasher);
+        })
+    }
+}
+
+impl_stable_hash_for!(struct hir::Lifetime {
+    id,
+    span,
+    name
+});
+
+impl_stable_hash_for!(struct hir::LifetimeDef {
+    lifetime,
+    bounds,
+    pure_wrt_drop
+});
+
+impl_stable_hash_for!(struct hir::Path {
+    span,
+    def,
+    segments
+});
+
+impl_stable_hash_for!(struct hir::PathSegment {
+    name,
+    parameters
+});
+
+impl_stable_hash_for!(enum hir::PathParameters {
+    AngleBracketedParameters(data),
+    ParenthesizedParameters(data)
+});
+
+impl_stable_hash_for!(struct hir::AngleBracketedParameterData {
+    lifetimes,
+    types,
+    infer_types,
+    bindings
+});
+
+impl_stable_hash_for!(struct hir::ParenthesizedParameterData {
+    span,
+    inputs,
+    output
+});
+
+impl_stable_hash_for!(enum hir::TyParamBound {
+    TraitTyParamBound(poly_trait_ref, trait_bound_modifier),
+    RegionTyParamBound(lifetime)
+});
+
+impl_stable_hash_for!(enum hir::TraitBoundModifier {
+    None,
+    Maybe
+});
+
+impl_stable_hash_for!(struct hir::TyParam {
+    name,
+    id,
+    bounds,
+    default,
+    span,
+    pure_wrt_drop
+});
+
+impl_stable_hash_for!(struct hir::Generics {
+    lifetimes,
+    ty_params,
+    where_clause,
+    span
+});
+
+impl_stable_hash_for!(struct hir::WhereClause {
+    id,
+    predicates
+});
+
+impl_stable_hash_for!(enum hir::WherePredicate {
+    BoundPredicate(pred),
+    RegionPredicate(pred),
+    EqPredicate(pred)
+});
+
+impl_stable_hash_for!(struct hir::WhereBoundPredicate {
+    span,
+    bound_lifetimes,
+    bounded_ty,
+    bounds
+});
+
+impl_stable_hash_for!(struct hir::WhereRegionPredicate {
+    span,
+    lifetime,
+    bounds
+});
+
+impl_stable_hash_for!(struct hir::WhereEqPredicate {
+    id,
+    span,
+    lhs_ty,
+    rhs_ty
+});
+
+impl_stable_hash_for!(struct hir::MutTy {
+    ty,
+    mutbl
+});
+
+impl_stable_hash_for!(struct hir::MethodSig {
+    unsafety,
+    constness,
+    abi,
+    decl,
+    generics
+});
+
+impl_stable_hash_for!(struct hir::TypeBinding {
+    id,
+    name,
+    ty,
+    span
+});
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for hir::Ty {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        let node_id_hashing_mode = match self.node {
+            hir::TySlice(..)       |
+            hir::TyArray(..)       |
+            hir::TyPtr(..)         |
+            hir::TyRptr(..)        |
+            hir::TyBareFn(..)      |
+            hir::TyNever           |
+            hir::TyTup(..)         |
+            hir::TyTraitObject(..) |
+            hir::TyImplTrait(..)   |
+            hir::TyTypeof(..)      |
+            hir::TyInfer           => {
+                NodeIdHashingMode::Ignore
+            }
+            hir::TyPath(..) => {
+                NodeIdHashingMode::HashTraitsInScope
+            }
+        };
+
+        hcx.while_hashing_hir_bodies(true, |hcx| {
+            let hir::Ty {
+                id,
+                ref node,
+                ref span,
+            } = *self;
+
+            hcx.with_node_id_hashing_mode(node_id_hashing_mode, |hcx| {
+                id.hash_stable(hcx, hasher);
+            });
+            node.hash_stable(hcx, hasher);
+            span.hash_stable(hcx, hasher);
+        })
+    }
+}
+
+impl_stable_hash_for!(enum hir::PrimTy {
+    TyInt(int_ty),
+    TyUint(uint_ty),
+    TyFloat(float_ty),
+    TyStr,
+    TyBool,
+    TyChar
+});
+
+impl_stable_hash_for!(struct hir::BareFnTy {
+    unsafety,
+    abi,
+    lifetimes,
+    decl
+});
+
+impl_stable_hash_for!(enum hir::Ty_ {
+    TySlice(t),
+    TyArray(t, body_id),
+    TyPtr(t),
+    TyRptr(lifetime, t),
+    TyBareFn(t),
+    TyNever,
+    TyTup(ts),
+    TyPath(qpath),
+    TyTraitObject(trait_refs, lifetime),
+    TyImplTrait(bounds),
+    TyTypeof(body_id),
+    TyInfer
+});
+
+impl_stable_hash_for!(struct hir::FnDecl {
+    inputs,
+    output,
+    variadic,
+    has_implicit_self
+});
+
+impl_stable_hash_for!(enum hir::FunctionRetTy {
+    DefaultReturn(span),
+    Return(t)
+});
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for hir::TraitRef {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        let hir::TraitRef {
+            ref path,
+            ref_id,
+        } = *self;
+
+        path.hash_stable(hcx, hasher);
+        hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashTraitsInScope, |hcx| {
+            ref_id.hash_stable(hcx, hasher);
+        });
+    }
+}
+
+
+impl_stable_hash_for!(struct hir::PolyTraitRef {
+    bound_lifetimes,
+    trait_ref,
+    span
+});
+
+impl_stable_hash_for!(enum hir::QPath {
+    Resolved(t, path),
+    TypeRelative(t, path_segment)
+});
+
+impl_stable_hash_for!(struct hir::MacroDef {
+    name,
+    attrs,
+    id,
+    span,
+    body
+});
+
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for hir::Block {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        let hir::Block {
+            ref stmts,
+            ref expr,
+            id,
+            rules,
+            span,
+            targeted_by_break,
+        } = *self;
+
+        let non_item_stmts = || stmts.iter().filter(|stmt| {
+            match stmt.node {
+                hir::StmtDecl(ref decl, _) => {
+                    match decl.node {
+                        // If this is a declaration of a nested item, we don't
+                        // want to leave any trace of it in the hash value, not
+                        // even that it exists. Otherwise changing the position
+                        // of nested items would invalidate the containing item
+                        // even though that does not constitute a semantic
+                        // change.
+                        hir::DeclItem(_) => false,
+                        hir::DeclLocal(_) => true
+                    }
+                }
+                hir::StmtExpr(..) |
+                hir::StmtSemi(..) => true
+            }
+        });
+
+        let count = non_item_stmts().count();
+
+        count.hash_stable(hcx, hasher);
+
+        for stmt in non_item_stmts() {
+            stmt.hash_stable(hcx, hasher);
+        }
+
+        expr.hash_stable(hcx, hasher);
+        id.hash_stable(hcx, hasher);
+        rules.hash_stable(hcx, hasher);
+        span.hash_stable(hcx, hasher);
+        targeted_by_break.hash_stable(hcx, hasher);
+    }
+}
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for hir::Pat {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        let node_id_hashing_mode = match self.node {
+            hir::PatKind::Wild        |
+            hir::PatKind::Binding(..) |
+            hir::PatKind::Tuple(..)   |
+            hir::PatKind::Box(..)     |
+            hir::PatKind::Ref(..)     |
+            hir::PatKind::Lit(..)     |
+            hir::PatKind::Range(..)   |
+            hir::PatKind::Slice(..)   => {
+                NodeIdHashingMode::Ignore
+            }
+            hir::PatKind::Path(..)        |
+            hir::PatKind::Struct(..)      |
+            hir::PatKind::TupleStruct(..) => {
+                NodeIdHashingMode::HashTraitsInScope
+            }
+        };
+
+        let hir::Pat {
+            id,
+            ref node,
+            ref span
+        } = *self;
+
+        hcx.with_node_id_hashing_mode(node_id_hashing_mode, |hcx| {
+            id.hash_stable(hcx, hasher);
+        });
+        node.hash_stable(hcx, hasher);
+        span.hash_stable(hcx, hasher);
+    }
+}
+
+impl_stable_hash_for_spanned!(hir::FieldPat);
+impl_stable_hash_for!(struct hir::FieldPat {
+    name,
+    pat,
+    is_shorthand
+});
+
+impl_stable_hash_for!(enum hir::BindingMode {
+    BindByRef(mutability),
+    BindByValue(mutability)
+});
+
+impl_stable_hash_for!(enum hir::RangeEnd {
+    Included,
+    Excluded
+});
+
+impl_stable_hash_for!(enum hir::PatKind {
+    Wild,
+    Binding(binding_mode, var, name, sub),
+    Struct(path, field_pats, dotdot),
+    TupleStruct(path, field_pats, dotdot),
+    Path(path),
+    Tuple(field_pats, dotdot),
+    Box(sub),
+    Ref(sub, mutability),
+    Lit(expr),
+    Range(start, end, end_kind),
+    Slice(one, two, three)
+});
+
+impl_stable_hash_for!(enum hir::BinOp_ {
+    BiAdd,
+    BiSub,
+    BiMul,
+    BiDiv,
+    BiRem,
+    BiAnd,
+    BiOr,
+    BiBitXor,
+    BiBitAnd,
+    BiBitOr,
+    BiShl,
+    BiShr,
+    BiEq,
+    BiLt,
+    BiLe,
+    BiNe,
+    BiGe,
+    BiGt
+});
+
+impl_stable_hash_for_spanned!(hir::BinOp_);
+
+impl_stable_hash_for!(enum hir::UnOp {
+    UnDeref,
+    UnNot,
+    UnNeg
+});
+
+impl_stable_hash_for_spanned!(hir::Stmt_);
+
+impl_stable_hash_for!(struct hir::Local {
+    pat,
+    ty,
+    init,
+    id,
+    span,
+    attrs
+});
+
+impl_stable_hash_for_spanned!(hir::Decl_);
+impl_stable_hash_for!(enum hir::Decl_ {
+    DeclLocal(local),
+    DeclItem(item_id)
+});
+
+impl_stable_hash_for!(struct hir::Arm {
+    attrs,
+    pats,
+    guard,
+    body
+});
+
+impl_stable_hash_for!(struct hir::Field {
+    name,
+    expr,
+    span,
+    is_shorthand
+});
+
+impl_stable_hash_for_spanned!(ast::Name);
+
+
+impl_stable_hash_for!(enum hir::BlockCheckMode {
+    DefaultBlock,
+    UnsafeBlock(src),
+    PushUnsafeBlock(src),
+    PopUnsafeBlock(src)
+});
+
+impl_stable_hash_for!(enum hir::UnsafeSource {
+    CompilerGenerated,
+    UserProvided
+});
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for hir::Expr {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        hcx.while_hashing_hir_bodies(true, |hcx| {
+            let hir::Expr {
+                id,
+                ref span,
+                ref node,
+                ref attrs
+            } = *self;
+
+            let (spans_always_on, node_id_hashing_mode) = match *node {
+                hir::ExprBox(..)        |
+                hir::ExprArray(..)      |
+                hir::ExprCall(..)       |
+                hir::ExprLit(..)        |
+                hir::ExprCast(..)       |
+                hir::ExprType(..)       |
+                hir::ExprIf(..)         |
+                hir::ExprWhile(..)      |
+                hir::ExprLoop(..)       |
+                hir::ExprMatch(..)      |
+                hir::ExprClosure(..)    |
+                hir::ExprBlock(..)      |
+                hir::ExprAssign(..)     |
+                hir::ExprTupField(..)   |
+                hir::ExprAddrOf(..)     |
+                hir::ExprBreak(..)      |
+                hir::ExprAgain(..)      |
+                hir::ExprRet(..)        |
+                hir::ExprInlineAsm(..)  |
+                hir::ExprRepeat(..)     |
+                hir::ExprTup(..)        => {
+                    // For these we only hash the span when debuginfo is on.
+                    (false, NodeIdHashingMode::Ignore)
+                }
+                // For the following, spans might be significant because of
+                // panic messages indicating the source location.
+                hir::ExprBinary(op, ..) => {
+                    (hcx.binop_can_panic_at_runtime(op.node), NodeIdHashingMode::Ignore)
+                }
+                hir::ExprUnary(op, _) => {
+                    (hcx.unop_can_panic_at_runtime(op), NodeIdHashingMode::Ignore)
+                }
+                hir::ExprAssignOp(op, ..) => {
+                    (hcx.binop_can_panic_at_runtime(op.node), NodeIdHashingMode::Ignore)
+                }
+                hir::ExprIndex(..) => {
+                    (true, NodeIdHashingMode::Ignore)
+                }
+                // For these we don't care about the span, but want to hash the
+                // trait in scope
+                hir::ExprMethodCall(..) |
+                hir::ExprPath(..)       |
+                hir::ExprStruct(..)     |
+                hir::ExprField(..)      => {
+                    (false, NodeIdHashingMode::HashTraitsInScope)
+                }
+            };
+
+            hcx.with_node_id_hashing_mode(node_id_hashing_mode, |hcx| {
+                id.hash_stable(hcx, hasher);
+            });
+
+            if spans_always_on {
+                hcx.while_hashing_spans(true, |hcx| {
+                    span.hash_stable(hcx, hasher);
+                    node.hash_stable(hcx, hasher);
+                    attrs.hash_stable(hcx, hasher);
+                });
+            } else {
+                span.hash_stable(hcx, hasher);
+                node.hash_stable(hcx, hasher);
+                attrs.hash_stable(hcx, hasher);
+            }
+        })
+    }
+}
+
+impl_stable_hash_for!(enum hir::Expr_ {
+    ExprBox(sub),
+    ExprArray(subs),
+    ExprCall(callee, args),
+    ExprMethodCall(name, ts, args),
+    ExprTup(fields),
+    ExprBinary(op, lhs, rhs),
+    ExprUnary(op, operand),
+    ExprLit(value),
+    ExprCast(expr, t),
+    ExprType(expr, t),
+    ExprIf(cond, then, els),
+    ExprWhile(cond, body, label),
+    ExprLoop(body, label, loop_src),
+    ExprMatch(matchee, arms, match_src),
+    ExprClosure(capture_clause, decl, body_id, span),
+    ExprBlock(blk),
+    ExprAssign(lhs, rhs),
+    ExprAssignOp(op, lhs, rhs),
+    ExprField(owner, field_name),
+    ExprTupField(owner, idx),
+    ExprIndex(lhs, rhs),
+    ExprPath(path),
+    ExprAddrOf(mutability, sub),
+    ExprBreak(destination, sub),
+    ExprAgain(destination),
+    ExprRet(val),
+    ExprInlineAsm(asm, inputs, outputs),
+    ExprStruct(path, fields, base),
+    ExprRepeat(val, times)
+});
+
+impl_stable_hash_for!(enum hir::LoopSource {
+    Loop,
+    WhileLet,
+    ForLoop
+});
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for hir::MatchSource {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        use hir::MatchSource;
+
+        mem::discriminant(self).hash_stable(hcx, hasher);
+        match *self {
+            MatchSource::Normal |
+            MatchSource::WhileLetDesugar |
+            MatchSource::ForLoopDesugar |
+            MatchSource::TryDesugar => {
+                // No fields to hash.
+            }
+            MatchSource::IfLetDesugar { contains_else_clause } => {
+                contains_else_clause.hash_stable(hcx, hasher);
+            }
+        }
+    }
+}
+
+impl_stable_hash_for!(enum hir::CaptureClause {
+    CaptureByValue,
+    CaptureByRef
+});
+
+impl_stable_hash_for_spanned!(usize);
+
+impl_stable_hash_for!(struct hir::Destination {
+    ident,
+    target_id
+});
+
+impl_stable_hash_for_spanned!(ast::Ident);
+
+impl_stable_hash_for!(enum hir::LoopIdResult {
+    Ok(node_id),
+    Err(loop_id_error)
+});
+
+impl_stable_hash_for!(enum hir::LoopIdError {
+    OutsideLoopScope,
+    UnlabeledCfInWhileCondition,
+    UnresolvedLabel
+});
+
+impl_stable_hash_for!(enum hir::ScopeTarget {
+    Block(node_id),
+    Loop(loop_id_result)
+});
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for ast::Ident {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        let ast::Ident {
+            ref name,
+            ctxt: _ // Ignore this
+        } = *self;
+
+        name.hash_stable(hcx, hasher);
+    }
+}
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for hir::TraitItem {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        let hir::TraitItem {
+            id,
+            name,
+            ref attrs,
+            ref node,
+            span
+        } = *self;
+
+        hcx.hash_hir_item_like(attrs, |hcx| {
+            id.hash_stable(hcx, hasher);
+            name.hash_stable(hcx, hasher);
+            attrs.hash_stable(hcx, hasher);
+            node.hash_stable(hcx, hasher);
+            span.hash_stable(hcx, hasher);
+        });
+    }
+}
+
+impl_stable_hash_for!(enum hir::TraitMethod {
+    Required(name),
+    Provided(body)
+});
+
+impl_stable_hash_for!(enum hir::TraitItemKind {
+    Const(t, body),
+    Method(sig, method),
+    Type(bounds, rhs)
+});
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for hir::ImplItem {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        let hir::ImplItem {
+            id,
+            name,
+            ref vis,
+            defaultness,
+            ref attrs,
+            ref node,
+            span
+        } = *self;
+
+        hcx.hash_hir_item_like(attrs, |hcx| {
+            id.hash_stable(hcx, hasher);
+            name.hash_stable(hcx, hasher);
+            vis.hash_stable(hcx, hasher);
+            defaultness.hash_stable(hcx, hasher);
+            attrs.hash_stable(hcx, hasher);
+            node.hash_stable(hcx, hasher);
+            span.hash_stable(hcx, hasher);
+        });
+    }
+}
+
+impl_stable_hash_for!(enum hir::ImplItemKind {
+    Const(t, body),
+    Method(sig, body),
+    Type(t)
+});
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for hir::Visibility {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        mem::discriminant(self).hash_stable(hcx, hasher);
+        match *self {
+            hir::Visibility::Public |
+            hir::Visibility::Crate |
+            hir::Visibility::Inherited => {
+                // No fields to hash.
+            }
+            hir::Visibility::Restricted { ref path, id } => {
+                hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashTraitsInScope, |hcx| {
+                    id.hash_stable(hcx, hasher);
+                });
+                path.hash_stable(hcx, hasher);
+            }
+        }
+    }
+}
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for hir::Defaultness {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        mem::discriminant(self).hash_stable(hcx, hasher);
+        match *self {
+            hir::Defaultness::Final => {
+                // No fields to hash.
+            }
+            hir::Defaultness::Default { has_value } => {
+                has_value.hash_stable(hcx, hasher);
+            }
+        }
+    }
+}
+
+impl_stable_hash_for!(enum hir::ImplPolarity {
+    Positive,
+    Negative
+});
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for hir::Mod {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        let hir::Mod {
+            inner,
+            // We are not hashing the IDs of the items contained in the module.
+            // This is harmless and matches the current behavior but it's not
+            // actually correct. See issue #40876.
+            item_ids: _,
+        } = *self;
+
+        inner.hash_stable(hcx, hasher);
+    }
+}
+
+impl_stable_hash_for!(struct hir::ForeignMod {
+    abi,
+    items
+});
+
+impl_stable_hash_for!(struct hir::EnumDef {
+    variants
+});
+
+impl_stable_hash_for!(struct hir::Variant_ {
+    name,
+    attrs,
+    data,
+    disr_expr
+});
+
+impl_stable_hash_for_spanned!(hir::Variant_);
+
+impl_stable_hash_for!(enum hir::UseKind {
+    Single,
+    Glob,
+    ListStem
+});
+
+impl_stable_hash_for!(struct hir::StructField {
+    span,
+    name,
+    vis,
+    id,
+    ty,
+    attrs
+});
+
+impl_stable_hash_for!(enum hir::VariantData {
+    Struct(fields, id),
+    Tuple(fields, id),
+    Unit(id)
+});
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for hir::Item {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        let node_id_hashing_mode = match self.node {
+            hir::ItemExternCrate(..) |
+            hir::ItemStatic(..)      |
+            hir::ItemConst(..)       |
+            hir::ItemFn(..)          |
+            hir::ItemMod(..)         |
+            hir::ItemForeignMod(..)  |
+            hir::ItemTy(..)          |
+            hir::ItemEnum(..)        |
+            hir::ItemStruct(..)      |
+            hir::ItemUnion(..)       |
+            hir::ItemTrait(..)       |
+            hir::ItemDefaultImpl(..) |
+            hir::ItemImpl(..)        => {
+                NodeIdHashingMode::Ignore
+            }
+            hir::ItemUse(..) => {
+                NodeIdHashingMode::HashTraitsInScope
+            }
+        };
+
+        let hir::Item {
+            name,
+            ref attrs,
+            id,
+            ref node,
+            ref vis,
+            span
+        } = *self;
+
+        hcx.hash_hir_item_like(attrs, |hcx| {
+            hcx.with_node_id_hashing_mode(node_id_hashing_mode, |hcx| {
+                id.hash_stable(hcx, hasher);
+            });
+            name.hash_stable(hcx, hasher);
+            attrs.hash_stable(hcx, hasher);
+            node.hash_stable(hcx, hasher);
+            vis.hash_stable(hcx, hasher);
+            span.hash_stable(hcx, hasher);
+        });
+    }
+}
+
+impl_stable_hash_for!(enum hir::Item_ {
+    ItemExternCrate(name),
+    ItemUse(path, use_kind),
+    ItemStatic(ty, mutability, body_id),
+    ItemConst(ty, body_id),
+    ItemFn(fn_decl, unsafety, constness, abi, generics, body_id),
+    ItemMod(module),
+    ItemForeignMod(foreign_mod),
+    ItemTy(ty, generics),
+    ItemEnum(enum_def, generics),
+    ItemStruct(variant_data, generics),
+    ItemUnion(variant_data, generics),
+    ItemTrait(unsafety, generics, bounds, item_refs),
+    ItemDefaultImpl(unsafety, trait_ref),
+    ItemImpl(unsafety, impl_polarity, generics, trait_ref, ty, impl_item_refs)
+});
+
+impl_stable_hash_for!(struct hir::TraitItemRef {
+    id,
+    name,
+    kind,
+    span,
+    defaultness
+});
+
+impl_stable_hash_for!(struct hir::ImplItemRef {
+    id,
+    name,
+    kind,
+    span,
+    vis,
+    defaultness
+});
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for hir::AssociatedItemKind {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        mem::discriminant(self).hash_stable(hcx, hasher);
+        match *self {
+            hir::AssociatedItemKind::Const |
+            hir::AssociatedItemKind::Type => {
+                // No fields to hash.
+            }
+            hir::AssociatedItemKind::Method { has_self } => {
+                has_self.hash_stable(hcx, hasher);
+            }
+        }
+    }
+}
+
+impl_stable_hash_for!(struct hir::ForeignItem {
+    name,
+    attrs,
+    node,
+    id,
+    span,
+    vis
+});
+
+impl_stable_hash_for!(enum hir::ForeignItem_ {
+    ForeignItemFn(fn_decl, arg_names, generics),
+    ForeignItemStatic(ty, is_mutbl)
+});
+
+impl_stable_hash_for!(enum hir::Stmt_ {
+    StmtDecl(decl, id),
+    StmtExpr(expr, id),
+    StmtSemi(expr, id)
+});
+
+impl_stable_hash_for!(struct hir::Arg {
+    pat,
+    id
+});
+
+impl_stable_hash_for!(struct hir::Body {
+    arguments,
+    value
+});
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for hir::BodyId {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        if hcx.hash_bodies() {
+            hcx.tcx().hir.body(*self).hash_stable(hcx, hasher);
+        }
+    }
+}
+
+impl_stable_hash_for!(struct hir::InlineAsmOutput {
+    constraint,
+    is_rw,
+    is_indirect
+});
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for hir::InlineAsm {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        let hir::InlineAsm {
+            asm,
+            asm_str_style,
+            ref outputs,
+            ref inputs,
+            ref clobbers,
+            volatile,
+            alignstack,
+            dialect,
+            ctxt: _, // This is used for error reporting
+        } = *self;
+
+        asm.hash_stable(hcx, hasher);
+        asm_str_style.hash_stable(hcx, hasher);
+        outputs.hash_stable(hcx, hasher);
+        inputs.hash_stable(hcx, hasher);
+        clobbers.hash_stable(hcx, hasher);
+        volatile.hash_stable(hcx, hasher);
+        alignstack.hash_stable(hcx, hasher);
+        dialect.hash_stable(hcx, hasher);
+    }
+}
+
+impl_stable_hash_for!(enum hir::def::CtorKind {
+    Fn,
+    Const,
+    Fictive
+});
+
+impl_stable_hash_for!(enum hir::def::Def {
+    Mod(def_id),
+    Struct(def_id),
+    Union(def_id),
+    Enum(def_id),
+    Variant(def_id),
+    Trait(def_id),
+    TyAlias(def_id),
+    AssociatedTy(def_id),
+    PrimTy(prim_ty),
+    TyParam(def_id),
+    SelfTy(trait_def_id, impl_def_id),
+    Fn(def_id),
+    Const(def_id),
+    Static(def_id, is_mutbl),
+    StructCtor(def_id, ctor_kind),
+    VariantCtor(def_id, ctor_kind),
+    Method(def_id),
+    AssociatedConst(def_id),
+    Local(def_id),
+    Upvar(def_id, index, expr_id),
+    Label(node_id),
+    Macro(def_id, macro_kind),
+    Err
+});
+
+impl_stable_hash_for!(enum hir::Mutability {
+    MutMutable,
+    MutImmutable
+});
+
+
+impl_stable_hash_for!(enum hir::Unsafety {
+    Unsafe,
+    Normal
+});
+
+
+impl_stable_hash_for!(enum hir::Constness {
+    Const,
+    NotConst
+});
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for hir::def_id::DefIndex {
+
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        DefId::local(*self).hash_stable(hcx, hasher);
+    }
+}
+
+impl_stable_hash_for!(struct hir::def::Export {
+    name,
+    def,
+    span
+});
diff --git a/src/librustc/ich/impls_mir.rs b/src/librustc/ich/impls_mir.rs
new file mode 100644
index 0000000000000..401f7e1921ab4
--- /dev/null
+++ b/src/librustc/ich/impls_mir.rs
@@ -0,0 +1,407 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! This module contains `HashStable` implementations for various MIR data
+//! types in no particular order.
+
+use ich::StableHashingContext;
+use mir;
+use rustc_data_structures::stable_hasher::{HashStable, StableHasher,
+                                           StableHasherResult};
+use std::mem;
+
+
+impl_stable_hash_for!(struct mir::SourceInfo { span, scope });
+impl_stable_hash_for!(enum mir::Mutability { Mut, Not });
+impl_stable_hash_for!(enum mir::BorrowKind { Shared, Unique, Mut });
+impl_stable_hash_for!(enum mir::LocalKind { Var, Temp, Arg, ReturnPointer });
+impl_stable_hash_for!(struct mir::LocalDecl<'tcx> { mutability, ty, name, source_info });
+impl_stable_hash_for!(struct mir::UpvarDecl { debug_name, by_ref });
+impl_stable_hash_for!(struct mir::BasicBlockData<'tcx> { statements, terminator, is_cleanup });
+impl_stable_hash_for!(struct mir::Terminator<'tcx> { source_info, kind });
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for mir::Local {
+    #[inline]
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        use rustc_data_structures::indexed_vec::Idx;
+        self.index().hash_stable(hcx, hasher);
+    }
+}
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for mir::BasicBlock {
+    #[inline]
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        use rustc_data_structures::indexed_vec::Idx;
+        self.index().hash_stable(hcx, hasher);
+    }
+}
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for mir::Field {
+    #[inline]
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        use rustc_data_structures::indexed_vec::Idx;
+        self.index().hash_stable(hcx, hasher);
+    }
+}
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for mir::VisibilityScope {
+    #[inline]
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        use rustc_data_structures::indexed_vec::Idx;
+        self.index().hash_stable(hcx, hasher);
+    }
+}
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for mir::Promoted {
+    #[inline]
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        use rustc_data_structures::indexed_vec::Idx;
+        self.index().hash_stable(hcx, hasher);
+    }
+}
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for mir::TerminatorKind<'tcx> {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        mem::discriminant(self).hash_stable(hcx, hasher);
+
+        match *self {
+            mir::TerminatorKind::Goto { ref target } => {
+                target.hash_stable(hcx, hasher);
+            }
+            mir::TerminatorKind::SwitchInt { ref discr,
+                                             switch_ty,
+                                             ref values,
+                                             ref targets } => {
+                discr.hash_stable(hcx, hasher);
+                switch_ty.hash_stable(hcx, hasher);
+                values.hash_stable(hcx, hasher);
+                targets.hash_stable(hcx, hasher);
+            }
+            mir::TerminatorKind::Resume |
+            mir::TerminatorKind::Return |
+            mir::TerminatorKind::Unreachable => {}
+            mir::TerminatorKind::Drop { ref location, target, unwind } => {
+                location.hash_stable(hcx, hasher);
+                target.hash_stable(hcx, hasher);
+                unwind.hash_stable(hcx, hasher);
+            }
+            mir::TerminatorKind::DropAndReplace { ref location,
+                                                  ref value,
+                                                  target,
+                                                  unwind, } => {
+                location.hash_stable(hcx, hasher);
+                value.hash_stable(hcx, hasher);
+                target.hash_stable(hcx, hasher);
+                unwind.hash_stable(hcx, hasher);
+            }
+            mir::TerminatorKind::Call { ref func,
+                                        ref args,
+                                        ref destination,
+                                        cleanup } => {
+                func.hash_stable(hcx, hasher);
+                args.hash_stable(hcx, hasher);
+                destination.hash_stable(hcx, hasher);
+                cleanup.hash_stable(hcx, hasher);
+            }
+            mir::TerminatorKind::Assert { ref cond,
+                                          expected,
+                                          ref msg,
+                                          target,
+                                          cleanup } => {
+                cond.hash_stable(hcx, hasher);
+                expected.hash_stable(hcx, hasher);
+                msg.hash_stable(hcx, hasher);
+                target.hash_stable(hcx, hasher);
+                cleanup.hash_stable(hcx, hasher);
+            }
+        }
+    }
+}
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for mir::AssertMessage<'tcx> {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        mem::discriminant(self).hash_stable(hcx, hasher);
+
+        match *self {
+            mir::AssertMessage::BoundsCheck { ref len, ref index } => {
+                len.hash_stable(hcx, hasher);
+                index.hash_stable(hcx, hasher);
+            }
+            mir::AssertMessage::Math(ref const_math_err) => {
+                const_math_err.hash_stable(hcx, hasher);
+            }
+        }
+    }
+}
+
+impl_stable_hash_for!(struct mir::Statement<'tcx> { source_info, kind });
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for mir::StatementKind<'tcx> {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        mem::discriminant(self).hash_stable(hcx, hasher);
+
+        match *self {
+            mir::StatementKind::Assign(ref lvalue, ref rvalue) => {
+                lvalue.hash_stable(hcx, hasher);
+                rvalue.hash_stable(hcx, hasher);
+            }
+            mir::StatementKind::SetDiscriminant { ref lvalue, variant_index } => {
+                lvalue.hash_stable(hcx, hasher);
+                variant_index.hash_stable(hcx, hasher);
+            }
+            mir::StatementKind::StorageLive(ref lvalue) |
+            mir::StatementKind::StorageDead(ref lvalue) => {
+                lvalue.hash_stable(hcx, hasher);
+            }
+            mir::StatementKind::Nop => {}
+            mir::StatementKind::InlineAsm { ref asm, ref outputs, ref inputs } => {
+                asm.hash_stable(hcx, hasher);
+                outputs.hash_stable(hcx, hasher);
+                inputs.hash_stable(hcx, hasher);
+            }
+        }
+    }
+}
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for mir::Lvalue<'tcx> {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        mem::discriminant(self).hash_stable(hcx, hasher);
+        match *self {
+            mir::Lvalue::Local(ref local) => {
+                local.hash_stable(hcx, hasher);
+            }
+            mir::Lvalue::Static(ref statik) => {
+                statik.hash_stable(hcx, hasher);
+            }
+            mir::Lvalue::Projection(ref lvalue_projection) => {
+                lvalue_projection.hash_stable(hcx, hasher);
+            }
+        }
+    }
+}
+
+impl<'a, 'tcx, B, V> HashStable<StableHashingContext<'a, 'tcx>> for mir::Projection<'tcx, B, V>
+    where B: HashStable<StableHashingContext<'a, 'tcx>>,
+          V: HashStable<StableHashingContext<'a, 'tcx>>
+{
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        let mir::Projection {
+            ref base,
+            ref elem,
+        } = *self;
+
+        base.hash_stable(hcx, hasher);
+        elem.hash_stable(hcx, hasher);
+    }
+}
+
+impl<'a, 'tcx, V> HashStable<StableHashingContext<'a, 'tcx>> for mir::ProjectionElem<'tcx, V>
+    where V: HashStable<StableHashingContext<'a, 'tcx>>
+{
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        mem::discriminant(self).hash_stable(hcx, hasher);
+        match *self {
+            mir::ProjectionElem::Deref => {}
+            mir::ProjectionElem::Field(field, ty) => {
+                field.hash_stable(hcx, hasher);
+                ty.hash_stable(hcx, hasher);
+            }
+            mir::ProjectionElem::Index(ref value) => {
+                value.hash_stable(hcx, hasher);
+            }
+            mir::ProjectionElem::ConstantIndex { offset, min_length, from_end } => {
+                offset.hash_stable(hcx, hasher);
+                min_length.hash_stable(hcx, hasher);
+                from_end.hash_stable(hcx, hasher);
+            }
+            mir::ProjectionElem::Subslice { from, to } => {
+                from.hash_stable(hcx, hasher);
+                to.hash_stable(hcx, hasher);
+            }
+            mir::ProjectionElem::Downcast(adt_def, variant) => {
+                adt_def.hash_stable(hcx, hasher);
+                variant.hash_stable(hcx, hasher);
+            }
+        }
+    }
+}
+
+impl_stable_hash_for!(struct mir::VisibilityScopeData { span, parent_scope });
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for mir::Operand<'tcx> {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        mem::discriminant(self).hash_stable(hcx, hasher);
+
+        match *self {
+            mir::Operand::Consume(ref lvalue) => {
+                lvalue.hash_stable(hcx, hasher);
+            }
+            mir::Operand::Constant(ref constant) => {
+                constant.hash_stable(hcx, hasher);
+            }
+        }
+    }
+}
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for mir::Rvalue<'tcx> {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        mem::discriminant(self).hash_stable(hcx, hasher);
+
+        match *self {
+            mir::Rvalue::Use(ref operand) => {
+                operand.hash_stable(hcx, hasher);
+            }
+            mir::Rvalue::Repeat(ref operand, ref val) => {
+                operand.hash_stable(hcx, hasher);
+                val.hash_stable(hcx, hasher);
+            }
+            mir::Rvalue::Ref(region, borrow_kind, ref lvalue) => {
+                region.hash_stable(hcx, hasher);
+                borrow_kind.hash_stable(hcx, hasher);
+                lvalue.hash_stable(hcx, hasher);
+            }
+            mir::Rvalue::Len(ref lvalue) => {
+                lvalue.hash_stable(hcx, hasher);
+            }
+            mir::Rvalue::Cast(cast_kind, ref operand, ty) => {
+                cast_kind.hash_stable(hcx, hasher);
+                operand.hash_stable(hcx, hasher);
+                ty.hash_stable(hcx, hasher);
+            }
+            mir::Rvalue::BinaryOp(op, ref operand1, ref operand2) |
+            mir::Rvalue::CheckedBinaryOp(op, ref operand1, ref operand2) => {
+                op.hash_stable(hcx, hasher);
+                operand1.hash_stable(hcx, hasher);
+                operand2.hash_stable(hcx, hasher);
+            }
+            mir::Rvalue::UnaryOp(op, ref operand) => {
+                op.hash_stable(hcx, hasher);
+                operand.hash_stable(hcx, hasher);
+            }
+            mir::Rvalue::Discriminant(ref lvalue) => {
+                lvalue.hash_stable(hcx, hasher);
+            }
+            mir::Rvalue::Box(ty) => {
+                ty.hash_stable(hcx, hasher);
+            }
+            mir::Rvalue::Aggregate(ref kind, ref operands) => {
+                kind.hash_stable(hcx, hasher);
+                operands.hash_stable(hcx, hasher);
+            }
+        }
+    }
+}
+
+impl_stable_hash_for!(enum mir::CastKind {
+    Misc,
+    ReifyFnPointer,
+    ClosureFnPointer,
+    UnsafeFnPointer,
+    Unsize
+});
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for mir::AggregateKind<'tcx> {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        mem::discriminant(self).hash_stable(hcx, hasher);
+        match *self {
+            mir::AggregateKind::Tuple => {}
+            mir::AggregateKind::Array(t) => {
+                t.hash_stable(hcx, hasher);
+            }
+            mir::AggregateKind::Adt(adt_def, idx, substs, active_field) => {
+                adt_def.hash_stable(hcx, hasher);
+                idx.hash_stable(hcx, hasher);
+                substs.hash_stable(hcx, hasher);
+                active_field.hash_stable(hcx, hasher);
+            }
+            mir::AggregateKind::Closure(def_id, ref substs) => {
+                def_id.hash_stable(hcx, hasher);
+                substs.hash_stable(hcx, hasher);
+            }
+        }
+    }
+}
+
+impl_stable_hash_for!(enum mir::BinOp {
+    Add,
+    Sub,
+    Mul,
+    Div,
+    Rem,
+    BitXor,
+    BitAnd,
+    BitOr,
+    Shl,
+    Shr,
+    Eq,
+    Lt,
+    Le,
+    Ne,
+    Ge,
+    Gt
+});
+
+impl_stable_hash_for!(enum mir::UnOp {
+    Not,
+    Neg
+});
+
+
+impl_stable_hash_for!(struct mir::Constant<'tcx> { span, ty, literal });
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for mir::Literal<'tcx> {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        mem::discriminant(self).hash_stable(hcx, hasher);
+        match *self {
+            mir::Literal::Item { def_id, substs } => {
+                def_id.hash_stable(hcx, hasher);
+                substs.hash_stable(hcx, hasher);
+            }
+            mir::Literal::Value { ref value } => {
+                value.hash_stable(hcx, hasher);
+            }
+            mir::Literal::Promoted { index } => {
+                index.hash_stable(hcx, hasher);
+            }
+        }
+    }
+}
+
+impl_stable_hash_for!(struct mir::Location { block, statement_index });
diff --git a/src/librustc/ich/impls_syntax.rs b/src/librustc/ich/impls_syntax.rs
new file mode 100644
index 0000000000000..26734500001f6
--- /dev/null
+++ b/src/librustc/ich/impls_syntax.rs
@@ -0,0 +1,301 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! This module contains `HashStable` implementations for various data types
+//! from libsyntax in no particular order.
+
+use ich::StableHashingContext;
+
+use std::hash as std_hash;
+use std::mem;
+
+use syntax::ast;
+use syntax::parse::token;
+use syntax::tokenstream;
+use syntax_pos::Span;
+
+use rustc_data_structures::stable_hasher::{HashStable, StableHasher,
+                                           StableHasherResult};
+use rustc_data_structures::accumulate_vec::AccumulateVec;
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for ::syntax::symbol::InternedString {
+    #[inline]
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        let s: &str = &**self;
+        s.hash_stable(hcx, hasher);
+    }
+}
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for ast::Name {
+    #[inline]
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        self.as_str().hash_stable(hcx, hasher);
+    }
+}
+
+impl_stable_hash_for!(enum ::syntax::ast::AsmDialect {
+    Att,
+    Intel
+});
+
+impl_stable_hash_for!(enum ::syntax::ext::base::MacroKind {
+    Bang,
+    Attr,
+    Derive
+});
+
+
+impl_stable_hash_for!(enum ::syntax::abi::Abi {
+    Cdecl,
+    Stdcall,
+    Fastcall,
+    Vectorcall,
+    Aapcs,
+    Win64,
+    SysV64,
+    PtxKernel,
+    Msp430Interrupt,
+    X86Interrupt,
+    Rust,
+    C,
+    System,
+    RustIntrinsic,
+    RustCall,
+    PlatformIntrinsic,
+    Unadjusted
+});
+
+impl_stable_hash_for!(struct ::syntax::attr::Deprecation { since, note });
+impl_stable_hash_for!(struct ::syntax::attr::Stability { level, feature, rustc_depr });
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for ::syntax::attr::StabilityLevel {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        mem::discriminant(self).hash_stable(hcx, hasher);
+        match *self {
+            ::syntax::attr::StabilityLevel::Unstable { ref reason, ref issue } => {
+                reason.hash_stable(hcx, hasher);
+                issue.hash_stable(hcx, hasher);
+            }
+            ::syntax::attr::StabilityLevel::Stable { ref since } => {
+                since.hash_stable(hcx, hasher);
+            }
+        }
+    }
+}
+
+impl_stable_hash_for!(struct ::syntax::attr::RustcDeprecation { since, reason });
+
+
+impl_stable_hash_for!(enum ::syntax::attr::IntType {
+    SignedInt(int_ty),
+    UnsignedInt(uint_ty)
+});
+
+impl_stable_hash_for!(enum ::syntax::ast::LitIntType {
+    Signed(int_ty),
+    Unsigned(int_ty),
+    Unsuffixed
+});
+
+impl_stable_hash_for_spanned!(::syntax::ast::LitKind);
+impl_stable_hash_for!(enum ::syntax::ast::LitKind {
+    Str(value, style),
+    ByteStr(value),
+    Byte(value),
+    Char(value),
+    Int(value, lit_int_type),
+    Float(value, float_ty),
+    FloatUnsuffixed(value),
+    Bool(value)
+});
+
+impl_stable_hash_for!(enum ::syntax::ast::IntTy { Is, I8, I16, I32, I64, I128 });
+impl_stable_hash_for!(enum ::syntax::ast::UintTy { Us, U8, U16, U32, U64, U128 });
+impl_stable_hash_for!(enum ::syntax::ast::FloatTy { F32, F64 });
+impl_stable_hash_for!(enum ::syntax::ast::Unsafety { Unsafe, Normal });
+impl_stable_hash_for!(enum ::syntax::ast::Constness { Const, NotConst });
+impl_stable_hash_for!(enum ::syntax::ast::Defaultness { Default, Final });
+impl_stable_hash_for!(struct ::syntax::ast::Lifetime { id, span, name });
+impl_stable_hash_for!(enum ::syntax::ast::StrStyle { Cooked, Raw(pounds) });
+impl_stable_hash_for!(enum ::syntax::ast::AttrStyle { Outer, Inner });
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for [ast::Attribute] {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        // Some attributes are always ignored during hashing.
+        let filtered: AccumulateVec<[&ast::Attribute; 8]> = self
+            .iter()
+            .filter(|attr| {
+                !attr.is_sugared_doc &&
+                attr.name().map(|name| !hcx.is_ignored_attr(name)).unwrap_or(true)
+            })
+            .collect();
+
+        filtered.len().hash_stable(hcx, hasher);
+        for attr in filtered {
+            attr.hash_stable(hcx, hasher);
+        }
+    }
+}
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for ast::Attribute {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        // Make sure that these have been filtered out.
+        debug_assert!(self.name().map(|name| !hcx.is_ignored_attr(name)).unwrap_or(true));
+        debug_assert!(!self.is_sugared_doc);
+
+        let ast::Attribute {
+            id: _,
+            style,
+            ref path,
+            ref tokens,
+            is_sugared_doc: _,
+            span,
+        } = *self;
+
+        style.hash_stable(hcx, hasher);
+        path.segments.len().hash_stable(hcx, hasher);
+        for segment in &path.segments {
+            segment.identifier.name.hash_stable(hcx, hasher);
+        }
+        for tt in tokens.trees() {
+            tt.hash_stable(hcx, hasher);
+        }
+        span.hash_stable(hcx, hasher);
+    }
+}
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for tokenstream::TokenTree {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        mem::discriminant(self).hash_stable(hcx, hasher);
+        match *self {
+            tokenstream::TokenTree::Token(span, ref token) => {
+                span.hash_stable(hcx, hasher);
+                hash_token(token, hcx, hasher, span);
+            }
+            tokenstream::TokenTree::Delimited(span, ref delimited) => {
+                span.hash_stable(hcx, hasher);
+                std_hash::Hash::hash(&delimited.delim, hasher);
+                for sub_tt in delimited.stream().trees() {
+                    sub_tt.hash_stable(hcx, hasher);
+                }
+            }
+        }
+    }
+}
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for tokenstream::TokenStream {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        for sub_tt in self.trees() {
+            sub_tt.hash_stable(hcx, hasher);
+        }
+    }
+}
+
+fn hash_token<'a, 'tcx, W: StableHasherResult>(token: &token::Token,
+                                               hcx: &mut StableHashingContext<'a, 'tcx>,
+                                               hasher: &mut StableHasher<W>,
+                                               error_reporting_span: Span) {
+    mem::discriminant(token).hash_stable(hcx, hasher);
+    match *token {
+        token::Token::Eq |
+        token::Token::Lt |
+        token::Token::Le |
+        token::Token::EqEq |
+        token::Token::Ne |
+        token::Token::Ge |
+        token::Token::Gt |
+        token::Token::AndAnd |
+        token::Token::OrOr |
+        token::Token::Not |
+        token::Token::Tilde |
+        token::Token::At |
+        token::Token::Dot |
+        token::Token::DotDot |
+        token::Token::DotDotDot |
+        token::Token::Comma |
+        token::Token::Semi |
+        token::Token::Colon |
+        token::Token::ModSep |
+        token::Token::RArrow |
+        token::Token::LArrow |
+        token::Token::FatArrow |
+        token::Token::Pound |
+        token::Token::Dollar |
+        token::Token::Question |
+        token::Token::Underscore |
+        token::Token::Whitespace |
+        token::Token::Comment |
+        token::Token::Eof => {}
+
+        token::Token::BinOp(bin_op_token) |
+        token::Token::BinOpEq(bin_op_token) => {
+            std_hash::Hash::hash(&bin_op_token, hasher);
+        }
+
+        token::Token::OpenDelim(delim_token) |
+        token::Token::CloseDelim(delim_token) => {
+            std_hash::Hash::hash(&delim_token, hasher);
+        }
+        token::Token::Literal(ref lit, ref opt_name) => {
+            mem::discriminant(lit).hash_stable(hcx, hasher);
+            match *lit {
+                token::Lit::Byte(val) |
+                token::Lit::Char(val) |
+                token::Lit::Integer(val) |
+                token::Lit::Float(val) |
+                token::Lit::Str_(val) |
+                token::Lit::ByteStr(val) => val.hash_stable(hcx, hasher),
+                token::Lit::StrRaw(val, n) |
+                token::Lit::ByteStrRaw(val, n) => {
+                    val.hash_stable(hcx, hasher);
+                    n.hash_stable(hcx, hasher);
+                }
+            };
+            opt_name.hash_stable(hcx, hasher);
+        }
+
+        token::Token::Ident(ident) |
+        token::Token::Lifetime(ident) |
+        token::Token::SubstNt(ident) => ident.name.hash_stable(hcx, hasher),
+
+        token::Token::Interpolated(ref non_terminal) => {
+            // FIXME(mw): This could be implemented properly. It's just a
+            //            lot of work, since we would need to hash the AST
+            //            in a stable way, in addition to the HIR.
+            //            Since this is hardly used anywhere, just emit a
+            //            warning for now.
+            if hcx.tcx().sess.opts.debugging_opts.incremental.is_some() {
+                let msg = format!("Quasi-quoting might make incremental \
+                                   compilation very inefficient: {:?}",
+                                  non_terminal);
+                hcx.tcx().sess.span_warn(error_reporting_span, &msg[..]);
+            }
+
+            std_hash::Hash::hash(non_terminal, hasher);
+        }
+
+        token::Token::DocComment(val) |
+        token::Token::Shebang(val) => val.hash_stable(hcx, hasher),
+    }
+}
diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs
new file mode 100644
index 0000000000000..7b6f3af2a11ec
--- /dev/null
+++ b/src/librustc/ich/impls_ty.rs
@@ -0,0 +1,415 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! This module contains `HashStable` implementations for various data types
+//! from rustc::ty in no particular order.
+
+use ich::StableHashingContext;
+use rustc_data_structures::stable_hasher::{HashStable, StableHasher,
+                                           StableHasherResult};
+use std::hash as std_hash;
+use std::mem;
+use ty;
+
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for ty::Ty<'tcx> {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        let type_hash = hcx.tcx().type_id_hash(*self);
+        type_hash.hash_stable(hcx, hasher);
+    }
+}
+
+impl_stable_hash_for!(struct ty::ItemSubsts<'tcx> { substs });
+
+impl<'a, 'tcx, T> HashStable<StableHashingContext<'a, 'tcx>> for ty::Slice<T>
+    where T: HashStable<StableHashingContext<'a, 'tcx>> {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        (&**self).hash_stable(hcx, hasher);
+    }
+}
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for ty::subst::Kind<'tcx> {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        self.as_type().hash_stable(hcx, hasher);
+        self.as_region().hash_stable(hcx, hasher);
+    }
+}
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for ty::Region {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        mem::discriminant(self).hash_stable(hcx, hasher);
+        match *self {
+            ty::ReErased |
+            ty::ReStatic |
+            ty::ReEmpty => {
+                // No variant fields to hash for these ...
+            }
+            ty::ReLateBound(db, ty::BrAnon(i)) => {
+                db.depth.hash_stable(hcx, hasher);
+                i.hash_stable(hcx, hasher);
+            }
+            ty::ReEarlyBound(ty::EarlyBoundRegion { index, name }) => {
+                index.hash_stable(hcx, hasher);
+                name.hash_stable(hcx, hasher);
+            }
+            ty::ReLateBound(..) |
+            ty::ReFree(..) |
+            ty::ReScope(..) |
+            ty::ReVar(..) |
+            ty::ReSkolemized(..) => {
+                bug!("TypeIdHasher: unexpected region {:?}", *self)
+            }
+        }
+    }
+}
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for ty::adjustment::AutoBorrow<'tcx> {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        mem::discriminant(self).hash_stable(hcx, hasher);
+        match *self {
+            ty::adjustment::AutoBorrow::Ref(ref region, mutability) => {
+                region.hash_stable(hcx, hasher);
+                mutability.hash_stable(hcx, hasher);
+            }
+            ty::adjustment::AutoBorrow::RawPtr(mutability) => {
+                mutability.hash_stable(hcx, hasher);
+            }
+        }
+    }
+}
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for ty::adjustment::Adjust<'tcx> {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        mem::discriminant(self).hash_stable(hcx, hasher);
+        match *self {
+            ty::adjustment::Adjust::NeverToAny |
+            ty::adjustment::Adjust::ReifyFnPointer |
+            ty::adjustment::Adjust::UnsafeFnPointer |
+            ty::adjustment::Adjust::ClosureFnPointer |
+            ty::adjustment::Adjust::MutToConstPointer => {}
+            ty::adjustment::Adjust::DerefRef { autoderefs, ref autoref, unsize } => {
+                autoderefs.hash_stable(hcx, hasher);
+                autoref.hash_stable(hcx, hasher);
+                unsize.hash_stable(hcx, hasher);
+            }
+        }
+    }
+}
+
+impl_stable_hash_for!(struct ty::adjustment::Adjustment<'tcx> { kind, target });
+impl_stable_hash_for!(struct ty::MethodCall { expr_id, autoderef });
+impl_stable_hash_for!(struct ty::MethodCallee<'tcx> { def_id, ty, substs });
+impl_stable_hash_for!(struct ty::UpvarId { var_id, closure_expr_id });
+impl_stable_hash_for!(struct ty::UpvarBorrow<'tcx> { kind, region });
+
+impl_stable_hash_for!(enum ty::BorrowKind {
+    ImmBorrow,
+    UniqueImmBorrow,
+    MutBorrow
+});
+
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for ty::UpvarCapture<'tcx> {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        mem::discriminant(self).hash_stable(hcx, hasher);
+        match *self {
+            ty::UpvarCapture::ByValue => {}
+            ty::UpvarCapture::ByRef(ref up_var_borrow) => {
+                up_var_borrow.hash_stable(hcx, hasher);
+            }
+        }
+    }
+}
+
+impl_stable_hash_for!(struct ty::FnSig<'tcx> {
+    inputs_and_output,
+    variadic,
+    unsafety,
+    abi
+});
+
+impl<'a, 'tcx, T> HashStable<StableHashingContext<'a, 'tcx>> for ty::Binder<T>
+    where T: HashStable<StableHashingContext<'a, 'tcx>> + ty::fold::TypeFoldable<'tcx>
+{
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        hcx.tcx().anonymize_late_bound_regions(self).0.hash_stable(hcx, hasher);
+    }
+}
+
+impl_stable_hash_for!(enum ty::ClosureKind { Fn, FnMut, FnOnce });
+
+impl_stable_hash_for!(enum ty::Visibility {
+    Public,
+    Restricted(def_id),
+    Invisible
+});
+
+impl_stable_hash_for!(struct ty::TraitRef<'tcx> { def_id, substs });
+impl_stable_hash_for!(struct ty::TraitPredicate<'tcx> { trait_ref });
+impl_stable_hash_for!(tuple_struct ty::EquatePredicate<'tcx> { t1, t2 });
+
+impl<'a, 'tcx, A, B> HashStable<StableHashingContext<'a, 'tcx>> for ty::OutlivesPredicate<A, B>
+    where A: HashStable<StableHashingContext<'a, 'tcx>>,
+          B: HashStable<StableHashingContext<'a, 'tcx>>,
+{
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        let ty::OutlivesPredicate(ref a, ref b) = *self;
+        a.hash_stable(hcx, hasher);
+        b.hash_stable(hcx, hasher);
+    }
+}
+
+impl_stable_hash_for!(struct ty::ProjectionPredicate<'tcx> { projection_ty, ty });
+impl_stable_hash_for!(struct ty::ProjectionTy<'tcx> { trait_ref, item_name });
+
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for ty::Predicate<'tcx> {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        mem::discriminant(self).hash_stable(hcx, hasher);
+        match *self {
+            ty::Predicate::Trait(ref pred) => {
+                pred.hash_stable(hcx, hasher);
+            }
+            ty::Predicate::Equate(ref pred) => {
+                pred.hash_stable(hcx, hasher);
+            }
+            ty::Predicate::RegionOutlives(ref pred) => {
+                pred.hash_stable(hcx, hasher);
+            }
+            ty::Predicate::TypeOutlives(ref pred) => {
+                pred.hash_stable(hcx, hasher);
+            }
+            ty::Predicate::Projection(ref pred) => {
+                pred.hash_stable(hcx, hasher);
+            }
+            ty::Predicate::WellFormed(ty) => {
+                ty.hash_stable(hcx, hasher);
+            }
+            ty::Predicate::ObjectSafe(def_id) => {
+                def_id.hash_stable(hcx, hasher);
+            }
+            ty::Predicate::ClosureKind(def_id, closure_kind) => {
+                def_id.hash_stable(hcx, hasher);
+                closure_kind.hash_stable(hcx, hasher);
+            }
+        }
+    }
+}
+
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for ty::AdtFlags {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          _: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        std_hash::Hash::hash(self, hasher);
+    }
+}
+
+impl_stable_hash_for!(struct ty::VariantDef {
+    did,
+    name,
+    discr,
+    fields,
+    ctor_kind
+});
+
+impl_stable_hash_for!(enum ty::VariantDiscr {
+    Explicit(def_id),
+    Relative(distance)
+});
+
+impl_stable_hash_for!(struct ty::FieldDef {
+    did,
+    name,
+    vis
+});
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>>
+for ::middle::const_val::ConstVal<'tcx> {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        use middle::const_val::ConstVal;
+
+        mem::discriminant(self).hash_stable(hcx, hasher);
+
+        match *self {
+            ConstVal::Float(ref value) => {
+                value.hash_stable(hcx, hasher);
+            }
+            ConstVal::Integral(ref value) => {
+                value.hash_stable(hcx, hasher);
+            }
+            ConstVal::Str(ref value) => {
+                value.hash_stable(hcx, hasher);
+            }
+            ConstVal::ByteStr(ref value) => {
+                value.hash_stable(hcx, hasher);
+            }
+            ConstVal::Bool(value) => {
+                value.hash_stable(hcx, hasher);
+            }
+            ConstVal::Function(def_id, substs) => {
+                def_id.hash_stable(hcx, hasher);
+                substs.hash_stable(hcx, hasher);
+            }
+            ConstVal::Struct(ref _name_value_map) => {
+                // BTreeMap<ast::Name, ConstVal<'tcx>>),
+                panic!("Ordering still unstable")
+            }
+            ConstVal::Tuple(ref value) => {
+                value.hash_stable(hcx, hasher);
+            }
+            ConstVal::Array(ref value) => {
+                value.hash_stable(hcx, hasher);
+            }
+            ConstVal::Repeat(ref value, times) => {
+                value.hash_stable(hcx, hasher);
+                times.hash_stable(hcx, hasher);
+            }
+            ConstVal::Char(value) => {
+                value.hash_stable(hcx, hasher);
+            }
+        }
+    }
+}
+
+impl_stable_hash_for!(struct ty::ClosureSubsts<'tcx> { substs });
+
+
+impl_stable_hash_for!(struct ty::GenericPredicates<'tcx> {
+    parent,
+    predicates
+});
+
+impl_stable_hash_for!(enum ty::Variance {
+    Covariant,
+    Invariant,
+    Contravariant,
+    Bivariant
+});
+
+impl_stable_hash_for!(enum ty::adjustment::CustomCoerceUnsized {
+    Struct(index)
+});
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for ty::Generics {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        let ty::Generics {
+            parent,
+            parent_regions,
+            parent_types,
+            ref regions,
+            ref types,
+
+            // Reverse map to each `TypeParameterDef`'s `index` field, from
+            // `def_id.index` (`def_id.krate` is the same as the item's).
+            type_param_to_index: _, // Don't hash this
+            has_self,
+        } = *self;
+
+        parent.hash_stable(hcx, hasher);
+        parent_regions.hash_stable(hcx, hasher);
+        parent_types.hash_stable(hcx, hasher);
+        regions.hash_stable(hcx, hasher);
+        types.hash_stable(hcx, hasher);
+        has_self.hash_stable(hcx, hasher);
+    }
+}
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for ty::RegionParameterDef {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        let ty::RegionParameterDef {
+            name,
+            def_id,
+            index,
+            issue_32330: _,
+            pure_wrt_drop
+        } = *self;
+
+        name.hash_stable(hcx, hasher);
+        def_id.hash_stable(hcx, hasher);
+        index.hash_stable(hcx, hasher);
+        pure_wrt_drop.hash_stable(hcx, hasher);
+    }
+}
+
+impl_stable_hash_for!(struct ty::TypeParameterDef {
+    name,
+    def_id,
+    index,
+    has_default,
+    object_lifetime_default,
+    pure_wrt_drop
+});
+
+
+impl<'a, 'tcx, T> HashStable<StableHashingContext<'a, 'tcx>>
+for ::middle::resolve_lifetime::Set1<T>
+    where T: HashStable<StableHashingContext<'a, 'tcx>>
+{
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        use middle::resolve_lifetime::Set1;
+
+        mem::discriminant(self).hash_stable(hcx, hasher);
+        match *self {
+            Set1::Empty |
+            Set1::Many => {
+                // Nothing to do.
+            }
+            Set1::One(ref value) => {
+                value.hash_stable(hcx, hasher);
+            }
+        }
+    }
+}
+
+impl_stable_hash_for!(enum ::middle::resolve_lifetime::Region {
+    Static,
+    EarlyBound(index, decl),
+    LateBound(db_index, decl),
+    LateBoundAnon(db_index, anon_index),
+    Free(call_site_scope_data, decl)
+});
+
+impl_stable_hash_for!(struct ::middle::region::CallSiteScopeData {
+    fn_id,
+    body_id
+});
+
+impl_stable_hash_for!(struct ty::DebruijnIndex {
+    depth
+});
diff --git a/src/librustc/ich/mod.rs b/src/librustc/ich/mod.rs
index 209953f3c686b..f0601a0efabf8 100644
--- a/src/librustc/ich/mod.rs
+++ b/src/librustc/ich/mod.rs
@@ -8,13 +8,23 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+//! ICH - Incremental Compilation Hash
+
 pub use self::fingerprint::Fingerprint;
 pub use self::def_path_hash::DefPathHashes;
 pub use self::caching_codemap_view::CachingCodemapView;
+pub use self::hcx::{StableHashingContext, NodeIdHashingMode};
 
 mod fingerprint;
 mod def_path_hash;
 mod caching_codemap_view;
+mod hcx;
+
+mod impls_const_math;
+mod impls_hir;
+mod impls_mir;
+mod impls_ty;
+mod impls_syntax;
 
 pub const ATTR_DIRTY: &'static str = "rustc_dirty";
 pub const ATTR_CLEAN: &'static str = "rustc_clean";
@@ -22,6 +32,20 @@ pub const ATTR_DIRTY_METADATA: &'static str = "rustc_metadata_dirty";
 pub const ATTR_CLEAN_METADATA: &'static str = "rustc_metadata_clean";
 pub const ATTR_IF_THIS_CHANGED: &'static str = "rustc_if_this_changed";
 pub const ATTR_THEN_THIS_WOULD_NEED: &'static str = "rustc_then_this_would_need";
+pub const ATTR_PARTITION_REUSED: &'static str = "rustc_partition_reused";
+pub const ATTR_PARTITION_TRANSLATED: &'static str = "rustc_partition_translated";
+
+
+pub const DEP_GRAPH_ASSERT_ATTRS: &'static [&'static str] = &[
+    ATTR_IF_THIS_CHANGED,
+    ATTR_THEN_THIS_WOULD_NEED,
+    ATTR_DIRTY,
+    ATTR_CLEAN,
+    ATTR_DIRTY_METADATA,
+    ATTR_CLEAN_METADATA,
+    ATTR_PARTITION_REUSED,
+    ATTR_PARTITION_TRANSLATED,
+];
 
 pub const IGNORED_ATTRIBUTES: &'static [&'static str] = &[
     "cfg",
@@ -30,5 +54,7 @@ pub const IGNORED_ATTRIBUTES: &'static [&'static str] = &[
     ATTR_DIRTY,
     ATTR_CLEAN,
     ATTR_DIRTY_METADATA,
-    ATTR_CLEAN_METADATA
+    ATTR_CLEAN_METADATA,
+    ATTR_PARTITION_REUSED,
+    ATTR_PARTITION_TRANSLATED,
 ];
diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs
index 294f80d7d2301..3b002fd4dfc1a 100644
--- a/src/librustc/lib.rs
+++ b/src/librustc/lib.rs
@@ -41,6 +41,7 @@
 #![feature(specialization)]
 #![feature(staged_api)]
 #![feature(unboxed_closures)]
+#![feature(discriminant_value)]
 
 extern crate arena;
 extern crate core;
diff --git a/src/librustc/macros.rs b/src/librustc/macros.rs
index 76dca1bb5b649..c18e585f79553 100644
--- a/src/librustc/macros.rs
+++ b/src/librustc/macros.rs
@@ -8,6 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+// ignore-tidy-linelength
+
 macro_rules! enum_from_u32 {
     ($(#[$attr:meta])* pub enum $name:ident {
         $($variant:ident = $e:expr,)*
@@ -59,3 +61,80 @@ macro_rules! span_bug {
         $crate::session::span_bug_fmt(file!(), line!(), $span, format_args!($($message)*))
     })
 }
+
+#[macro_export]
+macro_rules! __impl_stable_hash_field {
+    (DECL IGNORED) => (_);
+    (DECL $name:ident) => (ref $name);
+    (USE IGNORED $ctx:expr, $hasher:expr) => ({});
+    (USE $name:ident, $ctx:expr, $hasher:expr) => ($name.hash_stable($ctx, $hasher));
+}
+
+#[macro_export]
+macro_rules! impl_stable_hash_for {
+    (enum $enum_name:path { $( $variant:ident $( ( $($arg:ident),* ) )* ),* }) => {
+        impl<'a, 'tcx> ::rustc_data_structures::stable_hasher::HashStable<$crate::ich::StableHashingContext<'a, 'tcx>> for $enum_name {
+            #[inline]
+            fn hash_stable<W: ::rustc_data_structures::stable_hasher::StableHasherResult>(&self,
+                                                  __ctx: &mut $crate::ich::StableHashingContext<'a, 'tcx>,
+                                                  __hasher: &mut ::rustc_data_structures::stable_hasher::StableHasher<W>) {
+                use $enum_name::*;
+                ::std::mem::discriminant(self).hash_stable(__ctx, __hasher);
+
+                match *self {
+                    $(
+                        $variant $( ( $( __impl_stable_hash_field!(DECL $arg) ),* ) )* => {
+                            $($( __impl_stable_hash_field!(USE $arg, __ctx, __hasher) );*)*
+                        }
+                    )*
+                }
+            }
+        }
+    };
+    (struct $struct_name:path { $($field:ident),* }) => {
+        impl<'a, 'tcx> ::rustc_data_structures::stable_hasher::HashStable<$crate::ich::StableHashingContext<'a, 'tcx>> for $struct_name {
+            #[inline]
+            fn hash_stable<W: ::rustc_data_structures::stable_hasher::StableHasherResult>(&self,
+                                                  __ctx: &mut $crate::ich::StableHashingContext<'a, 'tcx>,
+                                                  __hasher: &mut ::rustc_data_structures::stable_hasher::StableHasher<W>) {
+                let $struct_name {
+                    $(ref $field),*
+                } = *self;
+
+                $( $field.hash_stable(__ctx, __hasher));*
+            }
+        }
+    };
+    (tuple_struct $struct_name:path { $($field:ident),* }) => {
+        impl<'a, 'tcx> ::rustc_data_structures::stable_hasher::HashStable<$crate::ich::StableHashingContext<'a, 'tcx>> for $struct_name {
+            #[inline]
+            fn hash_stable<W: ::rustc_data_structures::stable_hasher::StableHasherResult>(&self,
+                                                  __ctx: &mut $crate::ich::StableHashingContext<'a, 'tcx>,
+                                                  __hasher: &mut ::rustc_data_structures::stable_hasher::StableHasher<W>) {
+                let $struct_name (
+                    $(ref $field),*
+                ) = *self;
+
+                $( $field.hash_stable(__ctx, __hasher));*
+            }
+        }
+    };
+}
+
+#[macro_export]
+macro_rules! impl_stable_hash_for_spanned {
+    ($T:path) => (
+
+        impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for ::syntax::codemap::Spanned<$T>
+        {
+            #[inline]
+            fn hash_stable<W: StableHasherResult>(&self,
+                                                  hcx: &mut StableHashingContext<'a, 'tcx>,
+                                                  hasher: &mut StableHasher<W>) {
+                self.node.hash_stable(hcx, hasher);
+                self.span.hash_stable(hcx, hasher);
+            }
+        }
+    );
+}
+
diff --git a/src/librustc/mir/cache.rs b/src/librustc/mir/cache.rs
index bc9bbebb1796a..799686ceca4a0 100644
--- a/src/librustc/mir/cache.rs
+++ b/src/librustc/mir/cache.rs
@@ -10,7 +10,9 @@
 
 use std::cell::{Ref, RefCell};
 use rustc_data_structures::indexed_vec::IndexVec;
-
+use rustc_data_structures::stable_hasher::{HashStable, StableHasher,
+                                           StableHasherResult};
+use ich::StableHashingContext;
 use mir::{Mir, BasicBlock};
 
 use rustc_serialize as serialize;
@@ -33,6 +35,13 @@ impl serialize::Decodable for Cache {
     }
 }
 
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for Cache {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          _: &mut StableHashingContext<'a, 'tcx>,
+                                          _: &mut StableHasher<W>) {
+        // do nothing
+    }
+}
 
 impl Cache {
     pub fn new() -> Self {
diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs
index 01dc7f51e29d9..aea4684e526ce 100644
--- a/src/librustc/mir/mod.rs
+++ b/src/librustc/mir/mod.rs
@@ -243,6 +243,19 @@ impl<'tcx> Mir<'tcx> {
     }
 }
 
+impl_stable_hash_for!(struct Mir<'tcx> {
+    basic_blocks,
+    visibility_scopes,
+    promoted,
+    return_ty,
+    local_decls,
+    arg_count,
+    upvar_decls,
+    spread_arg,
+    span,
+    cache
+});
+
 impl<'tcx> Index<BasicBlock> for Mir<'tcx> {
     type Output = BasicBlockData<'tcx>;
 
@@ -830,6 +843,11 @@ pub struct Static<'tcx> {
     pub ty: Ty<'tcx>,
 }
 
+impl_stable_hash_for!(struct Static<'tcx> {
+    def_id,
+    ty
+});
+
 /// The `Projection` data structure defines things of the form `B.x`
 /// or `*B` or `B[index]`. Note that it is parameterized because it is
 /// shared between `Constant` and `Lvalue`. See the aliases
diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs
index 6a4e7db21dd12..3c529a6982042 100644
--- a/src/librustc/ty/mod.rs
+++ b/src/librustc/ty/mod.rs
@@ -19,6 +19,7 @@ use dep_graph::{self, DepNode};
 use hir::{map as hir_map, FreevarMap, TraitMap};
 use hir::def::{Def, CtorKind, ExportMap};
 use hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX, LOCAL_CRATE};
+use ich::StableHashingContext;
 use middle::const_val::ConstVal;
 use middle::lang_items::{FnTraitLangItem, FnMutTraitLangItem, FnOnceTraitLangItem};
 use middle::privacy::AccessLevels;
@@ -50,6 +51,8 @@ use syntax_pos::{DUMMY_SP, Span};
 use rustc_const_math::ConstInt;
 
 use rustc_data_structures::accumulate_vec::IntoIter as AccIntoIter;
+use rustc_data_structures::stable_hasher::{StableHasher, StableHasherResult,
+                                           HashStable};
 
 use hir;
 use hir::itemlikevisit::ItemLikeVisitor;
@@ -1379,6 +1382,25 @@ impl<'tcx> serialize::UseSpecializedEncodable for &'tcx AdtDef {
 
 impl<'tcx> serialize::UseSpecializedDecodable for &'tcx AdtDef {}
 
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for AdtDef {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        let ty::AdtDef {
+            did,
+            ref variants,
+            ref flags,
+            ref repr,
+        } = *self;
+
+        did.hash_stable(hcx, hasher);
+        variants.hash_stable(hcx, hasher);
+        flags.hash_stable(hcx, hasher);
+        repr.hash_stable(hcx, hasher);
+    }
+}
+
 #[derive(Copy, Clone, Debug, Eq, PartialEq)]
 pub enum AdtKind { Struct, Union, Enum }
 
@@ -1391,6 +1413,13 @@ pub struct ReprOptions {
     pub int: Option<attr::IntType>,
 }
 
+impl_stable_hash_for!(struct ReprOptions {
+    c,
+    packed,
+    simd,
+    int
+});
+
 impl ReprOptions {
     pub fn new(tcx: TyCtxt, did: DefId) -> ReprOptions {
         let mut ret = ReprOptions::default();
diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs
index 9ccd95dd8d805..c1735b4a4ec9a 100644
--- a/src/librustc_data_structures/lib.rs
+++ b/src/librustc_data_structures/lib.rs
@@ -37,6 +37,8 @@
 #![feature(unsize)]
 #![feature(i128_type)]
 #![feature(conservative_impl_trait)]
+#![feature(discriminant_value)]
+#![feature(specialization)]
 
 #![cfg_attr(unix, feature(libc))]
 #![cfg_attr(test, feature(test))]
diff --git a/src/librustc_data_structures/stable_hasher.rs b/src/librustc_data_structures/stable_hasher.rs
index 231c01c9ab78d..dc412a0763ef7 100644
--- a/src/librustc_data_structures/stable_hasher.rs
+++ b/src/librustc_data_structures/stable_hasher.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use std::hash::Hasher;
+use std::hash::{Hash, Hasher};
 use std::marker::PhantomData;
 use std::mem;
 use blake2b::Blake2bHasher;
@@ -174,3 +174,193 @@ impl<W> Hasher for StableHasher<W> {
         self.write_ileb128(i as i64);
     }
 }
+
+
+/// Something that implements `HashStable<CTX>` can be hashed in a way that is
+/// stable across multiple compiliation sessions.
+pub trait HashStable<CTX> {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut CTX,
+                                          hasher: &mut StableHasher<W>);
+}
+
+// Implement HashStable by just calling `Hash::hash()`. This works fine for
+// self-contained values that don't depend on the hashing context `CTX`.
+macro_rules! impl_stable_hash_via_hash {
+    ($t:ty) => (
+        impl<CTX> HashStable<CTX> for $t {
+            #[inline]
+            fn hash_stable<W: StableHasherResult>(&self,
+                                                  _: &mut CTX,
+                                                  hasher: &mut StableHasher<W>) {
+                ::std::hash::Hash::hash(self, hasher);
+            }
+        }
+    );
+}
+
+impl_stable_hash_via_hash!(i8);
+impl_stable_hash_via_hash!(i16);
+impl_stable_hash_via_hash!(i32);
+impl_stable_hash_via_hash!(i64);
+impl_stable_hash_via_hash!(isize);
+
+impl_stable_hash_via_hash!(u8);
+impl_stable_hash_via_hash!(u16);
+impl_stable_hash_via_hash!(u32);
+impl_stable_hash_via_hash!(u64);
+impl_stable_hash_via_hash!(usize);
+
+impl_stable_hash_via_hash!(u128);
+impl_stable_hash_via_hash!(i128);
+
+impl_stable_hash_via_hash!(char);
+impl_stable_hash_via_hash!(());
+
+impl<CTX> HashStable<CTX> for f32 {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          ctx: &mut CTX,
+                                          hasher: &mut StableHasher<W>) {
+        let val: u32 = unsafe {
+            ::std::mem::transmute(*self)
+        };
+        val.hash_stable(ctx, hasher);
+    }
+}
+
+impl<CTX> HashStable<CTX> for f64 {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          ctx: &mut CTX,
+                                          hasher: &mut StableHasher<W>) {
+        let val: u64 = unsafe {
+            ::std::mem::transmute(*self)
+        };
+        val.hash_stable(ctx, hasher);
+    }
+}
+
+impl<T1: HashStable<CTX>, T2: HashStable<CTX>, CTX> HashStable<CTX> for (T1, T2) {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          ctx: &mut CTX,
+                                          hasher: &mut StableHasher<W>) {
+        self.0.hash_stable(ctx, hasher);
+        self.1.hash_stable(ctx, hasher);
+    }
+}
+
+impl<T: HashStable<CTX>, CTX> HashStable<CTX> for [T] {
+    default fn hash_stable<W: StableHasherResult>(&self,
+                                                  ctx: &mut CTX,
+                                                  hasher: &mut StableHasher<W>) {
+        self.len().hash_stable(ctx, hasher);
+        for item in self {
+            item.hash_stable(ctx, hasher);
+        }
+    }
+}
+
+impl<T: HashStable<CTX>, CTX> HashStable<CTX> for Vec<T> {
+    #[inline]
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          ctx: &mut CTX,
+                                          hasher: &mut StableHasher<W>) {
+        (&self[..]).hash_stable(ctx, hasher);
+    }
+}
+
+impl<CTX> HashStable<CTX> for str {
+    #[inline]
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          _: &mut CTX,
+                                          hasher: &mut StableHasher<W>) {
+        self.len().hash(hasher);
+        self.as_bytes().hash(hasher);
+    }
+}
+
+impl<CTX> HashStable<CTX> for bool {
+    #[inline]
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          ctx: &mut CTX,
+                                          hasher: &mut StableHasher<W>) {
+        (if *self { 1u8 } else { 0u8 }).hash_stable(ctx, hasher);
+    }
+}
+
+
+impl<T, CTX> HashStable<CTX> for Option<T>
+    where T: HashStable<CTX>
+{
+    #[inline]
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          ctx: &mut CTX,
+                                          hasher: &mut StableHasher<W>) {
+        if let Some(ref value) = *self {
+            1u8.hash_stable(ctx, hasher);
+            value.hash_stable(ctx, hasher);
+        } else {
+            0u8.hash_stable(ctx, hasher);
+        }
+    }
+}
+
+impl<'a, T, CTX> HashStable<CTX> for &'a T
+    where T: HashStable<CTX>
+{
+    #[inline]
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          ctx: &mut CTX,
+                                          hasher: &mut StableHasher<W>) {
+        (**self).hash_stable(ctx, hasher);
+    }
+}
+
+impl<T, CTX> HashStable<CTX> for ::std::mem::Discriminant<T> {
+    #[inline]
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          _: &mut CTX,
+                                          hasher: &mut StableHasher<W>) {
+        ::std::hash::Hash::hash(self, hasher);
+    }
+}
+
+impl<K, V, CTX> HashStable<CTX> for ::std::collections::BTreeMap<K, V>
+    where K: Ord + HashStable<CTX>,
+          V: HashStable<CTX>,
+{
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          ctx: &mut CTX,
+                                          hasher: &mut StableHasher<W>) {
+        self.len().hash_stable(ctx, hasher);
+        for (k, v) in self {
+            k.hash_stable(ctx, hasher);
+            v.hash_stable(ctx, hasher);
+        }
+    }
+}
+
+impl<T, CTX> HashStable<CTX> for ::std::collections::BTreeSet<T>
+    where T: Ord + HashStable<CTX>,
+{
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          ctx: &mut CTX,
+                                          hasher: &mut StableHasher<W>) {
+        self.len().hash_stable(ctx, hasher);
+        for v in self {
+            v.hash_stable(ctx, hasher);
+        }
+    }
+}
+
+impl<I: ::indexed_vec::Idx, T, CTX> HashStable<CTX> for ::indexed_vec::IndexVec<I, T>
+    where T: HashStable<CTX>,
+{
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          ctx: &mut CTX,
+                                          hasher: &mut StableHasher<W>) {
+        self.len().hash_stable(ctx, hasher);
+        for v in &self.raw {
+            v.hash_stable(ctx, hasher);
+        }
+    }
+}
diff --git a/src/librustc_incremental/calculate_svh/mod.rs b/src/librustc_incremental/calculate_svh/mod.rs
index c9496a4deb8eb..c80a5a1627797 100644
--- a/src/librustc_incremental/calculate_svh/mod.rs
+++ b/src/librustc_incremental/calculate_svh/mod.rs
@@ -27,24 +27,17 @@
 //! at the end of compilation would be different from those computed
 //! at the beginning.
 
-use syntax::ast;
 use std::cell::RefCell;
 use std::hash::Hash;
 use rustc::dep_graph::DepNode;
 use rustc::hir;
 use rustc::hir::def_id::{CRATE_DEF_INDEX, DefId};
-use rustc::hir::intravisit as visit;
-use rustc::hir::intravisit::{Visitor, NestedVisitorMap};
-use rustc::ich::{Fingerprint, DefPathHashes, CachingCodemapView};
+use rustc::hir::itemlikevisit::ItemLikeVisitor;
+use rustc::ich::{Fingerprint, StableHashingContext};
 use rustc::ty::TyCtxt;
-use rustc_data_structures::stable_hasher::StableHasher;
+use rustc_data_structures::stable_hasher::{StableHasher, HashStable};
 use rustc_data_structures::fx::FxHashMap;
 use rustc::util::common::record_time;
-use rustc::session::config::DebugInfoLevel::NoDebugInfo;
-
-use self::svh_visitor::StrictVersionHashVisitor;
-
-mod svh_visitor;
 
 pub type IchHasher = StableHasher<Fingerprint>;
 
@@ -94,91 +87,42 @@ impl<'a> ::std::ops::Index<&'a DepNode<DefId>> for IncrementalHashesMap {
     }
 }
 
-
-pub fn compute_incremental_hashes_map<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>)
-                                                    -> IncrementalHashesMap {
-    let _ignore = tcx.dep_graph.in_ignore();
-    let krate = tcx.hir.krate();
-    let hash_spans = tcx.sess.opts.debuginfo != NoDebugInfo;
-    let mut visitor = HashItemsVisitor {
-        tcx: tcx,
-        hashes: IncrementalHashesMap::new(),
-        def_path_hashes: DefPathHashes::new(tcx),
-        codemap: CachingCodemapView::new(tcx),
-        hash_spans: hash_spans,
-    };
-    record_time(&tcx.sess.perf_stats.incr_comp_hashes_time, || {
-        visitor.calculate_def_id(DefId::local(CRATE_DEF_INDEX), |v| {
-            v.hash_crate_root_module(krate);
-        });
-        krate.visit_all_item_likes(&mut visitor.as_deep_visitor());
-
-        for macro_def in krate.exported_macros.iter() {
-            visitor.calculate_node_id(macro_def.id,
-                                      |v| v.visit_macro_def(macro_def));
-        }
-    });
-
-    tcx.sess.perf_stats.incr_comp_hashes_count.set(visitor.hashes.len() as u64);
-
-    record_time(&tcx.sess.perf_stats.svh_time, || visitor.compute_crate_hash());
-    visitor.hashes
-}
-
-struct HashItemsVisitor<'a, 'tcx: 'a> {
-    tcx: TyCtxt<'a, 'tcx, 'tcx>,
-    def_path_hashes: DefPathHashes<'a, 'tcx>,
-    codemap: CachingCodemapView<'tcx>,
+struct ComputeItemHashesVisitor<'a, 'tcx: 'a> {
+    hcx: StableHashingContext<'a, 'tcx>,
     hashes: IncrementalHashesMap,
-    hash_spans: bool,
 }
 
-impl<'a, 'tcx> HashItemsVisitor<'a, 'tcx> {
-    fn calculate_node_id<W>(&mut self, id: ast::NodeId, walk_op: W)
-        where W: for<'v> FnMut(&mut StrictVersionHashVisitor<'v, 'a, 'tcx>)
-    {
-        let def_id = self.tcx.hir.local_def_id(id);
-        self.calculate_def_id(def_id, walk_op)
-    }
-
-    fn calculate_def_id<W>(&mut self, def_id: DefId, mut walk_op: W)
-        where W: for<'v> FnMut(&mut StrictVersionHashVisitor<'v, 'a, 'tcx>)
+impl<'a, 'tcx: 'a> ComputeItemHashesVisitor<'a, 'tcx> {
+    fn compute_and_store_ich_for_item_like<T>(&mut self,
+                                              dep_node: DepNode<DefId>,
+                                              hash_bodies: bool,
+                                              item_like: T)
+        where T: HashStable<StableHashingContext<'a, 'tcx>>
     {
-        assert!(def_id.is_local());
-        debug!("HashItemsVisitor::calculate(def_id={:?})", def_id);
-        self.calculate_def_hash(DepNode::Hir(def_id), false, &mut walk_op);
-        self.calculate_def_hash(DepNode::HirBody(def_id), true, &mut walk_op);
-    }
+        let mut hasher = IchHasher::new();
+        self.hcx.while_hashing_hir_bodies(hash_bodies, |hcx| {
+            item_like.hash_stable(hcx, &mut hasher);
+        });
 
-    fn calculate_def_hash<W>(&mut self,
-                             dep_node: DepNode<DefId>,
-                             hash_bodies: bool,
-                             walk_op: &mut W)
-        where W: for<'v> FnMut(&mut StrictVersionHashVisitor<'v, 'a, 'tcx>)
-    {
-        let mut state = IchHasher::new();
-        walk_op(&mut StrictVersionHashVisitor::new(&mut state,
-                                                   self.tcx,
-                                                   &mut self.def_path_hashes,
-                                                   &mut self.codemap,
-                                                   self.hash_spans,
-                                                   hash_bodies));
-        let bytes_hashed = state.bytes_hashed();
-        let item_hash = state.finish();
+        let bytes_hashed = hasher.bytes_hashed();
+        let item_hash = hasher.finish();
         debug!("calculate_def_hash: dep_node={:?} hash={:?}", dep_node, item_hash);
         self.hashes.insert(dep_node, item_hash);
 
-        let bytes_hashed = self.tcx.sess.perf_stats.incr_comp_bytes_hashed.get() +
+        let tcx = self.hcx.tcx();
+        let bytes_hashed =
+            tcx.sess.perf_stats.incr_comp_bytes_hashed.get() +
             bytes_hashed;
-        self.tcx.sess.perf_stats.incr_comp_bytes_hashed.set(bytes_hashed);
+        tcx.sess.perf_stats.incr_comp_bytes_hashed.set(bytes_hashed);
     }
 
     fn compute_crate_hash(&mut self) {
-        let krate = self.tcx.hir.krate();
+        let tcx = self.hcx.tcx();
+        let krate = tcx.hir.krate();
 
         let mut crate_state = IchHasher::new();
 
-        let crate_disambiguator = self.tcx.sess.local_crate_disambiguator();
+        let crate_disambiguator = tcx.sess.local_crate_disambiguator();
         "crate_disambiguator".hash(&mut crate_state);
         crate_disambiguator.as_str().len().hash(&mut crate_state);
         crate_disambiguator.as_str().hash(&mut crate_state);
@@ -186,7 +130,7 @@ impl<'a, 'tcx> HashItemsVisitor<'a, 'tcx> {
         // add each item (in some deterministic order) to the overall
         // crate hash.
         {
-            let def_path_hashes = &mut self.def_path_hashes;
+            let hcx = &mut self.hcx;
             let mut item_hashes: Vec<_> =
                 self.hashes.iter()
                            .map(|(item_dep_node, &item_hash)| {
@@ -194,7 +138,7 @@ impl<'a, 'tcx> HashItemsVisitor<'a, 'tcx> {
                                // DepNode<u64> where the u64 is the
                                // hash of the def-id's def-path:
                                let item_dep_node =
-                                   item_dep_node.map_def(|&did| Some(def_path_hashes.hash(did)))
+                                   item_dep_node.map_def(|&did| Some(hcx.def_path_hash(did)))
                                                 .unwrap();
                                (item_dep_node, item_hash)
                            })
@@ -203,40 +147,85 @@ impl<'a, 'tcx> HashItemsVisitor<'a, 'tcx> {
             item_hashes.hash(&mut crate_state);
         }
 
-        {
-            let mut visitor = StrictVersionHashVisitor::new(&mut crate_state,
-                                                            self.tcx,
-                                                            &mut self.def_path_hashes,
-                                                            &mut self.codemap,
-                                                            self.hash_spans,
-                                                            false);
-            visitor.hash_attributes(&krate.attrs);
-        }
+        krate.attrs.hash_stable(&mut self.hcx, &mut crate_state);
 
         let crate_hash = crate_state.finish();
         self.hashes.insert(DepNode::Krate, crate_hash);
         debug!("calculate_crate_hash: crate_hash={:?}", crate_hash);
     }
-}
 
-
-impl<'a, 'tcx> Visitor<'tcx> for HashItemsVisitor<'a, 'tcx> {
-    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
-        NestedVisitorMap::None
+    fn hash_crate_root_module(&mut self, krate: &'tcx hir::Crate) {
+        let hir::Crate {
+            ref module,
+            // Crate attributes are not copied over to the root `Mod`, so hash
+            // them explicitly here.
+            ref attrs,
+            span,
+
+            // These fields are handled separately:
+            exported_macros: _,
+            items: _,
+            trait_items: _,
+            impl_items: _,
+            bodies: _,
+            trait_impls: _,
+            trait_default_impl: _,
+            body_ids: _,
+        } = *krate;
+
+        let def_id = DefId::local(CRATE_DEF_INDEX);
+        self.compute_and_store_ich_for_item_like(DepNode::Hir(def_id),
+                                                 false,
+                                                 (module, (span, attrs)));
+        self.compute_and_store_ich_for_item_like(DepNode::HirBody(def_id),
+                                                 true,
+                                                 (module, (span, attrs)));
     }
+}
 
+impl<'a, 'tcx: 'a> ItemLikeVisitor<'tcx> for ComputeItemHashesVisitor<'a, 'tcx> {
     fn visit_item(&mut self, item: &'tcx hir::Item) {
-        self.calculate_node_id(item.id, |v| v.visit_item(item));
-        visit::walk_item(self, item);
+        let def_id = self.hcx.tcx().hir.local_def_id(item.id);
+        self.compute_and_store_ich_for_item_like(DepNode::Hir(def_id), false, item);
+        self.compute_and_store_ich_for_item_like(DepNode::HirBody(def_id), true, item);
     }
 
-    fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem) {
-        self.calculate_node_id(trait_item.id, |v| v.visit_trait_item(trait_item));
-        visit::walk_trait_item(self, trait_item);
+    fn visit_trait_item(&mut self, item: &'tcx hir::TraitItem) {
+        let def_id = self.hcx.tcx().hir.local_def_id(item.id);
+        self.compute_and_store_ich_for_item_like(DepNode::Hir(def_id), false, item);
+        self.compute_and_store_ich_for_item_like(DepNode::HirBody(def_id), true, item);
     }
 
-    fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem) {
-        self.calculate_node_id(impl_item.id, |v| v.visit_impl_item(impl_item));
-        visit::walk_impl_item(self, impl_item);
+    fn visit_impl_item(&mut self, item: &'tcx hir::ImplItem) {
+        let def_id = self.hcx.tcx().hir.local_def_id(item.id);
+        self.compute_and_store_ich_for_item_like(DepNode::Hir(def_id), false, item);
+        self.compute_and_store_ich_for_item_like(DepNode::HirBody(def_id), true, item);
     }
 }
+
+pub fn compute_incremental_hashes_map<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>)
+                                                    -> IncrementalHashesMap {
+    let _ignore = tcx.dep_graph.in_ignore();
+    let krate = tcx.hir.krate();
+
+    let mut visitor = ComputeItemHashesVisitor {
+        hcx: StableHashingContext::new(tcx),
+        hashes: IncrementalHashesMap::new(),
+    };
+
+    record_time(&tcx.sess.perf_stats.incr_comp_hashes_time, || {
+        visitor.hash_crate_root_module(krate);
+        krate.visit_all_item_likes(&mut visitor);
+
+        for macro_def in krate.exported_macros.iter() {
+            let def_id = tcx.hir.local_def_id(macro_def.id);
+            visitor.compute_and_store_ich_for_item_like(DepNode::Hir(def_id), false, macro_def);
+            visitor.compute_and_store_ich_for_item_like(DepNode::HirBody(def_id), true, macro_def);
+        }
+    });
+
+    tcx.sess.perf_stats.incr_comp_hashes_count.set(visitor.hashes.len() as u64);
+
+    record_time(&tcx.sess.perf_stats.svh_time, || visitor.compute_crate_hash());
+    visitor.hashes
+}
diff --git a/src/librustc_incremental/calculate_svh/svh_visitor.rs b/src/librustc_incremental/calculate_svh/svh_visitor.rs
deleted file mode 100644
index 5401b371888e9..0000000000000
--- a/src/librustc_incremental/calculate_svh/svh_visitor.rs
+++ /dev/null
@@ -1,1111 +0,0 @@
-// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-use self::SawExprComponent::*;
-use self::SawAbiComponent::*;
-use self::SawItemComponent::*;
-use self::SawPatComponent::*;
-use self::SawTyComponent::*;
-use self::SawTraitOrImplItemComponent::*;
-use syntax::abi::Abi;
-use syntax::ast::{self, Name, NodeId};
-use syntax::attr;
-use syntax::ext::hygiene::SyntaxContext;
-use syntax::parse::token;
-use syntax::symbol::InternedString;
-use syntax_pos::{Span, BytePos};
-use syntax::tokenstream;
-use rustc::hir;
-use rustc::hir::*;
-use rustc::hir::def::Def;
-use rustc::hir::def_id::DefId;
-use rustc::hir::intravisit::{self as visit, Visitor};
-use rustc::ich::{DefPathHashes, CachingCodemapView, IGNORED_ATTRIBUTES};
-use rustc::ty::TyCtxt;
-use std::hash::{Hash, Hasher};
-
-use super::IchHasher;
-
-pub struct StrictVersionHashVisitor<'a, 'hash: 'a, 'tcx: 'hash> {
-    pub tcx: TyCtxt<'hash, 'tcx, 'tcx>,
-    pub st: &'a mut IchHasher,
-    // collect a deterministic hash of def-ids that we have seen
-    def_path_hashes: &'a mut DefPathHashes<'hash, 'tcx>,
-    hash_spans: bool,
-    codemap: &'a mut CachingCodemapView<'tcx>,
-    overflow_checks_enabled: bool,
-    hash_bodies: bool,
-}
-
-impl<'a, 'hash, 'tcx> StrictVersionHashVisitor<'a, 'hash, 'tcx> {
-    pub fn new(st: &'a mut IchHasher,
-               tcx: TyCtxt<'hash, 'tcx, 'tcx>,
-               def_path_hashes: &'a mut DefPathHashes<'hash, 'tcx>,
-               codemap: &'a mut CachingCodemapView<'tcx>,
-               hash_spans: bool,
-               hash_bodies: bool)
-               -> Self {
-        let check_overflow = tcx.sess.overflow_checks();
-
-        StrictVersionHashVisitor {
-            st: st,
-            tcx: tcx,
-            def_path_hashes: def_path_hashes,
-            hash_spans: hash_spans,
-            codemap: codemap,
-            overflow_checks_enabled: check_overflow,
-            hash_bodies: hash_bodies,
-        }
-    }
-
-    fn compute_def_id_hash(&mut self, def_id: DefId) -> u64 {
-        self.def_path_hashes.hash(def_id)
-    }
-
-    // Hash a span in a stable way. We can't directly hash the span's BytePos
-    // fields (that would be similar to hashing pointers, since those are just
-    // offsets into the CodeMap). Instead, we hash the (file name, line, column)
-    // triple, which stays the same even if the containing FileMap has moved
-    // within the CodeMap.
-    // Also note that we are hashing byte offsets for the column, not unicode
-    // codepoint offsets. For the purpose of the hash that's sufficient.
-    // Also, hashing filenames is expensive so we avoid doing it twice when the
-    // span starts and ends in the same file, which is almost always the case.
-    fn hash_span(&mut self, span: Span) {
-        debug!("hash_span: st={:?}", self.st);
-
-        // If this is not an empty or invalid span, we want to hash the last
-        // position that belongs to it, as opposed to hashing the first
-        // position past it.
-        let span_hi = if span.hi > span.lo {
-            // We might end up in the middle of a multibyte character here,
-            // but that's OK, since we are not trying to decode anything at
-            // this position.
-            span.hi - BytePos(1)
-        } else {
-            span.hi
-        };
-
-        let expn_kind = if span.ctxt == SyntaxContext::empty() {
-            SawSpanExpnKind::NoExpansion
-        } else {
-            SawSpanExpnKind::SomeExpansion
-        };
-
-        let loc1 = self.codemap.byte_pos_to_line_and_col(span.lo);
-        let loc1 = loc1.as_ref()
-                       .map(|&(ref fm, line, col)| (&fm.name[..], line, col))
-                       .unwrap_or(("???", 0, BytePos(0)));
-
-        let loc2 = self.codemap.byte_pos_to_line_and_col(span_hi);
-        let loc2 = loc2.as_ref()
-                       .map(|&(ref fm, line, col)| (&fm.name[..], line, col))
-                       .unwrap_or(("???", 0, BytePos(0)));
-
-        let saw = if loc1.0 == loc2.0 {
-            SawSpan(loc1.0,
-                    loc1.1, loc1.2,
-                    loc2.1, loc2.2,
-                    expn_kind)
-        } else {
-            SawSpanTwoFiles(loc1.0, loc1.1, loc1.2,
-                            loc2.0, loc2.1, loc2.2,
-                            expn_kind)
-        };
-        saw.hash(self.st);
-
-        if expn_kind == SawSpanExpnKind::SomeExpansion {
-            self.hash_span(span.source_callsite());
-        }
-    }
-
-    fn hash_discriminant<T>(&mut self, v: &T) {
-        unsafe {
-            let disr = ::std::intrinsics::discriminant_value(v);
-            debug!("hash_discriminant: disr={}, st={:?}", disr, self.st);
-            disr.hash(self.st);
-        }
-    }
-}
-
-// To off-load the bulk of the hash-computation on #[derive(Hash)],
-// we define a set of enums corresponding to the content that our
-// crate visitor will encounter as it traverses the ast.
-//
-// The important invariant is that all of the Saw*Component enums
-// do not carry any Spans, Names, or Idents.
-//
-// Not carrying any Names/Idents is the important fix for problem
-// noted on PR #13948: using the ident.name as the basis for a
-// hash leads to unstable SVH, because ident.name is just an index
-// into intern table (i.e. essentially a random address), not
-// computed from the name content.
-//
-// With the below enums, the SVH computation is not sensitive to
-// artifacts of how rustc was invoked nor of how the source code
-// was laid out.  (Or at least it is *less* sensitive.)
-
-// This enum represents the different potential bits of code the
-// visitor could encounter that could affect the ABI for the crate,
-// and assigns each a distinct tag to feed into the hash computation.
-#[derive(Hash)]
-enum SawAbiComponent<'a> {
-
-    // FIXME (#14132): should we include (some function of)
-    // ident.ctxt as well?
-    SawIdent(InternedString),
-    SawStructDef(InternedString),
-
-    SawLifetime,
-    SawLifetimeDef(usize),
-
-    SawMod,
-    SawForeignItem(SawForeignItemComponent),
-    SawItem(SawItemComponent),
-    SawTy(SawTyComponent),
-    SawFnDecl(bool),
-    SawGenerics,
-    SawTraitItem(SawTraitOrImplItemComponent),
-    SawImplItem(SawTraitOrImplItemComponent),
-    SawStructField,
-    SawVariant(bool),
-    SawQPath,
-    SawPathSegment,
-    SawPathParameters,
-    SawBlock,
-    SawPat(SawPatComponent),
-    SawLocal,
-    SawArm,
-    SawExpr(SawExprComponent<'a>),
-    SawStmt,
-    SawVis,
-    SawAssociatedItemKind(hir::AssociatedItemKind),
-    SawDefaultness(hir::Defaultness),
-    SawWherePredicate,
-    SawTyParamBound,
-    SawPolyTraitRef,
-    SawAssocTypeBinding,
-    SawAttribute(ast::AttrStyle),
-    SawMacroDef,
-    SawSpan(&'a str,
-            usize, BytePos,
-            usize, BytePos,
-            SawSpanExpnKind),
-    SawSpanTwoFiles(&'a str, usize, BytePos,
-                    &'a str, usize, BytePos,
-                    SawSpanExpnKind),
-}
-
-/// SawExprComponent carries all of the information that we want
-/// to include in the hash that *won't* be covered by the
-/// subsequent recursive traversal of the expression's
-/// substructure by the visitor.
-///
-/// We know every Expr_ variant is covered by a variant because
-/// `fn saw_expr` maps each to some case below.  Ensuring that
-/// each variant carries an appropriate payload has to be verified
-/// by hand.
-///
-/// (However, getting that *exactly* right is not so important
-/// because the SVH is just a developer convenience; there is no
-/// guarantee of collision-freedom, hash collisions are just
-/// (hopefully) unlikely.)
-///
-/// The xxxComponent enums and saw_xxx functions for Item, Pat,
-/// Ty, TraitItem and ImplItem follow the same methodology.
-#[derive(Hash)]
-enum SawExprComponent<'a> {
-
-    SawExprLoop(Option<InternedString>),
-    SawExprField(InternedString),
-    SawExprTupField(usize),
-    SawExprBreak(Option<InternedString>),
-    SawExprAgain(Option<InternedString>),
-
-    SawExprBox,
-    SawExprArray,
-    SawExprCall,
-    SawExprMethodCall,
-    SawExprTup,
-    SawExprBinary(hir::BinOp_),
-    SawExprUnary(hir::UnOp),
-    SawExprLit(ast::LitKind),
-    SawExprLitStr(InternedString, ast::StrStyle),
-    SawExprLitFloat(InternedString, Option<ast::FloatTy>),
-    SawExprCast,
-    SawExprType,
-    SawExprIf,
-    SawExprWhile,
-    SawExprMatch,
-    SawExprClosure(CaptureClause),
-    SawExprBlock,
-    SawExprAssign,
-    SawExprAssignOp(hir::BinOp_),
-    SawExprIndex,
-    SawExprPath,
-    SawExprAddrOf(hir::Mutability),
-    SawExprRet,
-    SawExprInlineAsm(StableInlineAsm<'a>),
-    SawExprStruct,
-    SawExprRepeat,
-}
-
-// The boolean returned indicates whether the span of this expression is always
-// significant, regardless of debuginfo.
-fn saw_expr<'a>(node: &'a Expr_,
-                overflow_checks_enabled: bool)
-                -> (SawExprComponent<'a>, bool) {
-    let binop_can_panic_at_runtime = |binop| {
-        match binop {
-            BiAdd |
-            BiSub |
-            BiMul => overflow_checks_enabled,
-
-            BiDiv |
-            BiRem => true,
-
-            BiAnd |
-            BiOr |
-            BiBitXor |
-            BiBitAnd |
-            BiBitOr |
-            BiShl |
-            BiShr |
-            BiEq |
-            BiLt |
-            BiLe |
-            BiNe |
-            BiGe |
-            BiGt => false
-        }
-    };
-
-    let unop_can_panic_at_runtime = |unop| {
-        match unop {
-            UnDeref |
-            UnNot => false,
-            UnNeg => overflow_checks_enabled,
-        }
-    };
-
-    match *node {
-        ExprBox(..)              => (SawExprBox, false),
-        ExprArray(..)            => (SawExprArray, false),
-        ExprCall(..)             => (SawExprCall, false),
-        ExprMethodCall(..)       => (SawExprMethodCall, false),
-        ExprTup(..)              => (SawExprTup, false),
-        ExprBinary(op, ..)       => {
-            (SawExprBinary(op.node), binop_can_panic_at_runtime(op.node))
-        }
-        ExprUnary(op, _)         => {
-            (SawExprUnary(op), unop_can_panic_at_runtime(op))
-        }
-        ExprLit(ref lit)         => (saw_lit(lit), false),
-        ExprCast(..)             => (SawExprCast, false),
-        ExprType(..)             => (SawExprType, false),
-        ExprIf(..)               => (SawExprIf, false),
-        ExprWhile(..)            => (SawExprWhile, false),
-        ExprLoop(_, id, _)       => (SawExprLoop(id.map(|id| id.node.as_str())), false),
-        ExprMatch(..)            => (SawExprMatch, false),
-        ExprClosure(cc, _, _, _) => (SawExprClosure(cc), false),
-        ExprBlock(..)            => (SawExprBlock, false),
-        ExprAssign(..)           => (SawExprAssign, false),
-        ExprAssignOp(op, ..)     => {
-            (SawExprAssignOp(op.node), binop_can_panic_at_runtime(op.node))
-        }
-        ExprField(_, name)       => (SawExprField(name.node.as_str()), false),
-        ExprTupField(_, id)      => (SawExprTupField(id.node), false),
-        ExprIndex(..)            => (SawExprIndex, true),
-        ExprPath(_)              => (SawExprPath, false),
-        ExprAddrOf(m, _)         => (SawExprAddrOf(m), false),
-        ExprBreak(label, _)      => (SawExprBreak(label.ident.map(|i|
-                                                    i.node.name.as_str())), false),
-        ExprAgain(label)         => (SawExprAgain(label.ident.map(|i|
-                                                    i.node.name.as_str())), false),
-        ExprRet(..)              => (SawExprRet, false),
-        ExprInlineAsm(ref a,..)  => (SawExprInlineAsm(StableInlineAsm(a)), false),
-        ExprStruct(..)           => (SawExprStruct, false),
-        ExprRepeat(..)           => (SawExprRepeat, false),
-    }
-}
-
-fn saw_lit(lit: &ast::Lit) -> SawExprComponent<'static> {
-    match lit.node {
-        ast::LitKind::Str(s, style) => SawExprLitStr(s.as_str(), style),
-        ast::LitKind::Float(s, ty) => SawExprLitFloat(s.as_str(), Some(ty)),
-        ast::LitKind::FloatUnsuffixed(s) => SawExprLitFloat(s.as_str(), None),
-        ref node @ _ => SawExprLit(node.clone()),
-    }
-}
-
-#[derive(Hash)]
-enum SawItemComponent {
-    SawItemExternCrate,
-    SawItemUse(UseKind),
-    SawItemStatic(Mutability),
-    SawItemConst,
-    SawItemFn(Unsafety, Constness, Abi),
-    SawItemMod,
-    SawItemForeignMod(Abi),
-    SawItemTy,
-    SawItemEnum,
-    SawItemStruct,
-    SawItemUnion,
-    SawItemTrait(Unsafety),
-    SawItemDefaultImpl(Unsafety),
-    SawItemImpl(Unsafety, ImplPolarity)
-}
-
-fn saw_item(node: &Item_) -> SawItemComponent {
-    match *node {
-        ItemExternCrate(..) => SawItemExternCrate,
-        ItemUse(_, kind) => SawItemUse(kind),
-        ItemStatic(_, mutability, _) => SawItemStatic(mutability),
-        ItemConst(..) =>SawItemConst,
-        ItemFn(_, unsafety, constness, abi, _, _) => SawItemFn(unsafety, constness, abi),
-        ItemMod(..) => SawItemMod,
-        ItemForeignMod(ref fm) => SawItemForeignMod(fm.abi),
-        ItemTy(..) => SawItemTy,
-        ItemEnum(..) => SawItemEnum,
-        ItemStruct(..) => SawItemStruct,
-        ItemUnion(..) => SawItemUnion,
-        ItemTrait(unsafety, ..) => SawItemTrait(unsafety),
-        ItemDefaultImpl(unsafety, _) => SawItemDefaultImpl(unsafety),
-        ItemImpl(unsafety, implpolarity, ..) => SawItemImpl(unsafety, implpolarity)
-    }
-}
-
-#[derive(Hash)]
-enum SawForeignItemComponent {
-    Static { mutable: bool },
-    Fn,
-}
-
-#[derive(Hash)]
-enum SawPatComponent {
-    SawPatWild,
-    SawPatBinding(BindingMode),
-    SawPatStruct,
-    SawPatTupleStruct,
-    SawPatPath,
-    SawPatTuple,
-    SawPatBox,
-    SawPatRef(Mutability),
-    SawPatLit,
-    SawPatRange,
-    SawPatSlice
-}
-
-fn saw_pat(node: &PatKind) -> SawPatComponent {
-    match *node {
-        PatKind::Wild => SawPatWild,
-        PatKind::Binding(bindingmode, ..) => SawPatBinding(bindingmode),
-        PatKind::Struct(..) => SawPatStruct,
-        PatKind::TupleStruct(..) => SawPatTupleStruct,
-        PatKind::Path(_) => SawPatPath,
-        PatKind::Tuple(..) => SawPatTuple,
-        PatKind::Box(..) => SawPatBox,
-        PatKind::Ref(_, mutability) => SawPatRef(mutability),
-        PatKind::Lit(..) => SawPatLit,
-        PatKind::Range(..) => SawPatRange,
-        PatKind::Slice(..) => SawPatSlice
-    }
-}
-
-#[derive(Hash)]
-enum SawTyComponent {
-    SawTySlice,
-    SawTyArray,
-    SawTyPtr(Mutability),
-    SawTyRptr(Mutability),
-    SawTyBareFn(Unsafety, Abi),
-    SawTyNever,
-    SawTyTup,
-    SawTyPath,
-    SawTyObjectSum,
-    SawTyImplTrait,
-    SawTyTypeof,
-    SawTyInfer
-}
-
-fn saw_ty(node: &Ty_) -> SawTyComponent {
-    match *node {
-      TySlice(..) => SawTySlice,
-      TyArray(..) => SawTyArray,
-      TyPtr(ref mty) => SawTyPtr(mty.mutbl),
-      TyRptr(_, ref mty) => SawTyRptr(mty.mutbl),
-      TyBareFn(ref barefnty) => SawTyBareFn(barefnty.unsafety, barefnty.abi),
-      TyNever => SawTyNever,
-      TyTup(..) => SawTyTup,
-      TyPath(_) => SawTyPath,
-      TyTraitObject(..) => SawTyObjectSum,
-      TyImplTrait(..) => SawTyImplTrait,
-      TyTypeof(..) => SawTyTypeof,
-      TyInfer => SawTyInfer
-    }
-}
-
-#[derive(Hash)]
-enum SawTraitOrImplItemComponent {
-    SawTraitOrImplItemConst,
-    // The boolean signifies whether a body is present
-    SawTraitOrImplItemMethod(Unsafety, Constness, Abi, bool),
-    SawTraitOrImplItemType
-}
-
-fn saw_trait_item(ti: &TraitItemKind) -> SawTraitOrImplItemComponent {
-    match *ti {
-        TraitItemKind::Const(..) => SawTraitOrImplItemConst,
-        TraitItemKind::Method(ref sig, TraitMethod::Required(_)) =>
-            SawTraitOrImplItemMethod(sig.unsafety, sig.constness, sig.abi, false),
-        TraitItemKind::Method(ref sig, TraitMethod::Provided(_)) =>
-            SawTraitOrImplItemMethod(sig.unsafety, sig.constness, sig.abi, true),
-        TraitItemKind::Type(..) => SawTraitOrImplItemType
-    }
-}
-
-fn saw_impl_item(ii: &ImplItemKind) -> SawTraitOrImplItemComponent {
-    match *ii {
-        ImplItemKind::Const(..) => SawTraitOrImplItemConst,
-        ImplItemKind::Method(ref sig, _) =>
-            SawTraitOrImplItemMethod(sig.unsafety, sig.constness, sig.abi, true),
-        ImplItemKind::Type(..) => SawTraitOrImplItemType
-    }
-}
-
-#[derive(Clone, Copy, Hash, Eq, PartialEq)]
-enum SawSpanExpnKind {
-    NoExpansion,
-    SomeExpansion,
-}
-
-/// A wrapper that provides a stable Hash implementation.
-struct StableInlineAsm<'a>(&'a InlineAsm);
-
-impl<'a> Hash for StableInlineAsm<'a> {
-    fn hash<H: Hasher>(&self, state: &mut H) {
-        let InlineAsm {
-            asm,
-            asm_str_style,
-            ref outputs,
-            ref inputs,
-            ref clobbers,
-            volatile,
-            alignstack,
-            dialect,
-            ctxt: _, // This is used for error reporting
-        } = *self.0;
-
-        asm.as_str().hash(state);
-        asm_str_style.hash(state);
-        outputs.len().hash(state);
-        for output in outputs {
-            let InlineAsmOutput { constraint, is_rw, is_indirect } = *output;
-            constraint.as_str().hash(state);
-            is_rw.hash(state);
-            is_indirect.hash(state);
-        }
-        inputs.len().hash(state);
-        for input in inputs {
-            input.as_str().hash(state);
-        }
-        clobbers.len().hash(state);
-        for clobber in clobbers {
-            clobber.as_str().hash(state);
-        }
-        volatile.hash(state);
-        alignstack.hash(state);
-        dialect.hash(state);
-    }
-}
-
-macro_rules! hash_attrs {
-    ($visitor:expr, $attrs:expr) => ({
-        let attrs = $attrs;
-        if attrs.len() > 0 {
-            $visitor.hash_attributes(attrs);
-        }
-    })
-}
-
-macro_rules! hash_span {
-    ($visitor:expr, $span:expr) => ({
-        hash_span!($visitor, $span, false)
-    });
-    ($visitor:expr, $span:expr, $force:expr) => ({
-        if $force || $visitor.hash_spans {
-            $visitor.hash_span($span);
-        }
-    });
-}
-
-impl<'a, 'hash, 'tcx> Visitor<'tcx> for StrictVersionHashVisitor<'a, 'hash, 'tcx> {
-    fn nested_visit_map<'this>(&'this mut self) -> visit::NestedVisitorMap<'this, 'tcx> {
-        if self.hash_bodies {
-            visit::NestedVisitorMap::OnlyBodies(&self.tcx.hir)
-        } else {
-            visit::NestedVisitorMap::None
-        }
-    }
-
-    fn visit_variant_data(&mut self,
-                          s: &'tcx VariantData,
-                          name: Name,
-                          _: &'tcx Generics,
-                          _: NodeId,
-                          span: Span) {
-        debug!("visit_variant_data: st={:?}", self.st);
-        SawStructDef(name.as_str()).hash(self.st);
-        hash_span!(self, span);
-        visit::walk_struct_def(self, s);
-    }
-
-    fn visit_variant(&mut self,
-                     v: &'tcx Variant,
-                     g: &'tcx Generics,
-                     item_id: NodeId) {
-        debug!("visit_variant: st={:?}", self.st);
-        SawVariant(v.node.disr_expr.is_some()).hash(self.st);
-        hash_attrs!(self, &v.node.attrs);
-        visit::walk_variant(self, v, g, item_id)
-    }
-
-    fn visit_name(&mut self, span: Span, name: Name) {
-        debug!("visit_name: st={:?}", self.st);
-        SawIdent(name.as_str()).hash(self.st);
-        hash_span!(self, span);
-    }
-
-    fn visit_lifetime(&mut self, l: &'tcx Lifetime) {
-        debug!("visit_lifetime: st={:?}", self.st);
-        SawLifetime.hash(self.st);
-        visit::walk_lifetime(self, l);
-    }
-
-    fn visit_lifetime_def(&mut self, l: &'tcx LifetimeDef) {
-        debug!("visit_lifetime_def: st={:?}", self.st);
-        SawLifetimeDef(l.bounds.len()).hash(self.st);
-        visit::walk_lifetime_def(self, l);
-    }
-
-    fn visit_expr(&mut self, ex: &'tcx Expr) {
-        debug!("visit_expr: st={:?}", self.st);
-        let (saw_expr, force_span) = saw_expr(&ex.node,
-                                              self.overflow_checks_enabled);
-        SawExpr(saw_expr).hash(self.st);
-        // No need to explicitly hash the discriminant here, since we are
-        // implicitly hashing the discriminant of SawExprComponent.
-        hash_span!(self, ex.span, force_span);
-        hash_attrs!(self, &ex.attrs);
-
-        // Always hash nested constant bodies (e.g. n in `[x; n]`).
-        let hash_bodies = self.hash_bodies;
-        self.hash_bodies = true;
-        visit::walk_expr(self, ex);
-        self.hash_bodies = hash_bodies;
-    }
-
-    fn visit_stmt(&mut self, s: &'tcx Stmt) {
-        debug!("visit_stmt: st={:?}", self.st);
-
-        // We don't want to modify the hash for decls, because
-        // they might be item decls (if they are local decls,
-        // we'll hash that fact in visit_local); but we do want to
-        // remember if this was a StmtExpr or StmtSemi (the later
-        // had an explicit semi-colon; this affects the typing
-        // rules).
-        match s.node {
-            StmtDecl(..) => (),
-            StmtExpr(..) => {
-                SawStmt.hash(self.st);
-                self.hash_discriminant(&s.node);
-                hash_span!(self, s.span);
-            }
-            StmtSemi(..) => {
-                SawStmt.hash(self.st);
-                self.hash_discriminant(&s.node);
-                hash_span!(self, s.span);
-            }
-        }
-
-        visit::walk_stmt(self, s)
-    }
-
-    fn visit_foreign_item(&mut self, i: &'tcx ForeignItem) {
-        debug!("visit_foreign_item: st={:?}", self.st);
-
-        match i.node {
-            ForeignItemFn(..) => {
-                SawForeignItem(SawForeignItemComponent::Fn)
-            }
-            ForeignItemStatic(_, mutable) => {
-                SawForeignItem(SawForeignItemComponent::Static {
-                    mutable: mutable
-                })
-            }
-        }.hash(self.st);
-
-        hash_span!(self, i.span);
-        hash_attrs!(self, &i.attrs);
-        visit::walk_foreign_item(self, i)
-    }
-
-    fn visit_item(&mut self, i: &'tcx Item) {
-        debug!("visit_item: {:?} st={:?}", i, self.st);
-
-        self.maybe_enable_overflow_checks(&i.attrs);
-
-        SawItem(saw_item(&i.node)).hash(self.st);
-        hash_span!(self, i.span);
-        hash_attrs!(self, &i.attrs);
-        visit::walk_item(self, i)
-    }
-
-    fn visit_mod(&mut self, m: &'tcx Mod, span: Span, n: NodeId) {
-        debug!("visit_mod: st={:?}", self.st);
-        SawMod.hash(self.st);
-        hash_span!(self, span);
-        visit::walk_mod(self, m, n)
-    }
-
-    fn visit_ty(&mut self, t: &'tcx Ty) {
-        debug!("visit_ty: st={:?}", self.st);
-        SawTy(saw_ty(&t.node)).hash(self.st);
-        hash_span!(self, t.span);
-
-        // Always hash nested constant bodies (e.g. N in `[T; N]`).
-        let hash_bodies = self.hash_bodies;
-        self.hash_bodies = true;
-        visit::walk_ty(self, t);
-        self.hash_bodies = hash_bodies;
-    }
-
-    fn visit_generics(&mut self, g: &'tcx Generics) {
-        debug!("visit_generics: st={:?}", self.st);
-        SawGenerics.hash(self.st);
-        visit::walk_generics(self, g)
-    }
-
-    fn visit_fn_decl(&mut self, fd: &'tcx FnDecl) {
-        debug!("visit_fn_decl: st={:?}", self.st);
-        SawFnDecl(fd.variadic).hash(self.st);
-        visit::walk_fn_decl(self, fd)
-    }
-
-    fn visit_trait_item(&mut self, ti: &'tcx TraitItem) {
-        debug!("visit_trait_item: st={:?}", self.st);
-
-        self.maybe_enable_overflow_checks(&ti.attrs);
-
-        SawTraitItem(saw_trait_item(&ti.node)).hash(self.st);
-        hash_span!(self, ti.span);
-        hash_attrs!(self, &ti.attrs);
-        visit::walk_trait_item(self, ti)
-    }
-
-    fn visit_impl_item(&mut self, ii: &'tcx ImplItem) {
-        debug!("visit_impl_item: st={:?}", self.st);
-
-        self.maybe_enable_overflow_checks(&ii.attrs);
-
-        SawImplItem(saw_impl_item(&ii.node)).hash(self.st);
-        hash_span!(self, ii.span);
-        hash_attrs!(self, &ii.attrs);
-        visit::walk_impl_item(self, ii)
-    }
-
-    fn visit_struct_field(&mut self, s: &'tcx StructField) {
-        debug!("visit_struct_field: st={:?}", self.st);
-        SawStructField.hash(self.st);
-        hash_span!(self, s.span);
-        hash_attrs!(self, &s.attrs);
-        visit::walk_struct_field(self, s)
-    }
-
-    fn visit_qpath(&mut self, qpath: &'tcx QPath, id: NodeId, span: Span) {
-        debug!("visit_qpath: st={:?}", self.st);
-        SawQPath.hash(self.st);
-        self.hash_discriminant(qpath);
-        visit::walk_qpath(self, qpath, id, span)
-    }
-
-    fn visit_path(&mut self, path: &'tcx Path, _: ast::NodeId) {
-        debug!("visit_path: st={:?}", self.st);
-        hash_span!(self, path.span);
-        visit::walk_path(self, path)
-    }
-
-    fn visit_def_mention(&mut self, def: Def) {
-        self.hash_def(def);
-    }
-
-    fn visit_block(&mut self, b: &'tcx Block) {
-        debug!("visit_block: st={:?}", self.st);
-        SawBlock.hash(self.st);
-        hash_span!(self, b.span);
-        visit::walk_block(self, b)
-    }
-
-    fn visit_pat(&mut self, p: &'tcx Pat) {
-        debug!("visit_pat: st={:?}", self.st);
-        SawPat(saw_pat(&p.node)).hash(self.st);
-        hash_span!(self, p.span);
-        visit::walk_pat(self, p)
-    }
-
-    fn visit_local(&mut self, l: &'tcx Local) {
-        debug!("visit_local: st={:?}", self.st);
-        SawLocal.hash(self.st);
-        hash_attrs!(self, &l.attrs);
-        visit::walk_local(self, l)
-        // No need to hash span, we are hashing all component spans
-    }
-
-    fn visit_arm(&mut self, a: &'tcx Arm) {
-        debug!("visit_arm: st={:?}", self.st);
-        SawArm.hash(self.st);
-        hash_attrs!(self, &a.attrs);
-        visit::walk_arm(self, a)
-    }
-
-    fn visit_id(&mut self, id: NodeId) {
-        debug!("visit_id: id={} st={:?}", id, self.st);
-        self.hash_resolve(id)
-    }
-
-    fn visit_vis(&mut self, v: &'tcx Visibility) {
-        debug!("visit_vis: st={:?}", self.st);
-        SawVis.hash(self.st);
-        self.hash_discriminant(v);
-        visit::walk_vis(self, v)
-    }
-
-    fn visit_associated_item_kind(&mut self, kind: &'tcx AssociatedItemKind) {
-        debug!("visit_associated_item_kind: st={:?}", self.st);
-        SawAssociatedItemKind(*kind).hash(self.st);
-        visit::walk_associated_item_kind(self, kind);
-    }
-
-    fn visit_defaultness(&mut self, defaultness: &'tcx Defaultness) {
-        debug!("visit_associated_item_kind: st={:?}", self.st);
-        SawDefaultness(*defaultness).hash(self.st);
-        visit::walk_defaultness(self, defaultness);
-    }
-
-    fn visit_where_predicate(&mut self, predicate: &'tcx WherePredicate) {
-        debug!("visit_where_predicate: st={:?}", self.st);
-        SawWherePredicate.hash(self.st);
-        self.hash_discriminant(predicate);
-        // Ignoring span. Any important nested components should be visited.
-        visit::walk_where_predicate(self, predicate)
-    }
-
-    fn visit_ty_param_bound(&mut self, bounds: &'tcx TyParamBound) {
-        debug!("visit_ty_param_bound: st={:?}", self.st);
-        SawTyParamBound.hash(self.st);
-        self.hash_discriminant(bounds);
-        // The TraitBoundModifier in TraitTyParamBound will be hash in
-        // visit_poly_trait_ref()
-        visit::walk_ty_param_bound(self, bounds)
-    }
-
-    fn visit_poly_trait_ref(&mut self, t: &'tcx PolyTraitRef, m: TraitBoundModifier) {
-        debug!("visit_poly_trait_ref: st={:?}", self.st);
-        SawPolyTraitRef.hash(self.st);
-        m.hash(self.st);
-        visit::walk_poly_trait_ref(self, t, m)
-    }
-
-    fn visit_path_segment(&mut self, path_span: Span, path_segment: &'tcx PathSegment) {
-        debug!("visit_path_segment: st={:?}", self.st);
-        SawPathSegment.hash(self.st);
-        visit::walk_path_segment(self, path_span, path_segment)
-    }
-
-    fn visit_path_parameters(&mut self, path_span: Span, path_parameters: &'tcx PathParameters) {
-        debug!("visit_path_parameters: st={:?}", self.st);
-        SawPathParameters.hash(self.st);
-        self.hash_discriminant(path_parameters);
-        visit::walk_path_parameters(self, path_span, path_parameters)
-    }
-
-    fn visit_assoc_type_binding(&mut self, type_binding: &'tcx TypeBinding) {
-        debug!("visit_assoc_type_binding: st={:?}", self.st);
-        SawAssocTypeBinding.hash(self.st);
-        hash_span!(self, type_binding.span);
-        visit::walk_assoc_type_binding(self, type_binding)
-    }
-
-    fn visit_attribute(&mut self, _: &ast::Attribute) {
-        // We explicitly do not use this method, since doing that would
-        // implicitly impose an order on the attributes being hashed, while we
-        // explicitly don't want their order to matter
-    }
-
-    fn visit_macro_def(&mut self, macro_def: &'tcx MacroDef) {
-        debug!("visit_macro_def: st={:?}", self.st);
-        SawMacroDef.hash(self.st);
-        hash_attrs!(self, &macro_def.attrs);
-        for tt in macro_def.body.trees() {
-            self.hash_token_tree(&tt);
-        }
-        visit::walk_macro_def(self, macro_def)
-    }
-}
-
-#[derive(Hash)]
-pub enum DefHash {
-    SawDefId,
-    SawLabel,
-    SawPrimTy,
-    SawSelfTy,
-    SawErr,
-}
-
-impl<'a, 'hash, 'tcx> StrictVersionHashVisitor<'a, 'hash, 'tcx> {
-    fn hash_resolve(&mut self, id: ast::NodeId) {
-        // Because whether or not a given id has an entry is dependent
-        // solely on expr variant etc, we don't need to hash whether
-        // or not an entry was present (we are already hashing what
-        // variant it is above when we visit the HIR).
-
-        if let Some(traits) = self.tcx.trait_map.get(&id) {
-            debug!("hash_resolve: id={:?} traits={:?} st={:?}", id, traits, self.st);
-            traits.len().hash(self.st);
-
-            // The ordering of the candidates is not fixed. So we hash
-            // the def-ids and then sort them and hash the collection.
-            let mut candidates: Vec<_> =
-                traits.iter()
-                      .map(|&TraitCandidate { def_id, import_id: _ }| {
-                          self.compute_def_id_hash(def_id)
-                      })
-                      .collect();
-            candidates.sort();
-            candidates.hash(self.st);
-        }
-    }
-
-    fn hash_def_id(&mut self, def_id: DefId) {
-        self.compute_def_id_hash(def_id).hash(self.st);
-    }
-
-    fn hash_def(&mut self, def: Def) {
-        match def {
-            // Crucial point: for all of these variants, the variant +
-            // add'l data that is added is always the same if the
-            // def-id is the same, so it suffices to hash the def-id
-            Def::Fn(..) |
-            Def::Mod(..) |
-            Def::Static(..) |
-            Def::Variant(..) |
-            Def::VariantCtor(..) |
-            Def::Enum(..) |
-            Def::TyAlias(..) |
-            Def::AssociatedTy(..) |
-            Def::TyParam(..) |
-            Def::Struct(..) |
-            Def::StructCtor(..) |
-            Def::Union(..) |
-            Def::Trait(..) |
-            Def::Method(..) |
-            Def::Const(..) |
-            Def::AssociatedConst(..) |
-            Def::Local(..) |
-            Def::Upvar(..) |
-            Def::Macro(..) => {
-                DefHash::SawDefId.hash(self.st);
-                self.hash_def_id(def.def_id());
-            }
-
-            Def::Label(..) => {
-                DefHash::SawLabel.hash(self.st);
-                // we don't encode the `id` because it always refers to something
-                // within this item, so if it changed, there would have to be other
-                // changes too
-            }
-            Def::PrimTy(ref prim_ty) => {
-                DefHash::SawPrimTy.hash(self.st);
-                prim_ty.hash(self.st);
-            }
-            Def::SelfTy(..) => {
-                DefHash::SawSelfTy.hash(self.st);
-                // the meaning of Self is always the same within a
-                // given context, so we don't need to hash the other
-                // fields
-            }
-            Def::Err => {
-                DefHash::SawErr.hash(self.st);
-            }
-        }
-    }
-
-    pub fn hash_attributes(&mut self, attributes: &[ast::Attribute]) {
-        debug!("hash_attributes: st={:?}", self.st);
-        let indices = self.indices_sorted_by(attributes, |attr| attr.name());
-
-        for i in indices {
-            let attr = &attributes[i];
-            match attr.name() {
-                Some(name) if IGNORED_ATTRIBUTES.contains(&&*name.as_str()) => continue,
-                _ => {}
-            };
-            if !attr.is_sugared_doc {
-                SawAttribute(attr.style).hash(self.st);
-                for segment in &attr.path.segments {
-                    SawIdent(segment.identifier.name.as_str()).hash(self.st);
-                }
-                for tt in attr.tokens.trees() {
-                    self.hash_token_tree(&tt);
-                }
-            }
-        }
-    }
-
-    fn indices_sorted_by<T, K, F>(&mut self, items: &[T], get_key: F) -> Vec<usize>
-        where K: Ord,
-              F: Fn(&T) -> K
-    {
-        let mut indices = Vec::with_capacity(items.len());
-        indices.extend(0 .. items.len());
-        indices.sort_by_key(|index| get_key(&items[*index]));
-        indices
-    }
-
-    fn maybe_enable_overflow_checks(&mut self, item_attrs: &[ast::Attribute]) {
-        if attr::contains_name(item_attrs, "rustc_inherit_overflow_checks") {
-            self.overflow_checks_enabled = true;
-        }
-    }
-
-    fn hash_token_tree(&mut self, tt: &tokenstream::TokenTree) {
-        self.hash_discriminant(tt);
-        match *tt {
-            tokenstream::TokenTree::Token(span, ref token) => {
-                hash_span!(self, span);
-                self.hash_token(token, span);
-            }
-            tokenstream::TokenTree::Delimited(span, ref delimited) => {
-                hash_span!(self, span);
-                delimited.delim.hash(self.st);
-                for sub_tt in delimited.stream().trees() {
-                    self.hash_token_tree(&sub_tt);
-                }
-            }
-        }
-    }
-
-    fn hash_token(&mut self,
-                  token: &token::Token,
-                  error_reporting_span: Span) {
-        self.hash_discriminant(token);
-        match *token {
-            token::Token::Eq |
-            token::Token::Lt |
-            token::Token::Le |
-            token::Token::EqEq |
-            token::Token::Ne |
-            token::Token::Ge |
-            token::Token::Gt |
-            token::Token::AndAnd |
-            token::Token::OrOr |
-            token::Token::Not |
-            token::Token::Tilde |
-            token::Token::At |
-            token::Token::Dot |
-            token::Token::DotDot |
-            token::Token::DotDotDot |
-            token::Token::Comma |
-            token::Token::Semi |
-            token::Token::Colon |
-            token::Token::ModSep |
-            token::Token::RArrow |
-            token::Token::LArrow |
-            token::Token::FatArrow |
-            token::Token::Pound |
-            token::Token::Dollar |
-            token::Token::Question |
-            token::Token::Underscore |
-            token::Token::Whitespace |
-            token::Token::Comment |
-            token::Token::Eof => {}
-
-            token::Token::BinOp(bin_op_token) |
-            token::Token::BinOpEq(bin_op_token) => bin_op_token.hash(self.st),
-
-            token::Token::OpenDelim(delim_token) |
-            token::Token::CloseDelim(delim_token) => delim_token.hash(self.st),
-
-            token::Token::Literal(ref lit, ref opt_name) => {
-                self.hash_discriminant(lit);
-                match *lit {
-                    token::Lit::Byte(val) |
-                    token::Lit::Char(val) |
-                    token::Lit::Integer(val) |
-                    token::Lit::Float(val) |
-                    token::Lit::Str_(val) |
-                    token::Lit::ByteStr(val) => val.as_str().hash(self.st),
-                    token::Lit::StrRaw(val, n) |
-                    token::Lit::ByteStrRaw(val, n) => {
-                        val.as_str().hash(self.st);
-                        n.hash(self.st);
-                    }
-                };
-                opt_name.map(ast::Name::as_str).hash(self.st);
-            }
-
-            token::Token::Ident(ident) |
-            token::Token::Lifetime(ident) |
-            token::Token::SubstNt(ident) => ident.name.as_str().hash(self.st),
-
-            token::Token::Interpolated(ref non_terminal) => {
-                // FIXME(mw): This could be implemented properly. It's just a
-                //            lot of work, since we would need to hash the AST
-                //            in a stable way, in addition to the HIR.
-                //            Since this is hardly used anywhere, just emit a
-                //            warning for now.
-                if self.tcx.sess.opts.debugging_opts.incremental.is_some() {
-                    let msg = format!("Quasi-quoting might make incremental \
-                                       compilation very inefficient: {:?}",
-                                      non_terminal);
-                    self.tcx.sess.span_warn(error_reporting_span, &msg[..]);
-                }
-
-                non_terminal.hash(self.st);
-            }
-
-            token::Token::DocComment(val) |
-            token::Token::Shebang(val) => val.as_str().hash(self.st),
-        }
-    }
-
-    pub fn hash_crate_root_module(&mut self, krate: &'tcx Crate) {
-        let hir::Crate {
-            ref module,
-            ref attrs,
-            span,
-
-            // These fields are handled separately:
-            exported_macros: _,
-            items: _,
-            trait_items: _,
-            impl_items: _,
-            bodies: _,
-            trait_impls: _,
-            trait_default_impl: _,
-            body_ids: _,
-        } = *krate;
-
-        visit::Visitor::visit_mod(self, module, span, ast::CRATE_NODE_ID);
-        // Crate attributes are not copied over to the root `Mod`, so hash them
-        // explicitly here.
-        hash_attrs!(self, attrs);
-    }
-}
diff --git a/src/librustc_incremental/lib.rs b/src/librustc_incremental/lib.rs
index 477777c975db2..d10df17f85837 100644
--- a/src/librustc_incremental/lib.rs
+++ b/src/librustc_incremental/lib.rs
@@ -22,7 +22,6 @@
 #![feature(rustc_private)]
 #![feature(staged_api)]
 #![feature(rand)]
-#![feature(core_intrinsics)]
 #![feature(conservative_impl_trait)]
 #![cfg_attr(stage0, feature(pub_restricted))]
 
diff --git a/src/librustc_trans/assert_module_sources.rs b/src/librustc_trans/assert_module_sources.rs
index 8528482c7856c..63cfe591ce366 100644
--- a/src/librustc_trans/assert_module_sources.rs
+++ b/src/librustc_trans/assert_module_sources.rs
@@ -32,8 +32,7 @@ use syntax::ast;
 
 use {ModuleSource, ModuleTranslation};
 
-const PARTITION_REUSED: &'static str = "rustc_partition_reused";
-const PARTITION_TRANSLATED: &'static str = "rustc_partition_translated";
+use rustc::ich::{ATTR_PARTITION_REUSED, ATTR_PARTITION_TRANSLATED};
 
 const MODULE: &'static str = "module";
 const CFG: &'static str = "cfg";
@@ -62,9 +61,9 @@ struct AssertModuleSource<'a, 'tcx: 'a> {
 
 impl<'a, 'tcx> AssertModuleSource<'a, 'tcx> {
     fn check_attr(&self, attr: &ast::Attribute) {
-        let disposition = if attr.check_name(PARTITION_REUSED) {
+        let disposition = if attr.check_name(ATTR_PARTITION_REUSED) {
             Disposition::Reused
-        } else if attr.check_name(PARTITION_TRANSLATED) {
+        } else if attr.check_name(ATTR_PARTITION_TRANSLATED) {
             Disposition::Translated
         } else {
             return;
diff --git a/src/libsyntax/ptr.rs b/src/libsyntax/ptr.rs
index 5875015893144..15111bbba0a92 100644
--- a/src/libsyntax/ptr.rs
+++ b/src/libsyntax/ptr.rs
@@ -43,6 +43,8 @@ use std::{mem, ptr, slice, vec};
 
 use serialize::{Encodable, Decodable, Encoder, Decoder};
 
+use rustc_data_structures::stable_hasher::{StableHasher, StableHasherResult,
+                                           HashStable};
 /// An owned smart pointer.
 #[derive(Hash, PartialEq, Eq, PartialOrd, Ord)]
 pub struct P<T: ?Sized> {
@@ -215,3 +217,13 @@ impl<T: Decodable> Decodable for P<[T]> {
         }))
     }
 }
+
+impl<CTX, T> HashStable<CTX> for P<T>
+    where T: ?Sized + HashStable<CTX>
+{
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut CTX,
+                                          hasher: &mut StableHasher<W>) {
+        (**self).hash_stable(hcx, hasher);
+    }
+}
diff --git a/src/libsyntax/util/rc_slice.rs b/src/libsyntax/util/rc_slice.rs
index 195fb23f9d8c7..2d9fd7aa87553 100644
--- a/src/libsyntax/util/rc_slice.rs
+++ b/src/libsyntax/util/rc_slice.rs
@@ -12,6 +12,9 @@ use std::fmt;
 use std::ops::Deref;
 use std::rc::Rc;
 
+use rustc_data_structures::stable_hasher::{StableHasher, StableHasherResult,
+                                           HashStable};
+
 #[derive(Clone)]
 pub struct RcSlice<T> {
     data: Rc<Box<[T]>>,
@@ -41,3 +44,13 @@ impl<T: fmt::Debug> fmt::Debug for RcSlice<T> {
         fmt::Debug::fmt(self.deref(), f)
     }
 }
+
+impl<CTX, T> HashStable<CTX> for RcSlice<T>
+    where T: HashStable<CTX>
+{
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut CTX,
+                                          hasher: &mut StableHasher<W>) {
+        (**self).hash_stable(hcx, hasher);
+    }
+}