about summary refs log tree commit diff
path: root/src/librustc/ich
diff options
context:
space:
mode:
Diffstat (limited to 'src/librustc/ich')
-rw-r--r--src/librustc/ich/hcx.rs300
-rw-r--r--src/librustc/ich/impls_const_math.rs71
-rw-r--r--src/librustc/ich/impls_hir.rs1104
-rw-r--r--src/librustc/ich/impls_mir.rs407
-rw-r--r--src/librustc/ich/impls_syntax.rs301
-rw-r--r--src/librustc/ich/impls_ty.rs415
-rw-r--r--src/librustc/ich/mod.rs28
7 files changed, 2625 insertions, 1 deletions
diff --git a/src/librustc/ich/hcx.rs b/src/librustc/ich/hcx.rs
new file mode 100644
index 00000000000..73d81212cd7
--- /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 00000000000..6d11f2a87a4
--- /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 00000000000..fb18f50027e
--- /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 00000000000..401f7e1921a
--- /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 00000000000..26734500001
--- /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 00000000000..7b6f3af2a11
--- /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 209953f3c68..f0601a0efab 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,
 ];