about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc/ich/hcx.rs52
-rw-r--r--src/librustc/ich/impls_ty.rs301
-rw-r--r--src/librustc/ich/mod.rs4
-rw-r--r--src/librustc/lib.rs1
-rw-r--r--src/librustc/middle/cstore.rs23
-rw-r--r--src/librustc/middle/free_region.rs4
-rw-r--r--src/librustc/ty/mod.rs17
-rw-r--r--src/librustc/ty/util.rs30
-rw-r--r--src/librustc_data_structures/array_vec.rs6
-rw-r--r--src/librustc_data_structures/blake2b.rs34
-rw-r--r--src/librustc_data_structures/lib.rs1
-rw-r--r--src/librustc_data_structures/stable_hasher.rs7
-rw-r--r--src/librustc_data_structures/transitive_relation.rs46
-rw-r--r--src/librustc_driver/driver.rs1
-rw-r--r--src/librustc_incremental/persist/data.rs14
-rw-r--r--src/librustc_incremental/persist/dirty_clean.rs64
-rw-r--r--src/librustc_incremental/persist/preds/mod.rs28
-rw-r--r--src/librustc_incremental/persist/save.rs81
-rw-r--r--src/librustc_metadata/astencode.rs42
-rw-r--r--src/librustc_metadata/cstore_impl.rs8
-rw-r--r--src/librustc_metadata/encoder.rs104
-rw-r--r--src/librustc_metadata/index_builder.rs140
-rw-r--r--src/librustc_metadata/lib.rs1
-rw-r--r--src/librustc_metadata/schema.rs140
-rw-r--r--src/librustc_trans/back/link.rs5
-rw-r--r--src/librustc_trans/base.rs11
-rw-r--r--src/librustc_trans/lib.rs2
-rw-r--r--src/test/incremental/hashes/enum_defs.rs92
-rw-r--r--src/test/incremental/hashes/extern_mods.rs40
-rw-r--r--src/test/incremental/hashes/function_interfaces.rs10
-rw-r--r--src/test/incremental/hashes/inherent_impls.rs20
-rw-r--r--src/test/incremental/hashes/struct_defs.rs90
-rw-r--r--src/test/incremental/hashes/trait_defs.rs121
-rw-r--r--src/test/incremental/hashes/trait_impls.rs58
-rw-r--r--src/test/incremental/unchecked_dirty_clean_metadata.rs10
-rw-r--r--src/tools/compiletest/src/runtest.rs10
36 files changed, 1241 insertions, 377 deletions
diff --git a/src/librustc/ich/hcx.rs b/src/librustc/ich/hcx.rs
index 5ef30550f11..3a6367c353c 100644
--- a/src/librustc/ich/hcx.rs
+++ b/src/librustc/ich/hcx.rs
@@ -13,8 +13,10 @@ use hir::def_id::DefId;
 use ich::{self, CachingCodemapView};
 use session::config::DebugInfoLevel::NoDebugInfo;
 use ty;
+use util::nodemap::NodeMap;
 
 use std::hash as std_hash;
+use std::collections::{HashMap, HashSet};
 
 use syntax::ast;
 use syntax::attr;
@@ -296,3 +298,53 @@ impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for Span {
         }
     }
 }
+
+pub fn hash_stable_hashmap<'a, 'tcx, K, V, R, SK, F, W>(hcx: &mut StableHashingContext<'a, 'tcx>,
+                                                        hasher: &mut StableHasher<W>,
+                                                        map: &HashMap<K, V, R>,
+                                                        extract_stable_key: F)
+    where K: Eq + std_hash::Hash,
+          V: HashStable<StableHashingContext<'a, 'tcx>>,
+          R: std_hash::BuildHasher,
+          SK: HashStable<StableHashingContext<'a, 'tcx>> + Ord + Clone,
+          F: Fn(&mut StableHashingContext<'a, 'tcx>, &K) -> SK,
+          W: StableHasherResult,
+{
+    let mut keys: Vec<_> = map.keys()
+                              .map(|k| (extract_stable_key(hcx, k), k))
+                              .collect();
+    keys.sort_unstable_by_key(|&(ref stable_key, _)| stable_key.clone());
+    keys.len().hash_stable(hcx, hasher);
+    for (stable_key, key) in keys {
+        stable_key.hash_stable(hcx, hasher);
+        map[key].hash_stable(hcx, hasher);
+    }
+}
+
+pub fn hash_stable_hashset<'a, 'tcx, K, R, SK, F, W>(hcx: &mut StableHashingContext<'a, 'tcx>,
+                                                     hasher: &mut StableHasher<W>,
+                                                     set: &HashSet<K, R>,
+                                                     extract_stable_key: F)
+    where K: Eq + std_hash::Hash,
+          R: std_hash::BuildHasher,
+          SK: HashStable<StableHashingContext<'a, 'tcx>> + Ord + Clone,
+          F: Fn(&mut StableHashingContext<'a, 'tcx>, &K) -> SK,
+          W: StableHasherResult,
+{
+    let mut keys: Vec<_> = set.iter()
+                              .map(|k| extract_stable_key(hcx, k))
+                              .collect();
+    keys.sort_unstable();
+    keys.hash_stable(hcx, hasher);
+}
+
+pub fn hash_stable_nodemap<'a, 'tcx, V, W>(hcx: &mut StableHashingContext<'a, 'tcx>,
+                                           hasher: &mut StableHasher<W>,
+                                           map: &NodeMap<V>)
+    where V: HashStable<StableHashingContext<'a, 'tcx>>,
+          W: StableHasherResult,
+{
+    hash_stable_hashmap(hcx, hasher, map, |hcx, node_id| {
+        hcx.tcx.hir.definitions().node_to_hir_id(*node_id).local_id
+    });
+}
diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs
index 7b6f3af2a11..46d1e7ef0c7 100644
--- a/src/librustc/ich/impls_ty.rs
+++ b/src/librustc/ich/impls_ty.rs
@@ -11,31 +11,22 @@
 //! This module contains `HashStable` implementations for various data types
 //! from rustc::ty in no particular order.
 
-use ich::StableHashingContext;
+use ich::{self, StableHashingContext, NodeIdHashingMode};
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher,
                                            StableHasherResult};
 use std::hash as std_hash;
 use std::mem;
+use syntax_pos::symbol::InternedString;
 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>
+impl<'a, 'tcx, T> HashStable<StableHashingContext<'a, 'tcx>> for &'tcx 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);
+        (&self[..]).hash_stable(hcx, hasher);
     }
 }
 
@@ -67,9 +58,13 @@ impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for ty::Region {
                 index.hash_stable(hcx, hasher);
                 name.hash_stable(hcx, hasher);
             }
+            ty::ReScope(code_extent) => {
+                code_extent.hash_stable(hcx, hasher);
+            }
+            ty::ReFree(ref free_region) => {
+                free_region.hash_stable(hcx, hasher);
+            }
             ty::ReLateBound(..) |
-            ty::ReFree(..) |
-            ty::ReScope(..) |
             ty::ReVar(..) |
             ty::ReSkolemized(..) => {
                 bug!("TypeIdHasher: unexpected region {:?}", *self)
@@ -127,7 +122,6 @@ impl_stable_hash_for!(enum ty::BorrowKind {
     MutBorrow
 });
 
-
 impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for ty::UpvarCapture<'tcx> {
     fn hash_stable<W: StableHasherResult>(&self,
                                           hcx: &mut StableHashingContext<'a, 'tcx>,
@@ -223,7 +217,6 @@ impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for ty::Predicate<'tcx
     }
 }
 
-
 impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for ty::AdtFlags {
     fn hash_stable<W: StableHasherResult>(&self,
                                           _: &mut StableHashingContext<'a, 'tcx>,
@@ -280,9 +273,14 @@ for ::middle::const_val::ConstVal<'tcx> {
                 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::Struct(ref name_value_map) => {
+                let mut values: Vec<(InternedString, &ConstVal)> =
+                    name_value_map.iter()
+                                  .map(|(name, val)| (name.as_str(), val))
+                                  .collect();
+
+                values.sort_unstable_by_key(|&(ref name, _)| name.clone());
+                values.hash_stable(hcx, hasher);
             }
             ConstVal::Tuple(ref value) => {
                 value.hash_stable(hcx, hasher);
@@ -303,7 +301,6 @@ for ::middle::const_val::ConstVal<'tcx> {
 
 impl_stable_hash_for!(struct ty::ClosureSubsts<'tcx> { substs });
 
-
 impl_stable_hash_for!(struct ty::GenericPredicates<'tcx> {
     parent,
     predicates
@@ -413,3 +410,265 @@ impl_stable_hash_for!(struct ::middle::region::CallSiteScopeData {
 impl_stable_hash_for!(struct ty::DebruijnIndex {
     depth
 });
+
+impl_stable_hash_for!(enum ty::cast::CastKind {
+    CoercionCast,
+    PtrPtrCast,
+    PtrAddrCast,
+    AddrPtrCast,
+    NumericCast,
+    EnumCast,
+    PrimIntCast,
+    U8CharCast,
+    ArrayPtrCast,
+    FnPtrPtrCast,
+    FnPtrAddrCast
+});
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for ::middle::region::CodeExtent
+{
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| {
+            hcx.tcx().region_maps.code_extent_data(*self).hash_stable(hcx, hasher);
+        });
+    }
+}
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for ::middle::region::CodeExtentData
+{
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        use middle::region::CodeExtentData;
+
+        mem::discriminant(self).hash_stable(hcx, hasher);
+        match *self {
+            CodeExtentData::Misc(node_id) |
+            CodeExtentData::DestructionScope(node_id) => {
+                node_id.hash_stable(hcx, hasher);
+            }
+            CodeExtentData::CallSiteScope { fn_id, body_id } |
+            CodeExtentData::ParameterScope { fn_id, body_id } => {
+                fn_id.hash_stable(hcx, hasher);
+                body_id.hash_stable(hcx, hasher);
+            }
+            CodeExtentData::Remainder(block_remainder) => {
+                block_remainder.hash_stable(hcx, hasher);
+            }
+        }
+    }
+}
+
+impl_stable_hash_for!(struct ::middle::region::BlockRemainder {
+    block,
+    first_statement_index
+});
+
+impl_stable_hash_for!(struct ty::adjustment::CoerceUnsizedInfo {
+    custom_kind
+});
+
+impl_stable_hash_for!(struct ty::FreeRegion {
+    scope,
+    bound_region
+});
+
+impl_stable_hash_for!(enum ty::BoundRegion {
+    BrAnon(index),
+    BrNamed(def_id, name),
+    BrFresh(index),
+    BrEnv
+});
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for ty::TypeVariants<'tcx>
+{
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        use ty::TypeVariants::*;
+
+        mem::discriminant(self).hash_stable(hcx, hasher);
+        match *self {
+            TyBool  |
+            TyChar  |
+            TyStr   |
+            TyNever => {
+                // Nothing more to hash.
+            }
+            TyInt(int_ty) => {
+                int_ty.hash_stable(hcx, hasher);
+            }
+            TyUint(uint_ty) => {
+                uint_ty.hash_stable(hcx, hasher);
+            }
+            TyFloat(float_ty)  => {
+                float_ty.hash_stable(hcx, hasher);
+            }
+            TyAdt(adt_def, substs) => {
+                adt_def.hash_stable(hcx, hasher);
+                substs.hash_stable(hcx, hasher);
+            }
+            TyArray(inner_ty, len) => {
+                inner_ty.hash_stable(hcx, hasher);
+                len.hash_stable(hcx, hasher);
+            }
+            TySlice(inner_ty) => {
+                inner_ty.hash_stable(hcx, hasher);
+            }
+            TyRawPtr(pointee_ty) => {
+                pointee_ty.hash_stable(hcx, hasher);
+            }
+            TyRef(region, pointee_ty) => {
+                region.hash_stable(hcx, hasher);
+                pointee_ty.hash_stable(hcx, hasher);
+            }
+            TyFnDef(def_id, substs, ref sig) => {
+                def_id.hash_stable(hcx, hasher);
+                substs.hash_stable(hcx, hasher);
+                sig.hash_stable(hcx, hasher);
+            }
+            TyFnPtr(ref sig) => {
+                sig.hash_stable(hcx, hasher);
+            }
+            TyDynamic(ref existential_predicates, region) => {
+                existential_predicates.hash_stable(hcx, hasher);
+                region.hash_stable(hcx, hasher);
+            }
+            TyClosure(def_id, closure_substs) => {
+                def_id.hash_stable(hcx, hasher);
+                closure_substs.hash_stable(hcx, hasher);
+            }
+            TyTuple(inner_tys, from_diverging_type_var) => {
+                inner_tys.hash_stable(hcx, hasher);
+                from_diverging_type_var.hash_stable(hcx, hasher);
+            }
+            TyProjection(ref projection_ty) => {
+                projection_ty.hash_stable(hcx, hasher);
+            }
+            TyAnon(def_id, substs) => {
+                def_id.hash_stable(hcx, hasher);
+                substs.hash_stable(hcx, hasher);
+            }
+            TyParam(param_ty) => {
+                param_ty.hash_stable(hcx, hasher);
+            }
+
+            TyError     |
+            TyInfer(..) => {
+                bug!("ty::TypeVariants::hash_stable() - Unexpected variant.")
+            }
+        }
+    }
+}
+
+impl_stable_hash_for!(struct ty::ParamTy {
+    idx,
+    name
+});
+
+impl_stable_hash_for!(struct ty::TypeAndMut<'tcx> {
+    ty,
+    mutbl
+});
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for ty::ExistentialPredicate<'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::ExistentialPredicate::Trait(ref trait_ref) => {
+                trait_ref.hash_stable(hcx, hasher);
+            }
+            ty::ExistentialPredicate::Projection(ref projection) => {
+                projection.hash_stable(hcx, hasher);
+            }
+            ty::ExistentialPredicate::AutoTrait(def_id) => {
+                def_id.hash_stable(hcx, hasher);
+            }
+        }
+    }
+}
+
+impl_stable_hash_for!(struct ty::ExistentialTraitRef<'tcx> {
+    def_id,
+    substs
+});
+
+impl_stable_hash_for!(struct ty::ExistentialProjection<'tcx> {
+    trait_ref,
+    item_name,
+    ty
+});
+
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for ty::TypeckTables<'tcx> {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        let ty::TypeckTables {
+            ref type_relative_path_defs,
+            ref node_types,
+            ref item_substs,
+            ref adjustments,
+            ref method_map,
+            ref upvar_capture_map,
+            ref closure_tys,
+            ref closure_kinds,
+            ref liberated_fn_sigs,
+            ref fru_field_types,
+
+            ref cast_kinds,
+
+            // FIXME(#41184): This is still ignored at the moment.
+            lints: _,
+            ref used_trait_imports,
+            tainted_by_errors,
+            ref free_region_map,
+        } = *self;
+
+        hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| {
+            ich::hash_stable_nodemap(hcx, hasher, type_relative_path_defs);
+            ich::hash_stable_nodemap(hcx, hasher, node_types);
+            ich::hash_stable_nodemap(hcx, hasher, item_substs);
+            ich::hash_stable_nodemap(hcx, hasher, adjustments);
+
+            ich::hash_stable_hashmap(hcx, hasher, method_map, |hcx, method_call| {
+                let ty::MethodCall {
+                    expr_id,
+                    autoderef
+                } = *method_call;
+
+                let def_id = hcx.tcx().hir.local_def_id(expr_id);
+                (hcx.def_path_hash(def_id), autoderef)
+            });
+
+            ich::hash_stable_hashmap(hcx, hasher, upvar_capture_map, |hcx, up_var_id| {
+                let ty::UpvarId {
+                    var_id,
+                    closure_expr_id
+                } = *up_var_id;
+
+                let var_def_id = hcx.tcx().hir.local_def_id(var_id);
+                let closure_def_id = hcx.tcx().hir.local_def_id(closure_expr_id);
+                (hcx.def_path_hash(var_def_id), hcx.def_path_hash(closure_def_id))
+            });
+
+            ich::hash_stable_nodemap(hcx, hasher, closure_tys);
+            ich::hash_stable_nodemap(hcx, hasher, closure_kinds);
+            ich::hash_stable_nodemap(hcx, hasher, liberated_fn_sigs);
+            ich::hash_stable_nodemap(hcx, hasher, fru_field_types);
+            ich::hash_stable_nodemap(hcx, hasher, cast_kinds);
+
+            ich::hash_stable_hashset(hcx, hasher, used_trait_imports, |hcx, def_id| {
+                hcx.def_path_hash(*def_id)
+            });
+
+            tainted_by_errors.hash_stable(hcx, hasher);
+            free_region_map.hash_stable(hcx, hasher);
+        })
+    }
+}
diff --git a/src/librustc/ich/mod.rs b/src/librustc/ich/mod.rs
index f932c90a331..d70ed051ac4 100644
--- a/src/librustc/ich/mod.rs
+++ b/src/librustc/ich/mod.rs
@@ -12,8 +12,8 @@
 
 pub use self::fingerprint::Fingerprint;
 pub use self::caching_codemap_view::CachingCodemapView;
-pub use self::hcx::{StableHashingContext, NodeIdHashingMode};
-
+pub use self::hcx::{StableHashingContext, NodeIdHashingMode, hash_stable_hashmap,
+                    hash_stable_hashset, hash_stable_nodemap};
 mod fingerprint;
 mod caching_codemap_view;
 mod hcx;
diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs
index 3b002fd4dfc..1f96330d51d 100644
--- a/src/librustc/lib.rs
+++ b/src/librustc/lib.rs
@@ -42,6 +42,7 @@
 #![feature(staged_api)]
 #![feature(unboxed_closures)]
 #![feature(discriminant_value)]
+#![feature(sort_unstable)]
 
 extern crate arena;
 extern crate core;
diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs
index 69432181283..81cf24e58dd 100644
--- a/src/librustc/middle/cstore.rs
+++ b/src/librustc/middle/cstore.rs
@@ -27,6 +27,7 @@ use hir::def_id::{CrateNum, DefId, DefIndex};
 use hir::map as hir_map;
 use hir::map::definitions::{Definitions, DefKey, DisambiguatedDefPathData};
 use hir::svh::Svh;
+use ich;
 use middle::lang_items;
 use ty::{self, TyCtxt};
 use session::Session;
@@ -161,6 +162,20 @@ pub struct ExternCrate {
     pub path_len: usize,
 }
 
+pub struct EncodedMetadata {
+    pub raw_data: Vec<u8>,
+    pub hashes: Vec<EncodedMetadataHash>,
+}
+
+/// The hash for some metadata that (when saving) will be exported
+/// from this crate, or which (when importing) was exported by an
+/// upstream crate.
+#[derive(Debug, RustcEncodable, RustcDecodable, Copy, Clone)]
+pub struct EncodedMetadataHash {
+    pub def_index: DefIndex,
+    pub hash: ich::Fingerprint,
+}
+
 /// A store of Rust crates, through with their metadata
 /// can be accessed.
 pub trait CrateStore {
@@ -258,7 +273,8 @@ pub trait CrateStore {
     fn encode_metadata<'a, 'tcx>(&self,
                                  tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                  link_meta: &LinkMeta,
-                                 reachable: &NodeSet) -> Vec<u8>;
+                                 reachable: &NodeSet)
+                                 -> EncodedMetadata;
     fn metadata_encoding_version(&self) -> &[u8];
 }
 
@@ -417,7 +433,10 @@ impl CrateStore for DummyCrateStore {
     fn encode_metadata<'a, 'tcx>(&self,
                                  tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                  link_meta: &LinkMeta,
-                                 reachable: &NodeSet) -> Vec<u8> { vec![] }
+                                 reachable: &NodeSet)
+                                 -> EncodedMetadata {
+        bug!("encode_metadata")
+    }
     fn metadata_encoding_version(&self) -> &[u8] { bug!("metadata_encoding_version") }
 }
 
diff --git a/src/librustc/middle/free_region.rs b/src/librustc/middle/free_region.rs
index cdb081ab400..a8eb6a10743 100644
--- a/src/librustc/middle/free_region.rs
+++ b/src/librustc/middle/free_region.rs
@@ -180,3 +180,7 @@ fn lub() {
     map.relate_free_regions(frs[1], frs[2]);
     assert_eq!(map.lub_free_regions(frs[0], frs[1]), ty::ReFree(frs[2]));
 }
+
+impl_stable_hash_for!(struct FreeRegionMap {
+    relation
+});
diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs
index a2c356c20db..23f35d3bdd7 100644
--- a/src/librustc/ty/mod.rs
+++ b/src/librustc/ty/mod.rs
@@ -452,6 +452,23 @@ impl<'tcx> Hash for TyS<'tcx> {
     }
 }
 
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for ty::TyS<'tcx> {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        let ty::TyS {
+            ref sty,
+
+            // The other fields just provide fast access to information that is
+            // also contained in `sty`, so no need to hash them.
+            flags: _,
+            region_depth: _,
+        } = *self;
+
+        sty.hash_stable(hcx, hasher);
+    }
+}
+
 pub type Ty<'tcx> = &'tcx TyS<'tcx>;
 
 impl<'tcx> serialize::UseSpecializedEncodable for Ty<'tcx> {}
diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs
index fd8191303a9..c650ffe3027 100644
--- a/src/librustc/ty/util.rs
+++ b/src/librustc/ty/util.rs
@@ -13,7 +13,7 @@
 use hir::def_id::{DefId, LOCAL_CRATE};
 use hir::map::DefPathData;
 use infer::InferCtxt;
-// use hir::map as hir_map;
+use ich::{StableHashingContext, NodeIdHashingMode};
 use traits::{self, Reveal};
 use ty::{self, Ty, TyCtxt, TypeAndMut, TypeFlags, TypeFoldable};
 use ty::ParameterEnvironment;
@@ -25,8 +25,8 @@ use util::nodemap::FxHashMap;
 use middle::lang_items;
 
 use rustc_const_math::{ConstInt, ConstIsize, ConstUsize};
-use rustc_data_structures::stable_hasher::{StableHasher, StableHasherResult};
-
+use rustc_data_structures::stable_hasher::{StableHasher, StableHasherResult,
+                                           HashStable};
 use std::cell::RefCell;
 use std::cmp;
 use std::hash::Hash;
@@ -187,6 +187,22 @@ impl<'tcx> ParameterEnvironment<'tcx> {
     }
 }
 
+impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> {
+    /// Creates a hash of the type `Ty` which will be the same no matter what crate
+    /// context it's calculated within. This is used by the `type_id` intrinsic.
+    pub fn type_id_hash(self, ty: Ty<'tcx>) -> u64 {
+        let mut hasher = StableHasher::new();
+        let mut hcx = StableHashingContext::new(self);
+
+        hcx.while_hashing_spans(false, |hcx| {
+            hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| {
+                ty.hash_stable(hcx, &mut hasher);
+            });
+        });
+        hasher.finish()
+    }
+}
+
 impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
     pub fn has_error_field(self, ty: Ty<'tcx>) -> bool {
         match ty.sty {
@@ -339,14 +355,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
             .collect()
     }
 
-    /// Creates a hash of the type `Ty` which will be the same no matter what crate
-    /// context it's calculated within. This is used by the `type_id` intrinsic.
-    pub fn type_id_hash(self, ty: Ty<'tcx>) -> u64 {
-        let mut hasher = TypeIdHasher::new(self);
-        hasher.visit_ty(ty);
-        hasher.finish()
-    }
-
     /// Calculate the destructor of a given type.
     pub fn calculate_dtor(
         self,
diff --git a/src/librustc_data_structures/array_vec.rs b/src/librustc_data_structures/array_vec.rs
index adb22197226..848e5a076bb 100644
--- a/src/librustc_data_structures/array_vec.rs
+++ b/src/librustc_data_structures/array_vec.rs
@@ -40,6 +40,12 @@ unsafe impl<T> Array for [T; 8] {
     const LEN: usize = 8;
 }
 
+unsafe impl<T> Array for [T; 32] {
+    type Element = T;
+    type PartialStorage = [ManuallyDrop<T>; 32];
+    const LEN: usize = 32;
+}
+
 pub struct ArrayVec<A: Array> {
     count: usize,
     values: A::PartialStorage
diff --git a/src/librustc_data_structures/blake2b.rs b/src/librustc_data_structures/blake2b.rs
index 9d97a83f693..bdef9fefd41 100644
--- a/src/librustc_data_structures/blake2b.rs
+++ b/src/librustc_data_structures/blake2b.rs
@@ -29,16 +29,23 @@ pub struct Blake2bCtx {
     t: [u64; 2],
     c: usize,
     outlen: u16,
-    finalized: bool
+    finalized: bool,
+
+    #[cfg(debug_assertions)]
+    fnv_hash: u64,
 }
 
+#[cfg(debug_assertions)]
 impl ::std::fmt::Debug for Blake2bCtx {
-    fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> {
-        try!(write!(fmt, "hash: "));
-        for v in &self.h {
-            try!(write!(fmt, "{:x}", v));
-        }
-        Ok(())
+    fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
+        write!(fmt, "{:x}", self.fnv_hash)
+    }
+}
+
+#[cfg(not(debug_assertions))]
+impl ::std::fmt::Debug for Blake2bCtx {
+    fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
+        write!(fmt, "Enable debug_assertions() for more info.")
     }
 }
 
@@ -157,6 +164,9 @@ fn blake2b_new(outlen: usize, key: &[u8]) -> Blake2bCtx {
         c: 0,
         outlen: outlen as u16,
         finalized: false,
+
+        #[cfg(debug_assertions)]
+        fnv_hash: 0xcbf29ce484222325,
     };
 
     ctx.h[0] ^= 0x01010000 ^ ((key.len() << 8) as u64) ^ (outlen as u64);
@@ -194,6 +204,16 @@ fn blake2b_update(ctx: &mut Blake2bCtx, mut data: &[u8]) {
         checked_mem_copy(data, &mut ctx.b[ctx.c .. ], bytes_to_copy);
         ctx.c += bytes_to_copy;
     }
+
+    #[cfg(debug_assertions)]
+    {
+        // compute additional FNV hash for simpler to read debug output
+        const MAGIC_PRIME: u64 = 0x00000100000001b3;
+
+        for &byte in data {
+            ctx.fnv_hash = (ctx.fnv_hash ^ byte as u64).wrapping_mul(MAGIC_PRIME);
+        }
+    }
 }
 
 fn blake2b_final(ctx: &mut Blake2bCtx)
diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs
index 72c533a7461..00c46d992bf 100644
--- a/src/librustc_data_structures/lib.rs
+++ b/src/librustc_data_structures/lib.rs
@@ -40,6 +40,7 @@
 #![feature(discriminant_value)]
 #![feature(specialization)]
 #![feature(manually_drop)]
+#![feature(struct_field_attributes)]
 
 #![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 dc412a0763e..95f063976d4 100644
--- a/src/librustc_data_structures/stable_hasher.rs
+++ b/src/librustc_data_structures/stable_hasher.rs
@@ -40,13 +40,18 @@ fn write_signed_leb128_to_buf(buf: &mut [u8; 16], value: i64) -> usize {
 /// This hasher currently always uses the stable Blake2b algorithm
 /// and allows for variable output lengths through its type
 /// parameter.
-#[derive(Debug)]
 pub struct StableHasher<W> {
     state: Blake2bHasher,
     bytes_hashed: u64,
     width: PhantomData<W>,
 }
 
+impl<W: StableHasherResult> ::std::fmt::Debug for StableHasher<W> {
+    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
+        write!(f, "{:?}", self.state)
+    }
+}
+
 pub trait StableHasherResult: Sized {
     fn finish(hasher: StableHasher<Self>) -> Self;
 }
diff --git a/src/librustc_data_structures/transitive_relation.rs b/src/librustc_data_structures/transitive_relation.rs
index 2bce7faf08c..2631108aeb5 100644
--- a/src/librustc_data_structures/transitive_relation.rs
+++ b/src/librustc_data_structures/transitive_relation.rs
@@ -9,11 +9,14 @@
 // except according to those terms.
 
 use bitvec::BitMatrix;
+use stable_hasher::{HashStable, StableHasher, StableHasherResult};
 use rustc_serialize::{Encodable, Encoder, Decodable, Decoder};
 use std::cell::RefCell;
 use std::fmt::Debug;
 use std::mem;
 
+
+
 #[derive(Clone)]
 pub struct TransitiveRelation<T: Debug + PartialEq> {
     // List of elements. This is used to map from a T to a usize.  We
@@ -334,6 +337,49 @@ impl<T> Decodable for TransitiveRelation<T>
     }
 }
 
+impl<CTX, T> HashStable<CTX> for TransitiveRelation<T>
+    where T: HashStable<CTX> + PartialEq + Debug
+{
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut CTX,
+                                          hasher: &mut StableHasher<W>) {
+        // We are assuming here that the relation graph has been built in a
+        // deterministic way and we can just hash it the way it is.
+        let TransitiveRelation {
+            ref elements,
+            ref edges,
+            // "closure" is just a copy of the data above
+            closure: _
+        } = *self;
+
+        elements.hash_stable(hcx, hasher);
+        edges.hash_stable(hcx, hasher);
+    }
+}
+
+impl<CTX> HashStable<CTX> for Edge {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut CTX,
+                                          hasher: &mut StableHasher<W>) {
+        let Edge {
+            ref source,
+            ref target,
+        } = *self;
+
+        source.hash_stable(hcx, hasher);
+        target.hash_stable(hcx, hasher);
+    }
+}
+
+impl<CTX> HashStable<CTX> for Index {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut CTX,
+                                          hasher: &mut StableHasher<W>) {
+        let Index(idx) = *self;
+        idx.hash_stable(hcx, hasher);
+    }
+}
+
 #[test]
 fn test_one_step() {
     let mut relation = TransitiveRelation::new();
diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs
index 7556aa70752..21888ba94b3 100644
--- a/src/librustc_driver/driver.rs
+++ b/src/librustc_driver/driver.rs
@@ -1084,6 +1084,7 @@ pub fn phase_4_translate_to_llvm<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
          "serialize dep graph",
          || rustc_incremental::save_dep_graph(tcx,
                                               &incremental_hashes_map,
+                                              &translation.metadata.hashes,
                                               translation.link.crate_hash));
     translation
 }
diff --git a/src/librustc_incremental/persist/data.rs b/src/librustc_incremental/persist/data.rs
index d9009073956..8a1af5dd08d 100644
--- a/src/librustc_incremental/persist/data.rs
+++ b/src/librustc_incremental/persist/data.rs
@@ -13,6 +13,7 @@
 use rustc::dep_graph::{DepNode, WorkProduct, WorkProductId};
 use rustc::hir::def_id::DefIndex;
 use rustc::ich::Fingerprint;
+use rustc::middle::cstore::EncodedMetadataHash;
 use std::sync::Arc;
 use rustc_data_structures::fx::FxHashMap;
 
@@ -98,7 +99,7 @@ pub struct SerializedMetadataHashes {
     /// where `X` refers to some item in this crate. That `X` will be
     /// a `DefPathIndex` that gets retracted to the current `DefId`
     /// (matching the one found in this structure).
-    pub hashes: Vec<SerializedMetadataHash>,
+    pub hashes: Vec<EncodedMetadataHash>,
 
     /// For each DefIndex (as it occurs in SerializedMetadataHash), this
     /// map stores the DefPathIndex (as it occurs in DefIdDirectory), so
@@ -112,14 +113,3 @@ pub struct SerializedMetadataHashes {
     /// the DefIndex.
     pub index_map: FxHashMap<DefIndex, DefPathIndex>
 }
-
-/// The hash for some metadata that (when saving) will be exported
-/// from this crate, or which (when importing) was exported by an
-/// upstream crate.
-#[derive(Debug, RustcEncodable, RustcDecodable)]
-pub struct SerializedMetadataHash {
-    pub def_index: DefIndex,
-
-    /// the hash itself, computed by `calculate_item_hash`
-    pub hash: Fingerprint,
-}
diff --git a/src/librustc_incremental/persist/dirty_clean.rs b/src/librustc_incremental/persist/dirty_clean.rs
index d931f64d579..af5c1f05bd1 100644
--- a/src/librustc_incremental/persist/dirty_clean.rs
+++ b/src/librustc_incremental/persist/dirty_clean.rs
@@ -215,9 +215,11 @@ impl<'a, 'tcx> ItemLikeVisitor<'tcx> for DirtyCleanVisitor<'a, 'tcx> {
     }
 }
 
-pub fn check_dirty_clean_metadata<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                                  prev_metadata_hashes: &FxHashMap<DefId, Fingerprint>,
-                                  current_metadata_hashes: &FxHashMap<DefId, Fingerprint>) {
+pub fn check_dirty_clean_metadata<'a, 'tcx>(
+    tcx: TyCtxt<'a, 'tcx, 'tcx>,
+    prev_metadata_hashes: &FxHashMap<DefId, Fingerprint>,
+    current_metadata_hashes: &FxHashMap<DefId, Fingerprint>)
+{
     if !tcx.sess.opts.debugging_opts.query_dep_graph {
         return;
     }
@@ -230,7 +232,7 @@ pub fn check_dirty_clean_metadata<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
             current_metadata_hashes: current_metadata_hashes,
             checked_attrs: FxHashSet(),
         };
-        krate.visit_all_item_likes(&mut dirty_clean_visitor);
+        intravisit::walk_crate(&mut dirty_clean_visitor, krate);
 
         let mut all_attrs = FindAllAttrs {
             tcx: tcx,
@@ -246,30 +248,58 @@ pub fn check_dirty_clean_metadata<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     });
 }
 
-pub struct DirtyCleanMetadataVisitor<'a, 'tcx:'a, 'm> {
+pub struct DirtyCleanMetadataVisitor<'a, 'tcx: 'a, 'm> {
     tcx: TyCtxt<'a, 'tcx, 'tcx>,
     prev_metadata_hashes: &'m FxHashMap<DefId, Fingerprint>,
     current_metadata_hashes: &'m FxHashMap<DefId, Fingerprint>,
     checked_attrs: FxHashSet<ast::AttrId>,
 }
 
-impl<'a, 'tcx, 'm> ItemLikeVisitor<'tcx> for DirtyCleanMetadataVisitor<'a, 'tcx, 'm> {
+impl<'a, 'tcx, 'm> intravisit::Visitor<'tcx> for DirtyCleanMetadataVisitor<'a, 'tcx, 'm> {
+
+    fn nested_visit_map<'this>(&'this mut self) -> intravisit::NestedVisitorMap<'this, 'tcx> {
+        intravisit::NestedVisitorMap::All(&self.tcx.hir)
+    }
+
     fn visit_item(&mut self, item: &'tcx hir::Item) {
         self.check_item(item.id, item.span);
+        intravisit::walk_item(self, item);
+    }
 
-        if let hir::ItemEnum(ref def, _) = item.node {
-            for v in &def.variants {
-                self.check_item(v.node.data.id(), v.span);
-            }
+    fn visit_variant_data(&mut self,
+                          variant_data: &'tcx hir::VariantData,
+                          _: ast::Name,
+                          _: &'tcx hir::Generics,
+                          _parent_id: ast::NodeId,
+                          span: Span) {
+        if self.tcx.hir.find(variant_data.id()).is_some() {
+            // VariantData that represent structs or tuples don't have a
+            // separate entry in the HIR map and checking them would error,
+            // so only check if this is an enum or union variant.
+            self.check_item(variant_data.id(), span);
         }
+
+        intravisit::walk_struct_def(self, variant_data);
     }
 
-    fn visit_trait_item(&mut self, item: &hir::TraitItem) {
+    fn visit_trait_item(&mut self, item: &'tcx hir::TraitItem) {
         self.check_item(item.id, item.span);
+        intravisit::walk_trait_item(self, item);
     }
 
-    fn visit_impl_item(&mut self, item: &hir::ImplItem) {
+    fn visit_impl_item(&mut self, item: &'tcx hir::ImplItem) {
         self.check_item(item.id, item.span);
+        intravisit::walk_impl_item(self, item);
+    }
+
+    fn visit_foreign_item(&mut self, i: &'tcx hir::ForeignItem) {
+        self.check_item(i.id, i.span);
+        intravisit::walk_foreign_item(self, i);
+    }
+
+    fn visit_struct_field(&mut self, s: &'tcx hir::StructField) {
+        self.check_item(s.id, s.span);
+        intravisit::walk_struct_field(self, s);
     }
 }
 
@@ -281,13 +311,15 @@ impl<'a, 'tcx, 'm> DirtyCleanMetadataVisitor<'a, 'tcx, 'm> {
         for attr in self.tcx.get_attrs(def_id).iter() {
             if attr.check_name(ATTR_DIRTY_METADATA) {
                 if check_config(self.tcx, attr) {
-                    self.checked_attrs.insert(attr.id);
-                    self.assert_state(false, def_id, item_span);
+                    if self.checked_attrs.insert(attr.id) {
+                        self.assert_state(false, def_id, item_span);
+                    }
                 }
             } else if attr.check_name(ATTR_CLEAN_METADATA) {
                 if check_config(self.tcx, attr) {
-                    self.checked_attrs.insert(attr.id);
-                    self.assert_state(true, def_id, item_span);
+                    if self.checked_attrs.insert(attr.id) {
+                        self.assert_state(true, def_id, item_span);
+                    }
                 }
             }
         }
diff --git a/src/librustc_incremental/persist/preds/mod.rs b/src/librustc_incremental/persist/preds/mod.rs
index fe8cf72996e..e769641a4ca 100644
--- a/src/librustc_incremental/persist/preds/mod.rs
+++ b/src/librustc_incremental/persist/preds/mod.rs
@@ -44,16 +44,18 @@ impl<'q> Predecessors<'q> {
     pub fn new(query: &'q DepGraphQuery<DefId>, hcx: &mut HashContext) -> Self {
         let tcx = hcx.tcx;
 
-        let collect_for_metadata = tcx.sess.opts.debugging_opts.incremental_cc ||
-            tcx.sess.opts.debugging_opts.query_dep_graph;
-
         // Find the set of "start nodes". These are nodes that we will
         // possibly query later.
         let is_output = |node: &DepNode<DefId>| -> bool {
             match *node {
                 DepNode::WorkProduct(_) => true,
-                DepNode::MetaData(ref def_id) => collect_for_metadata && def_id.is_local(),
-
+                DepNode::MetaData(ref def_id) => {
+                    // We do *not* create dep-nodes for the current crate's
+                    // metadata anymore, just for metadata that we import/read
+                    // from other crates.
+                    debug_assert!(!def_id.is_local());
+                    false
+                }
                 // if -Z query-dep-graph is passed, save more extended data
                 // to enable better unit testing
                 DepNode::TypeckTables(_) |
@@ -75,6 +77,22 @@ impl<'q> Predecessors<'q> {
                   .or_insert_with(|| hcx.hash(input).unwrap());
         }
 
+        if tcx.sess.opts.debugging_opts.query_dep_graph {
+            // Not all inputs might have been reachable from an output node,
+            // but we still want their hash for our unit tests.
+            let hir_nodes = query.graph.all_nodes().iter().filter_map(|node| {
+                match node.data {
+                    DepNode::Hir(_) => Some(&node.data),
+                    _ => None,
+                }
+            });
+
+            for node in hir_nodes {
+                hashes.entry(node)
+                      .or_insert_with(|| hcx.hash(node).unwrap());
+            }
+        }
+
         let bootstrap_outputs: Vec<&'q DepNode<DefId>> =
             (0 .. graph.len_nodes())
             .map(NodeIndex)
diff --git a/src/librustc_incremental/persist/save.rs b/src/librustc_incremental/persist/save.rs
index 1591503865e..1864009fbdf 100644
--- a/src/librustc_incremental/persist/save.rs
+++ b/src/librustc_incremental/persist/save.rs
@@ -12,13 +12,12 @@ use rustc::dep_graph::DepNode;
 use rustc::hir::def_id::DefId;
 use rustc::hir::svh::Svh;
 use rustc::ich::Fingerprint;
+use rustc::middle::cstore::EncodedMetadataHash;
 use rustc::session::Session;
 use rustc::ty::TyCtxt;
 use rustc_data_structures::fx::FxHashMap;
-use rustc_data_structures::graph::{NodeIndex, INCOMING};
 use rustc_serialize::Encodable as RustcEncodable;
 use rustc_serialize::opaque::Encoder;
-use std::hash::Hash;
 use std::io::{self, Cursor, Write};
 use std::fs::{self, File};
 use std::path::PathBuf;
@@ -32,10 +31,10 @@ use super::fs::*;
 use super::dirty_clean;
 use super::file_format;
 use super::work_product;
-use calculate_svh::IchHasher;
 
 pub fn save_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                 incremental_hashes_map: &IncrementalHashesMap,
+                                metadata_hashes: &[EncodedMetadataHash],
                                 svh: Svh) {
     debug!("save_dep_graph()");
     let _ignore = tcx.dep_graph.in_ignore();
@@ -56,16 +55,16 @@ pub fn save_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     let preds = Predecessors::new(&query, &mut hcx);
     let mut current_metadata_hashes = FxHashMap();
 
+    // IMPORTANT: We are saving the metadata hashes *before* the dep-graph,
+    //            since metadata-encoding might add new entries to the
+    //            DefIdDirectory (which is saved in the dep-graph file).
     if sess.opts.debugging_opts.incremental_cc ||
        sess.opts.debugging_opts.query_dep_graph {
-        // IMPORTANT: We are saving the metadata hashes *before* the dep-graph,
-        //            since metadata-encoding might add new entries to the
-        //            DefIdDirectory (which is saved in the dep-graph file).
         save_in(sess,
                 metadata_hash_export_path(sess),
                 |e| encode_metadata_hashes(tcx,
                                            svh,
-                                           &preds,
+                                           metadata_hashes,
                                            &mut builder,
                                            &mut current_metadata_hashes,
                                            e));
@@ -241,80 +240,16 @@ pub fn encode_dep_graph(preds: &Predecessors,
 
 pub fn encode_metadata_hashes(tcx: TyCtxt,
                               svh: Svh,
-                              preds: &Predecessors,
+                              metadata_hashes: &[EncodedMetadataHash],
                               builder: &mut DefIdDirectoryBuilder,
                               current_metadata_hashes: &mut FxHashMap<DefId, Fingerprint>,
                               encoder: &mut Encoder)
                               -> io::Result<()> {
-    // For each `MetaData(X)` node where `X` is local, accumulate a
-    // hash.  These are the metadata items we export. Downstream
-    // crates will want to see a hash that tells them whether we might
-    // have changed the metadata for a given item since they last
-    // compiled.
-    //
-    // (I initially wrote this with an iterator, but it seemed harder to read.)
     let mut serialized_hashes = SerializedMetadataHashes {
-        hashes: vec![],
+        hashes: metadata_hashes.to_vec(),
         index_map: FxHashMap()
     };
 
-    for (index, target) in preds.reduced_graph.all_nodes().iter().enumerate() {
-        let index = NodeIndex(index);
-        let def_id = match *target.data {
-            DepNode::MetaData(def_id) if def_id.is_local() => def_id,
-            _ => continue,
-        };
-
-        // To create the hash for each item `X`, we don't hash the raw
-        // bytes of the metadata (though in principle we
-        // could). Instead, we walk the predecessors of `MetaData(X)`
-        // from the dep-graph. This corresponds to all the inputs that
-        // were read to construct the metadata. To create the hash for
-        // the metadata, we hash (the hash of) all of those inputs.
-        debug!("save: computing metadata hash for {:?}", def_id);
-
-        // Create a vector containing a pair of (source-id, hash).
-        // The source-id is stored as a `DepNode<u64>`, where the u64
-        // is the det. hash of the def-path. This is convenient
-        // because we can sort this to get a stable ordering across
-        // compilations, even if the def-ids themselves have changed.
-        let mut hashes: Vec<(DepNode<u64>, Fingerprint)> =
-            preds.reduced_graph
-                 .depth_traverse(index, INCOMING)
-                 .map(|index| preds.reduced_graph.node_data(index))
-                 .filter(|dep_node| HashContext::is_hashable(dep_node))
-                 .map(|dep_node| {
-                     let hash_dep_node = dep_node.map_def(|&def_id| Some(tcx.def_path_hash(def_id)))
-                                                 .unwrap();
-                     let hash = preds.hashes[dep_node];
-                     (hash_dep_node, hash)
-                 })
-                 .collect();
-
-        hashes.sort();
-        let mut state = IchHasher::new();
-        hashes.hash(&mut state);
-        let hash = state.finish();
-
-        debug!("save: metadata hash for {:?} is {}", def_id, hash);
-
-        if tcx.sess.opts.debugging_opts.incremental_dump_hash {
-            println!("metadata hash for {:?} is {}", def_id, hash);
-            for pred_index in preds.reduced_graph.depth_traverse(index, INCOMING) {
-                let dep_node = preds.reduced_graph.node_data(pred_index);
-                if HashContext::is_hashable(&dep_node) {
-                    println!("metadata hash for {:?} depends on {:?} with hash {}",
-                             def_id, dep_node, preds.hashes[dep_node]);
-                }
-            }
-        }
-
-        serialized_hashes.hashes.push(SerializedMetadataHash {
-            def_index: def_id.index,
-            hash: hash,
-        });
-    }
-
     if tcx.sess.opts.debugging_opts.query_dep_graph {
         for serialized_hash in &serialized_hashes.hashes {
             let def_id = DefId::local(serialized_hash.def_index);
diff --git a/src/librustc_metadata/astencode.rs b/src/librustc_metadata/astencode.rs
index 459132eb9c6..d9008ce555c 100644
--- a/src/librustc_metadata/astencode.rs
+++ b/src/librustc_metadata/astencode.rs
@@ -10,14 +10,12 @@
 
 use rustc::hir::intravisit::{Visitor, NestedVisitorMap};
 
-use encoder::EncodeContext;
+use index_builder::EntryBuilder;
 use schema::*;
 
 use rustc::hir;
 use rustc::ty;
 
-use rustc_serialize::Encodable;
-
 #[derive(RustcEncodable, RustcDecodable)]
 pub struct Ast<'tcx> {
     pub body: Lazy<hir::Body>,
@@ -26,7 +24,14 @@ pub struct Ast<'tcx> {
     pub rvalue_promotable_to_static: bool,
 }
 
-impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
+impl_stable_hash_for!(struct Ast<'tcx> {
+    body,
+    tables,
+    nested_bodies,
+    rvalue_promotable_to_static
+});
+
+impl<'a, 'b, 'tcx> EntryBuilder<'a, 'b, 'tcx> {
     pub fn encode_body(&mut self, body_id: hir::BodyId) -> Lazy<Ast<'tcx>> {
         let body = self.tcx.hir.body(body_id);
         let lazy_body = self.lazy(body);
@@ -34,15 +39,12 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
         let tables = self.tcx.body_tables(body_id);
         let lazy_tables = self.lazy(tables);
 
-        let nested_pos = self.position();
-        let nested_count = {
-            let mut visitor = NestedBodyEncodingVisitor {
-                ecx: self,
-                count: 0,
-            };
-            visitor.visit_body(body);
-            visitor.count
+        let mut visitor = NestedBodyCollector {
+            tcx: self.tcx,
+            bodies_found: Vec::new(),
         };
+        visitor.visit_body(body);
+        let lazy_nested_bodies = self.lazy_seq_ref_from_slice(&visitor.bodies_found);
 
         let rvalue_promotable_to_static =
             self.tcx.rvalue_promotable_to_static.borrow()[&body.value.id];
@@ -50,27 +52,25 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
         self.lazy(&Ast {
             body: lazy_body,
             tables: lazy_tables,
-            nested_bodies: LazySeq::with_position_and_length(nested_pos, nested_count),
+            nested_bodies: lazy_nested_bodies,
             rvalue_promotable_to_static: rvalue_promotable_to_static
         })
     }
 }
 
-struct NestedBodyEncodingVisitor<'a, 'b: 'a, 'tcx: 'b> {
-    ecx: &'a mut EncodeContext<'b, 'tcx>,
-    count: usize,
+struct NestedBodyCollector<'a, 'tcx: 'a> {
+    tcx: ty::TyCtxt<'a, 'tcx, 'tcx>,
+    bodies_found: Vec<&'tcx hir::Body>,
 }
 
-impl<'a, 'b, 'tcx> Visitor<'tcx> for NestedBodyEncodingVisitor<'a, 'b, 'tcx> {
+impl<'a, 'tcx: 'a> Visitor<'tcx> for NestedBodyCollector<'a, 'tcx> {
     fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
         NestedVisitorMap::None
     }
 
     fn visit_nested_body(&mut self, body: hir::BodyId) {
-        let body = self.ecx.tcx.hir.body(body);
-        body.encode(self.ecx).unwrap();
-        self.count += 1;
-
+        let body = self.tcx.hir.body(body);
+        self.bodies_found.push(body);
         self.visit_body(body);
     }
 }
diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs
index 37984e4c371..3239dfb937b 100644
--- a/src/librustc_metadata/cstore_impl.rs
+++ b/src/librustc_metadata/cstore_impl.rs
@@ -14,8 +14,9 @@ use locator;
 use schema;
 
 use rustc::dep_graph::DepTrackingMapConfig;
-use rustc::middle::cstore::{CrateStore, CrateSource, LibSource, DepKind, ExternCrate};
-use rustc::middle::cstore::{NativeLibrary, LinkMeta, LinkagePreference, LoadedMacro};
+use rustc::middle::cstore::{CrateStore, CrateSource, LibSource, DepKind,
+                            ExternCrate, NativeLibrary, LinkMeta,
+                            LinkagePreference, LoadedMacro, EncodedMetadata};
 use rustc::hir::def::{self, Def};
 use rustc::middle::lang_items;
 use rustc::session::Session;
@@ -498,7 +499,8 @@ impl CrateStore for cstore::CStore {
     fn encode_metadata<'a, 'tcx>(&self,
                                  tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                  link_meta: &LinkMeta,
-                                 reachable: &NodeSet) -> Vec<u8>
+                                 reachable: &NodeSet)
+                                 -> EncodedMetadata
     {
         encoder::encode_metadata(tcx, self, link_meta, reachable)
     }
diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs
index 38d774992a5..ffe68094c6a 100644
--- a/src/librustc_metadata/encoder.rs
+++ b/src/librustc_metadata/encoder.rs
@@ -12,7 +12,8 @@ use cstore;
 use index::Index;
 use schema::*;
 
-use rustc::middle::cstore::{LinkMeta, LinkagePreference, NativeLibrary};
+use rustc::middle::cstore::{LinkMeta, LinkagePreference, NativeLibrary,
+                            EncodedMetadata, EncodedMetadataHash};
 use rustc::hir::def_id::{CrateNum, CRATE_DEF_INDEX, DefIndex, DefId};
 use rustc::hir::map::definitions::DefPathTable;
 use rustc::middle::dependency_format::Linkage;
@@ -42,7 +43,7 @@ use rustc::hir::itemlikevisit::ItemLikeVisitor;
 use rustc::hir::intravisit::{Visitor, NestedVisitorMap};
 use rustc::hir::intravisit;
 
-use super::index_builder::{FromId, IndexBuilder, Untracked};
+use super::index_builder::{FromId, IndexBuilder, Untracked, EntryBuilder};
 
 pub struct EncodeContext<'a, 'tcx: 'a> {
     opaque: opaque::Encoder<'a>,
@@ -54,6 +55,8 @@ pub struct EncodeContext<'a, 'tcx: 'a> {
     lazy_state: LazyState,
     type_shorthands: FxHashMap<Ty<'tcx>, usize>,
     predicate_shorthands: FxHashMap<ty::Predicate<'tcx>, usize>,
+
+    pub metadata_hashes: Vec<EncodedMetadataHash>,
 }
 
 macro_rules! encoder_methods {
@@ -172,7 +175,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
         })
     }
 
-    fn lazy_seq<I, T>(&mut self, iter: I) -> LazySeq<T>
+    pub fn lazy_seq<I, T>(&mut self, iter: I) -> LazySeq<T>
         where I: IntoIterator<Item = T>,
               T: Encodable
     {
@@ -184,7 +187,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
         })
     }
 
-    fn lazy_seq_ref<'b, I, T>(&mut self, iter: I) -> LazySeq<T>
+    pub fn lazy_seq_ref<'b, I, T>(&mut self, iter: I) -> LazySeq<T>
         where I: IntoIterator<Item = &'b T>,
               T: 'b + Encodable
     {
@@ -233,15 +236,20 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
 
         Ok(())
     }
+}
 
+impl<'a, 'b: 'a, 'tcx: 'b> EntryBuilder<'a, 'b, 'tcx> {
     fn encode_item_variances(&mut self, def_id: DefId) -> LazySeq<ty::Variance> {
+        debug!("EntryBuilder::encode_item_variances({:?})", def_id);
         let tcx = self.tcx;
-        self.lazy_seq(tcx.item_variances(def_id).iter().cloned())
+        self.lazy_seq_from_slice(&tcx.item_variances(def_id))
     }
 
     fn encode_item_type(&mut self, def_id: DefId) -> Lazy<Ty<'tcx>> {
         let tcx = self.tcx;
-        self.lazy(&tcx.item_type(def_id))
+        let ty = tcx.item_type(def_id);
+        debug!("EntryBuilder::encode_item_type({:?}) => {:?}", def_id, ty);
+        self.lazy(&ty)
     }
 
     /// Encode data for the given variant of the given ADT. The
@@ -256,6 +264,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
         let def = tcx.lookup_adt_def(enum_did);
         let variant = &def.variants[index];
         let def_id = variant.did;
+        debug!("EntryBuilder::encode_enum_variant_info({:?})", def_id);
 
         let data = VariantData {
             ctor_kind: variant.ctor_kind,
@@ -302,10 +311,13 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
                            -> Entry<'tcx> {
         let tcx = self.tcx;
         let def_id = tcx.hir.local_def_id(id);
+        debug!("EntryBuilder::encode_info_for_mod({:?})", def_id);
 
         let data = ModData {
             reexports: match tcx.export_map.get(&id) {
-                Some(exports) if *vis == hir::Public => self.lazy_seq_ref(exports),
+                Some(exports) if *vis == hir::Public => {
+                    self.lazy_seq_from_slice(exports.as_slice())
+                }
                 _ => LazySeq::empty(),
             },
         };
@@ -339,14 +351,14 @@ impl<'a, 'b, 'tcx> IndexBuilder<'a, 'b, 'tcx> {
         for (variant_index, variant) in def.variants.iter().enumerate() {
             for (field_index, field) in variant.fields.iter().enumerate() {
                 self.record(field.did,
-                            EncodeContext::encode_field,
+                            EntryBuilder::encode_field,
                             (adt_def_id, Untracked((variant_index, field_index))));
             }
         }
     }
 }
 
-impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
+impl<'a, 'b: 'a, 'tcx: 'b> EntryBuilder<'a, 'b, 'tcx> {
     /// Encode data for the given field of the given variant of the
     /// given ADT. The indices of the variant/field are untracked:
     /// this is ok because we will have to lookup the adt-def by its
@@ -363,6 +375,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
         let field = &variant.fields[field_index];
 
         let def_id = field.did;
+        debug!("EntryBuilder::encode_field({:?})", def_id);
+
         let variant_id = tcx.hir.as_local_node_id(variant.did).unwrap();
         let variant_data = tcx.hir.expect_variant_data(variant_id);
 
@@ -387,6 +401,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
     }
 
     fn encode_struct_ctor(&mut self, (adt_def_id, def_id): (DefId, DefId)) -> Entry<'tcx> {
+        debug!("EntryBuilder::encode_struct_ctor({:?})", def_id);
         let tcx = self.tcx;
         let variant = tcx.lookup_adt_def(adt_def_id).struct_variant();
 
@@ -429,16 +444,19 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
     }
 
     fn encode_generics(&mut self, def_id: DefId) -> Lazy<ty::Generics> {
+        debug!("EntryBuilder::encode_generics({:?})", def_id);
         let tcx = self.tcx;
         self.lazy(tcx.item_generics(def_id))
     }
 
     fn encode_predicates(&mut self, def_id: DefId) -> Lazy<ty::GenericPredicates<'tcx>> {
+        debug!("EntryBuilder::encode_predicates({:?})", def_id);
         let tcx = self.tcx;
         self.lazy(&tcx.item_predicates(def_id))
     }
 
     fn encode_info_for_trait_item(&mut self, def_id: DefId) -> Entry<'tcx> {
+        debug!("EntryBuilder::encode_info_for_trait_item({:?})", def_id);
         let tcx = self.tcx;
 
         let node_id = tcx.hir.as_local_node_id(def_id).unwrap();
@@ -521,6 +539,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
     }
 
     fn encode_info_for_impl_item(&mut self, def_id: DefId) -> Entry<'tcx> {
+        debug!("EntryBuilder::encode_info_for_impl_item({:?})", def_id);
         let node_id = self.tcx.hir.as_local_node_id(def_id).unwrap();
         let ast_item = self.tcx.hir.expect_impl_item(node_id);
         let impl_item = self.tcx.associated_item(def_id);
@@ -607,11 +626,13 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
     }
 
     fn encode_mir(&mut self, def_id: DefId) -> Option<Lazy<mir::Mir<'tcx>>> {
+        debug!("EntryBuilder::encode_mir({:?})", def_id);
         self.tcx.maps.mir.borrow().get(&def_id).map(|mir| self.lazy(&*mir.borrow()))
     }
 
     // Encodes the inherent implementations of a structure, enumeration, or trait.
     fn encode_inherent_implementations(&mut self, def_id: DefId) -> LazySeq<DefIndex> {
+        debug!("EntryBuilder::encode_inherent_implementations({:?})", def_id);
         match self.tcx.maps.inherent_impls.borrow().get(&def_id) {
             None => LazySeq::empty(),
             Some(implementations) => {
@@ -624,18 +645,19 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
     }
 
     fn encode_stability(&mut self, def_id: DefId) -> Option<Lazy<attr::Stability>> {
+        debug!("EntryBuilder::encode_stability({:?})", def_id);
         self.tcx.lookup_stability(def_id).map(|stab| self.lazy(stab))
     }
 
     fn encode_deprecation(&mut self, def_id: DefId) -> Option<Lazy<attr::Deprecation>> {
+        debug!("EntryBuilder::encode_deprecation({:?})", def_id);
         self.tcx.lookup_deprecation(def_id).map(|depr| self.lazy(&depr))
     }
 
     fn encode_info_for_item(&mut self, (def_id, item): (DefId, &'tcx hir::Item)) -> Entry<'tcx> {
         let tcx = self.tcx;
 
-        debug!("encoding info for item at {}",
-               tcx.sess.codemap().span_to_string(item.span));
+        debug!("EntryBuilder::encode_info_for_item({:?})", def_id);
 
         let kind = match item.node {
             hir::ItemStatic(_, hir::MutMutable, _) => EntryKind::MutStatic,
@@ -907,7 +929,7 @@ impl<'a, 'b, 'tcx> IndexBuilder<'a, 'b, 'tcx> {
                 let def = self.tcx.lookup_adt_def(def_id);
                 for (i, variant) in def.variants.iter().enumerate() {
                     self.record(variant.did,
-                                EncodeContext::encode_enum_variant_info,
+                                EntryBuilder::encode_enum_variant_info,
                                 (def_id, Untracked(i)));
                 }
             }
@@ -918,7 +940,7 @@ impl<'a, 'b, 'tcx> IndexBuilder<'a, 'b, 'tcx> {
                 if !struct_def.is_struct() {
                     let ctor_def_id = self.tcx.hir.local_def_id(struct_def.id());
                     self.record(ctor_def_id,
-                                EncodeContext::encode_struct_ctor,
+                                EntryBuilder::encode_struct_ctor,
                                 (def_id, ctor_def_id));
                 }
             }
@@ -928,14 +950,14 @@ impl<'a, 'b, 'tcx> IndexBuilder<'a, 'b, 'tcx> {
             hir::ItemImpl(..) => {
                 for &trait_item_def_id in self.tcx.associated_item_def_ids(def_id).iter() {
                     self.record(trait_item_def_id,
-                                EncodeContext::encode_info_for_impl_item,
+                                EntryBuilder::encode_info_for_impl_item,
                                 trait_item_def_id);
                 }
             }
             hir::ItemTrait(..) => {
                 for &item_def_id in self.tcx.associated_item_def_ids(def_id).iter() {
                     self.record(item_def_id,
-                                EncodeContext::encode_info_for_trait_item,
+                                EntryBuilder::encode_info_for_trait_item,
                                 item_def_id);
                 }
             }
@@ -943,13 +965,13 @@ impl<'a, 'b, 'tcx> IndexBuilder<'a, 'b, 'tcx> {
     }
 }
 
-impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
+impl<'a, 'b: 'a, 'tcx: 'b> EntryBuilder<'a, 'b, 'tcx> {
     fn encode_info_for_foreign_item(&mut self,
                                     (def_id, nitem): (DefId, &hir::ForeignItem))
                                     -> Entry<'tcx> {
         let tcx = self.tcx;
 
-        debug!("writing foreign item {}", tcx.node_path_str(nitem.id));
+        debug!("EntryBuilder::encode_info_for_foreign_item({:?})", def_id);
 
         let kind = match nitem.node {
             hir::ForeignItemFn(_, ref names, _) => {
@@ -1002,7 +1024,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for EncodeVisitor<'a, 'b, 'tcx> {
         match item.node {
             hir::ItemExternCrate(_) |
             hir::ItemUse(..) => (), // ignore these
-            _ => self.index.record(def_id, EncodeContext::encode_info_for_item, (def_id, item)),
+            _ => self.index.record(def_id, EntryBuilder::encode_info_for_item, (def_id, item)),
         }
         self.index.encode_addl_info_for_item(item);
     }
@@ -1010,7 +1032,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for EncodeVisitor<'a, 'b, 'tcx> {
         intravisit::walk_foreign_item(self, ni);
         let def_id = self.index.tcx.hir.local_def_id(ni.id);
         self.index.record(def_id,
-                          EncodeContext::encode_info_for_foreign_item,
+                          EntryBuilder::encode_info_for_foreign_item,
                           (def_id, ni));
     }
     fn visit_generics(&mut self, generics: &'tcx hir::Generics) {
@@ -1023,7 +1045,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for EncodeVisitor<'a, 'b, 'tcx> {
     }
     fn visit_macro_def(&mut self, macro_def: &'tcx hir::MacroDef) {
         let def_id = self.index.tcx.hir.local_def_id(macro_def.id);
-        self.index.record(def_id, EncodeContext::encode_info_for_macro_def, macro_def);
+        self.index.record(def_id, EntryBuilder::encode_info_for_macro_def, macro_def);
     }
 }
 
@@ -1032,14 +1054,14 @@ impl<'a, 'b, 'tcx> IndexBuilder<'a, 'b, 'tcx> {
         for ty_param in &generics.ty_params {
             let def_id = self.tcx.hir.local_def_id(ty_param.id);
             let has_default = Untracked(ty_param.default.is_some());
-            self.record(def_id, EncodeContext::encode_info_for_ty_param, (def_id, has_default));
+            self.record(def_id, EntryBuilder::encode_info_for_ty_param, (def_id, has_default));
         }
     }
 
     fn encode_info_for_ty(&mut self, ty: &hir::Ty) {
         if let hir::TyImplTrait(_) = ty.node {
             let def_id = self.tcx.hir.local_def_id(ty.id);
-            self.record(def_id, EncodeContext::encode_info_for_anon_ty, def_id);
+            self.record(def_id, EntryBuilder::encode_info_for_anon_ty, def_id);
         }
     }
 
@@ -1047,17 +1069,18 @@ impl<'a, 'b, 'tcx> IndexBuilder<'a, 'b, 'tcx> {
         match expr.node {
             hir::ExprClosure(..) => {
                 let def_id = self.tcx.hir.local_def_id(expr.id);
-                self.record(def_id, EncodeContext::encode_info_for_closure, def_id);
+                self.record(def_id, EntryBuilder::encode_info_for_closure, def_id);
             }
             _ => {}
         }
     }
 }
 
-impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
+impl<'a, 'b: 'a, 'tcx: 'b> EntryBuilder<'a, 'b, 'tcx> {
     fn encode_info_for_ty_param(&mut self,
                                 (def_id, Untracked(has_default)): (DefId, Untracked<bool>))
                                 -> Entry<'tcx> {
+        debug!("EntryBuilder::encode_info_for_ty_param({:?})", def_id);
         let tcx = self.tcx;
         Entry {
             kind: EntryKind::Type,
@@ -1084,6 +1107,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
     }
 
     fn encode_info_for_anon_ty(&mut self, def_id: DefId) -> Entry<'tcx> {
+        debug!("EntryBuilder::encode_info_for_anon_ty({:?})", def_id);
         let tcx = self.tcx;
         Entry {
             kind: EntryKind::Type,
@@ -1106,6 +1130,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
     }
 
     fn encode_info_for_closure(&mut self, def_id: DefId) -> Entry<'tcx> {
+        debug!("EntryBuilder::encode_info_for_closure({:?})", def_id);
         let tcx = self.tcx;
 
         let data = ClosureData {
@@ -1133,11 +1158,20 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
         }
     }
 
+    fn encode_attributes(&mut self, attrs: &[ast::Attribute]) -> LazySeq<ast::Attribute> {
+        // NOTE: This must use lazy_seq_from_slice(), not lazy_seq() because
+        //       we really on the HashStable specialization for [Attribute]
+        //       to properly filter things out.
+        self.lazy_seq_from_slice(attrs)
+    }
+}
+
+impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
     fn encode_info_for_items(&mut self) -> Index {
         let krate = self.tcx.hir.krate();
         let mut index = IndexBuilder::new(self);
         index.record(DefId::local(CRATE_DEF_INDEX),
-                     EncodeContext::encode_info_for_mod,
+                     EntryBuilder::encode_info_for_mod,
                      FromId(CRATE_NODE_ID, (&krate.module, &krate.attrs, &hir::Public)));
         let mut visitor = EncodeVisitor { index: index };
         krate.visit_all_item_likes(&mut visitor.as_deep_visitor());
@@ -1147,10 +1181,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
         visitor.index.into_items()
     }
 
-    fn encode_attributes(&mut self, attrs: &[ast::Attribute]) -> LazySeq<ast::Attribute> {
-        self.lazy_seq_ref(attrs)
-    }
-
     fn encode_crate_deps(&mut self) -> LazySeq<CrateDep> {
         fn get_ordered_deps(cstore: &cstore::CStore) -> Vec<(CrateNum, Rc<cstore::CrateMetadata>)> {
             // Pull the cnums and name,vers,hash out of cstore
@@ -1298,7 +1328,9 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
             None => LazySeq::empty(),
         }
     }
+}
 
+impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
     fn encode_crate_root(&mut self) -> Lazy<CrateRoot> {
         let mut i = self.position();
         let crate_deps = self.encode_crate_deps();
@@ -1431,14 +1463,15 @@ pub fn encode_metadata<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                  cstore: &cstore::CStore,
                                  link_meta: &LinkMeta,
                                  exported_symbols: &NodeSet)
-                                 -> Vec<u8> {
+                                 -> EncodedMetadata
+{
     let mut cursor = Cursor::new(vec![]);
     cursor.write_all(METADATA_HEADER).unwrap();
 
     // Will be filed with the root position after encoding everything.
     cursor.write_all(&[0, 0, 0, 0]).unwrap();
 
-    let root = {
+    let (root, metadata_hashes) = {
         let mut ecx = EncodeContext {
             opaque: opaque::Encoder::new(&mut cursor),
             tcx: tcx,
@@ -1448,6 +1481,7 @@ pub fn encode_metadata<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
             lazy_state: LazyState::NoNode,
             type_shorthands: Default::default(),
             predicate_shorthands: Default::default(),
+            metadata_hashes: Vec::new(),
         };
 
         // Encode the rustc version string in a predictable location.
@@ -1455,7 +1489,8 @@ pub fn encode_metadata<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 
         // Encode all the entries and extra information in the crate,
         // culminating in the `CrateRoot` which points to all of it.
-        ecx.encode_crate_root()
+        let root = ecx.encode_crate_root();
+        (root, ecx.metadata_hashes)
     };
     let mut result = cursor.into_inner();
 
@@ -1467,7 +1502,10 @@ pub fn encode_metadata<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     result[header + 2] = (pos >> 8) as u8;
     result[header + 3] = (pos >> 0) as u8;
 
-    result
+    EncodedMetadata {
+        raw_data: result,
+        hashes: metadata_hashes,
+    }
 }
 
 pub fn get_repr_options<'a, 'tcx, 'gcx>(tcx: &TyCtxt<'a, 'tcx, 'gcx>, did: DefId) -> ReprOptions {
diff --git a/src/librustc_metadata/index_builder.rs b/src/librustc_metadata/index_builder.rs
index a811f72bc95..01f948866b8 100644
--- a/src/librustc_metadata/index_builder.rs
+++ b/src/librustc_metadata/index_builder.rs
@@ -59,14 +59,19 @@ use encoder::EncodeContext;
 use index::Index;
 use schema::*;
 
-use rustc::dep_graph::DepNode;
 use rustc::hir;
 use rustc::hir::def_id::DefId;
+use rustc::ich::{StableHashingContext, Fingerprint};
+use rustc::middle::cstore::EncodedMetadataHash;
 use rustc::ty::TyCtxt;
 use syntax::ast;
 
 use std::ops::{Deref, DerefMut};
 
+use rustc_data_structures::accumulate_vec::AccumulateVec;
+use rustc_data_structures::stable_hasher::{StableHasher, HashStable};
+use rustc_serialize::Encodable;
+
 /// Builder that can encode new items, adding them into the index.
 /// Item encoding cannot be nested.
 pub struct IndexBuilder<'a, 'b: 'a, 'tcx: 'b> {
@@ -112,16 +117,45 @@ impl<'a, 'b, 'tcx> IndexBuilder<'a, 'b, 'tcx> {
     /// holds, and that it is therefore not gaining "secret" access to
     /// bits of HIR or other state that would not be trackd by the
     /// content system.
-    pub fn record<DATA>(&mut self,
-                        id: DefId,
-                        op: fn(&mut EncodeContext<'b, 'tcx>, DATA) -> Entry<'tcx>,
-                        data: DATA)
+    pub fn record<'x, DATA>(&'x mut self,
+                            id: DefId,
+                            op: fn(&mut EntryBuilder<'x, 'b, 'tcx>, DATA) -> Entry<'tcx>,
+                            data: DATA)
         where DATA: DepGraphRead
     {
-        let _task = self.tcx.dep_graph.in_task(DepNode::MetaData(id));
-        data.read(self.tcx);
-        let entry = op(&mut self.ecx, data);
-        self.items.record(id, self.ecx.lazy(&entry));
+        assert!(id.is_local());
+        let tcx: TyCtxt<'b, 'tcx, 'tcx> = self.ecx.tcx;
+
+        // We don't track this since we are explicitly computing the incr. comp.
+        // hashes anyway. In theory we could do some tracking here and use it to
+        // avoid rehashing things (and instead cache the hashes) but it's
+        // unclear whether that would be a win since hashing is cheap enough.
+        let _task = tcx.dep_graph.in_ignore();
+
+        let compute_ich = (tcx.sess.opts.debugging_opts.query_dep_graph ||
+                           tcx.sess.opts.debugging_opts.incremental_cc) &&
+                           tcx.sess.opts.build_dep_graph();
+
+        let ecx: &'x mut EncodeContext<'b, 'tcx> = &mut *self.ecx;
+        let mut entry_builder = EntryBuilder {
+            tcx: tcx,
+            ecx: ecx,
+            hcx: if compute_ich {
+                Some((StableHashingContext::new(tcx), StableHasher::new()))
+            } else {
+                None
+            }
+        };
+
+        let entry = op(&mut entry_builder, data);
+
+        if let Some((ref mut hcx, ref mut hasher)) = entry_builder.hcx {
+            entry.hash_stable(hcx, hasher);
+        }
+
+        let entry = entry_builder.ecx.lazy(&entry);
+        entry_builder.finish(id);
+        self.items.record(id, entry);
     }
 
     pub fn into_items(self) -> Index {
@@ -223,3 +257,91 @@ impl<T> DepGraphRead for FromId<T> {
         tcx.hir.read(self.0);
     }
 }
+
+pub struct EntryBuilder<'a, 'b: 'a, 'tcx: 'b> {
+    pub tcx: TyCtxt<'b, 'tcx, 'tcx>,
+    ecx: &'a mut EncodeContext<'b, 'tcx>,
+    hcx: Option<(StableHashingContext<'b, 'tcx>, StableHasher<Fingerprint>)>,
+}
+
+impl<'a, 'b: 'a, 'tcx: 'b> EntryBuilder<'a, 'b, 'tcx> {
+
+    pub fn finish(self, def_id: DefId) {
+        if let Some((_, hasher)) = self.hcx {
+            let hash = hasher.finish();
+            self.ecx.metadata_hashes.push(EncodedMetadataHash {
+                def_index: def_id.index,
+                hash: hash,
+            });
+        }
+    }
+
+    pub fn lazy<T>(&mut self, value: &T) -> Lazy<T>
+        where T: Encodable + HashStable<StableHashingContext<'b, 'tcx>>
+    {
+        if let Some((ref mut hcx, ref mut hasher)) = self.hcx {
+            value.hash_stable(hcx, hasher);
+            debug!("metadata-hash: {:?}", hasher);
+        }
+        self.ecx.lazy(value)
+    }
+
+    pub fn lazy_seq<I, T>(&mut self, iter: I) -> LazySeq<T>
+        where I: IntoIterator<Item = T>,
+              T: Encodable + HashStable<StableHashingContext<'b, 'tcx>>
+    {
+        if let Some((ref mut hcx, ref mut hasher)) = self.hcx {
+            let iter = iter.into_iter();
+            let (lower_bound, upper_bound) = iter.size_hint();
+
+            if upper_bound == Some(lower_bound) {
+                lower_bound.hash_stable(hcx, hasher);
+                let mut num_items_hashed = 0;
+                let ret = self.ecx.lazy_seq(iter.inspect(|item| {
+                    item.hash_stable(hcx, hasher);
+                    num_items_hashed += 1;
+                }));
+
+                // Sometimes items in a sequence are filtered out without being
+                // hashed (e.g. for &[ast::Attribute]) and this code path cannot
+                // handle that correctly, so we want to make sure we didn't hit
+                // it by accident.
+                if lower_bound != num_items_hashed {
+                    bug!("Hashed a different number of items ({}) than expected ({})",
+                         num_items_hashed,
+                         lower_bound);
+                }
+                debug!("metadata-hash: {:?}", hasher);
+                ret
+            } else {
+                // Collect into a vec so we know the length of the sequence
+                let items: AccumulateVec<[T; 32]> = iter.collect();
+                items.hash_stable(hcx, hasher);
+                debug!("metadata-hash: {:?}", hasher);
+                self.ecx.lazy_seq(items)
+            }
+        } else {
+            self.ecx.lazy_seq(iter)
+        }
+    }
+
+    pub fn lazy_seq_from_slice<T>(&mut self, slice: &[T]) -> LazySeq<T>
+        where T: Encodable + HashStable<StableHashingContext<'b, 'tcx>>
+    {
+        if let Some((ref mut hcx, ref mut hasher)) = self.hcx {
+            slice.hash_stable(hcx, hasher);
+            debug!("metadata-hash: {:?}", hasher);
+        }
+        self.ecx.lazy_seq_ref(slice.iter())
+    }
+
+    pub fn lazy_seq_ref_from_slice<T>(&mut self, slice: &[&T]) -> LazySeq<T>
+        where T: Encodable + HashStable<StableHashingContext<'b, 'tcx>>
+    {
+        if let Some((ref mut hcx, ref mut hasher)) = self.hcx {
+            slice.hash_stable(hcx, hasher);
+            debug!("metadata-hash: {:?}", hasher);
+        }
+        self.ecx.lazy_seq_ref(slice.iter().map(|x| *x))
+    }
+}
diff --git a/src/librustc_metadata/lib.rs b/src/librustc_metadata/lib.rs
index 2fbdb8c0de6..b9e142ac650 100644
--- a/src/librustc_metadata/lib.rs
+++ b/src/librustc_metadata/lib.rs
@@ -27,6 +27,7 @@
 #![feature(rustc_private)]
 #![feature(specialization)]
 #![feature(staged_api)]
+#![feature(discriminant_value)]
 
 #[macro_use]
 extern crate log;
diff --git a/src/librustc_metadata/schema.rs b/src/librustc_metadata/schema.rs
index abb482a50eb..53d6a9ec10d 100644
--- a/src/librustc_metadata/schema.rs
+++ b/src/librustc_metadata/schema.rs
@@ -14,6 +14,7 @@ use index;
 use rustc::hir;
 use rustc::hir::def::{self, CtorKind};
 use rustc::hir::def_id::{DefIndex, DefId};
+use rustc::ich::StableHashingContext;
 use rustc::middle::const_val::ConstVal;
 use rustc::middle::cstore::{DepKind, LinkagePreference, NativeLibrary};
 use rustc::middle::lang_items;
@@ -27,6 +28,10 @@ use syntax::symbol::Symbol;
 use syntax_pos::{self, Span};
 
 use std::marker::PhantomData;
+use std::mem;
+
+use rustc_data_structures::stable_hasher::{StableHasher, HashStable,
+                                           StableHasherResult};
 
 pub fn rustc_version() -> String {
     format!("rustc {}",
@@ -100,6 +105,15 @@ impl<T> Clone for Lazy<T> {
 impl<T> serialize::UseSpecializedEncodable for Lazy<T> {}
 impl<T> serialize::UseSpecializedDecodable for Lazy<T> {}
 
+impl<CTX, T> HashStable<CTX> for Lazy<T> {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          _: &mut CTX,
+                                          _: &mut StableHasher<W>) {
+        // There's nothing to do. Whatever got encoded within this Lazy<>
+        // wrapper has already been hashed.
+    }
+}
+
 /// A sequence of type T referred to by its absolute position
 /// in the metadata and length, and which can be decoded lazily.
 /// The sequence is a single node for the purposes of `Lazy`.
@@ -148,6 +162,15 @@ impl<T> Clone for LazySeq<T> {
 impl<T> serialize::UseSpecializedEncodable for LazySeq<T> {}
 impl<T> serialize::UseSpecializedDecodable for LazySeq<T> {}
 
+impl<CTX, T> HashStable<CTX> for LazySeq<T> {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          _: &mut CTX,
+                                          _: &mut StableHasher<W>) {
+        // There's nothing to do. Whatever got encoded within this Lazy<>
+        // wrapper has already been hashed.
+    }
+}
+
 /// Encoding / decoding state for `Lazy` and `LazySeq`.
 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
 pub enum LazyState {
@@ -219,6 +242,23 @@ pub struct Entry<'tcx> {
     pub mir: Option<Lazy<mir::Mir<'tcx>>>,
 }
 
+impl_stable_hash_for!(struct Entry<'tcx> {
+    kind,
+    visibility,
+    span,
+    attributes,
+    children,
+    stability,
+    deprecation,
+    ty,
+    inherent_impls,
+    variances,
+    generics,
+    predicates,
+    ast,
+    mir
+});
+
 #[derive(Copy, Clone, RustcEncodable, RustcDecodable)]
 pub enum EntryKind<'tcx> {
     Const(u8),
@@ -246,22 +286,91 @@ pub enum EntryKind<'tcx> {
     AssociatedConst(AssociatedContainer, u8),
 }
 
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for EntryKind<'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 {
+            EntryKind::ImmStatic        |
+            EntryKind::MutStatic        |
+            EntryKind::ForeignImmStatic |
+            EntryKind::ForeignMutStatic |
+            EntryKind::ForeignMod       |
+            EntryKind::Field |
+            EntryKind::Type => {
+                // Nothing else to hash here.
+            }
+            EntryKind::Const(qualif) => {
+                qualif.hash_stable(hcx, hasher);
+            }
+            EntryKind::Enum(ref repr_options) => {
+                repr_options.hash_stable(hcx, hasher);
+            }
+            EntryKind::Variant(ref variant_data) => {
+                variant_data.hash_stable(hcx, hasher);
+            }
+            EntryKind::Struct(ref variant_data, ref repr_options) |
+            EntryKind::Union(ref variant_data, ref repr_options)  => {
+                variant_data.hash_stable(hcx, hasher);
+                repr_options.hash_stable(hcx, hasher);
+            }
+            EntryKind::Fn(ref fn_data) |
+            EntryKind::ForeignFn(ref fn_data) => {
+                fn_data.hash_stable(hcx, hasher);
+            }
+            EntryKind::Mod(ref mod_data) => {
+                mod_data.hash_stable(hcx, hasher);
+            }
+            EntryKind::MacroDef(ref macro_def) => {
+                macro_def.hash_stable(hcx, hasher);
+            }
+            EntryKind::Closure(closure_data) => {
+                closure_data.hash_stable(hcx, hasher);
+            }
+            EntryKind::Trait(ref trait_data) => {
+                trait_data.hash_stable(hcx, hasher);
+            }
+            EntryKind::DefaultImpl(ref impl_data) |
+            EntryKind::Impl(ref impl_data) => {
+                impl_data.hash_stable(hcx, hasher);
+            }
+            EntryKind::Method(ref method_data) => {
+                method_data.hash_stable(hcx, hasher);
+            }
+            EntryKind::AssociatedType(associated_container) => {
+                associated_container.hash_stable(hcx, hasher);
+            }
+            EntryKind::AssociatedConst(associated_container, qualif) => {
+                associated_container.hash_stable(hcx, hasher);
+                qualif.hash_stable(hcx, hasher);
+            }
+        }
+    }
+}
+
 #[derive(RustcEncodable, RustcDecodable)]
 pub struct ModData {
     pub reexports: LazySeq<def::Export>,
 }
 
+impl_stable_hash_for!(struct ModData { reexports });
+
 #[derive(RustcEncodable, RustcDecodable)]
 pub struct MacroDef {
     pub body: String,
 }
 
+impl_stable_hash_for!(struct MacroDef { body });
+
 #[derive(RustcEncodable, RustcDecodable)]
 pub struct FnData {
     pub constness: hir::Constness,
     pub arg_names: LazySeq<ast::Name>,
 }
 
+impl_stable_hash_for!(struct FnData { constness, arg_names });
+
 #[derive(RustcEncodable, RustcDecodable)]
 pub struct VariantData<'tcx> {
     pub ctor_kind: CtorKind,
@@ -273,6 +382,13 @@ pub struct VariantData<'tcx> {
     pub struct_ctor: Option<DefIndex>,
 }
 
+impl_stable_hash_for!(struct VariantData<'tcx> {
+    ctor_kind,
+    discr,
+    evaluated_discr,
+    struct_ctor
+});
+
 #[derive(RustcEncodable, RustcDecodable)]
 pub struct TraitData<'tcx> {
     pub unsafety: hir::Unsafety,
@@ -281,6 +397,13 @@ pub struct TraitData<'tcx> {
     pub super_predicates: Lazy<ty::GenericPredicates<'tcx>>,
 }
 
+impl_stable_hash_for!(struct TraitData<'tcx> {
+    unsafety,
+    paren_sugar,
+    has_default_impl,
+    super_predicates
+});
+
 #[derive(RustcEncodable, RustcDecodable)]
 pub struct ImplData<'tcx> {
     pub polarity: hir::ImplPolarity,
@@ -291,6 +414,14 @@ pub struct ImplData<'tcx> {
     pub trait_ref: Option<Lazy<ty::TraitRef<'tcx>>>,
 }
 
+impl_stable_hash_for!(struct ImplData<'tcx> {
+    polarity,
+    parent_impl,
+    coerce_unsized_info,
+    trait_ref
+});
+
+
 /// Describes whether the container of an associated item
 /// is a trait or an impl and whether, in a trait, it has
 /// a default, or an in impl, whether it's marked "default".
@@ -302,6 +433,13 @@ pub enum AssociatedContainer {
     ImplFinal,
 }
 
+impl_stable_hash_for!(enum ::schema::AssociatedContainer {
+    TraitRequired,
+    TraitWithDefault,
+    ImplDefault,
+    ImplFinal
+});
+
 impl AssociatedContainer {
     pub fn with_def_id(&self, def_id: DefId) -> ty::AssociatedItemContainer {
         match *self {
@@ -335,9 +473,11 @@ pub struct MethodData {
     pub container: AssociatedContainer,
     pub has_self: bool,
 }
+impl_stable_hash_for!(struct MethodData { fn_data, container, has_self });
 
 #[derive(RustcEncodable, RustcDecodable)]
 pub struct ClosureData<'tcx> {
     pub kind: ty::ClosureKind,
     pub ty: Lazy<ty::PolyFnSig<'tcx>>,
 }
+impl_stable_hash_for!(struct ClosureData<'tcx> { kind, ty });
diff --git a/src/librustc_trans/back/link.rs b/src/librustc_trans/back/link.rs
index 66380079a8b..0ffa7a79408 100644
--- a/src/librustc_trans/back/link.rs
+++ b/src/librustc_trans/back/link.rs
@@ -443,7 +443,10 @@ fn archive_config<'a>(sess: &'a Session,
 }
 
 fn emit_metadata<'a>(sess: &'a Session, trans: &CrateTranslation, out_filename: &Path) {
-    let result = fs::File::create(out_filename).and_then(|mut f| f.write_all(&trans.metadata));
+    let result = fs::File::create(out_filename).and_then(|mut f| {
+        f.write_all(&trans.metadata.raw_data)
+    });
+
     if let Err(e) = result {
         sess.fatal(&format!("failed to write {}: {}", out_filename.display(), e));
     }
diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs
index 574b345218b..f76e816bcf0 100644
--- a/src/librustc_trans/base.rs
+++ b/src/librustc_trans/base.rs
@@ -36,6 +36,7 @@ use llvm::{Linkage, ValueRef, Vector, get_param};
 use llvm;
 use rustc::hir::def_id::LOCAL_CRATE;
 use middle::lang_items::StartFnLangItem;
+use middle::cstore::EncodedMetadata;
 use rustc::ty::{self, Ty, TyCtxt};
 use rustc::dep_graph::{AssertDepGraphSafe, DepNode, WorkProduct};
 use rustc::hir::map as hir_map;
@@ -724,7 +725,8 @@ fn contains_null(s: &str) -> bool {
 }
 
 fn write_metadata(cx: &SharedCrateContext,
-                  exported_symbols: &NodeSet) -> Vec<u8> {
+                  exported_symbols: &NodeSet)
+                  -> EncodedMetadata {
     use flate;
 
     #[derive(PartialEq, Eq, PartialOrd, Ord)]
@@ -748,7 +750,10 @@ fn write_metadata(cx: &SharedCrateContext,
     }).max().unwrap();
 
     if kind == MetadataKind::None {
-        return Vec::new();
+        return EncodedMetadata {
+            raw_data: vec![],
+            hashes: vec![],
+        };
     }
 
     let cstore = &cx.tcx().sess.cstore;
@@ -761,7 +766,7 @@ fn write_metadata(cx: &SharedCrateContext,
 
     assert!(kind == MetadataKind::Compressed);
     let mut compressed = cstore.metadata_encoding_version().to_vec();
-    compressed.extend_from_slice(&flate::deflate_bytes(&metadata));
+    compressed.extend_from_slice(&flate::deflate_bytes(&metadata.raw_data));
 
     let llmeta = C_bytes_in_context(cx.metadata_llcx(), &compressed);
     let llconst = C_struct_in_context(cx.metadata_llcx(), &[llmeta], false);
diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs
index 5c3b17c8897..628d46f8e70 100644
--- a/src/librustc_trans/lib.rs
+++ b/src/librustc_trans/lib.rs
@@ -168,7 +168,7 @@ pub struct CrateTranslation {
     pub modules: Vec<ModuleTranslation>,
     pub metadata_module: ModuleTranslation,
     pub link: middle::cstore::LinkMeta,
-    pub metadata: Vec<u8>,
+    pub metadata: middle::cstore::EncodedMetadata,
     pub exported_symbols: back::symbol_export::ExportedSymbols,
     pub no_builtins: bool,
     pub windows_subsystem: Option<String>,
diff --git a/src/test/incremental/hashes/enum_defs.rs b/src/test/incremental/hashes/enum_defs.rs
index 048ccb529a2..37c6ef58f5e 100644
--- a/src/test/incremental/hashes/enum_defs.rs
+++ b/src/test/incremental/hashes/enum_defs.rs
@@ -38,8 +38,13 @@ enum EnumVisibility { A }
 #[cfg(not(cfail1))]
 #[rustc_dirty(label="Hir", cfg="cfail2")]
 #[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
-pub enum EnumVisibility { A }
+pub enum EnumVisibility {
+    #[rustc_metadata_dirty(cfg="cfail2")]
+    #[rustc_metadata_clean(cfg="cfail3")]
+    A
+}
 
 
 
@@ -56,7 +61,10 @@ enum EnumChangeNameCStyleVariant {
 #[rustc_metadata_dirty(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 enum EnumChangeNameCStyleVariant {
+    #[rustc_metadata_dirty(cfg="cfail2")]
+    #[rustc_metadata_clean(cfg="cfail3")]
     Variant1,
+    #[rustc_metadata_clean(cfg="cfail3")]
     Variant2Changed,
 }
 
@@ -259,10 +267,13 @@ enum EnumChangeFieldTypeTupleStyleVariant {
 #[cfg(not(cfail1))]
 #[rustc_dirty(label="Hir", cfg="cfail2")]
 #[rustc_clean(label="Hir", cfg="cfail3")]
-#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 enum EnumChangeFieldTypeTupleStyleVariant {
-    Variant1(u32, u64),
+    Variant1(u32,
+        #[rustc_metadata_dirty(cfg="cfail2")]
+        #[rustc_metadata_clean(cfg="cfail3")]
+        u64),
 }
 
 
@@ -277,11 +288,16 @@ enum EnumChangeFieldTypeStructStyleVariant {
 #[cfg(not(cfail1))]
 #[rustc_dirty(label="Hir", cfg="cfail2")]
 #[rustc_clean(label="Hir", cfg="cfail3")]
-#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 enum EnumChangeFieldTypeStructStyleVariant {
     Variant1,
-    Variant2 { a: u32, b: u64 },
+    Variant2 {
+        a: u32,
+        #[rustc_metadata_dirty(cfg="cfail2")]
+        #[rustc_metadata_clean(cfg="cfail3")]
+        b: u64
+    },
 }
 
 
@@ -312,10 +328,16 @@ enum EnumChangeOrderTupleStyleVariant {
 #[cfg(not(cfail1))]
 #[rustc_dirty(label="Hir", cfg="cfail2")]
 #[rustc_clean(label="Hir", cfg="cfail3")]
-#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 enum EnumChangeOrderTupleStyleVariant {
-    Variant1(u64, u32),
+    Variant1(
+        #[rustc_metadata_dirty(cfg="cfail2")]
+        #[rustc_metadata_clean(cfg="cfail3")]
+        u64,
+        #[rustc_metadata_dirty(cfg="cfail2")]
+        #[rustc_metadata_clean(cfg="cfail3")]
+        u32),
 }
 
 
@@ -611,11 +633,23 @@ enum EnumSwapUsageTypeParameters<A, B> {
 #[cfg(not(cfail1))]
 #[rustc_dirty(label="Hir", cfg="cfail2")]
 #[rustc_clean(label="Hir", cfg="cfail3")]
-#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 enum EnumSwapUsageTypeParameters<A, B> {
-    Variant1 { a: B },
-    Variant2 { a: A },
+    #[rustc_metadata_clean(cfg="cfail2")]
+    #[rustc_metadata_clean(cfg="cfail3")]
+    Variant1 {
+        #[rustc_metadata_dirty(cfg="cfail2")]
+        #[rustc_metadata_clean(cfg="cfail3")]
+        a: B
+    },
+    #[rustc_metadata_clean(cfg="cfail2")]
+    #[rustc_metadata_clean(cfg="cfail3")]
+    Variant2 {
+        #[rustc_metadata_dirty(cfg="cfail2")]
+        #[rustc_metadata_clean(cfg="cfail3")]
+        a: A
+    },
 }
 
 
@@ -630,11 +664,23 @@ enum EnumSwapUsageLifetimeParameters<'a, 'b> {
 #[cfg(not(cfail1))]
 #[rustc_dirty(label="Hir", cfg="cfail2")]
 #[rustc_clean(label="Hir", cfg="cfail3")]
-#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 enum EnumSwapUsageLifetimeParameters<'a, 'b> {
-    Variant1 { a: &'b u32 },
-    Variant2 { b: &'a u32 },
+    #[rustc_metadata_clean(cfg="cfail2")]
+    #[rustc_metadata_clean(cfg="cfail3")]
+    Variant1 {
+        #[rustc_metadata_dirty(cfg="cfail2")]
+        #[rustc_metadata_clean(cfg="cfail3")]
+        a: &'b u32
+    },
+    #[rustc_metadata_clean(cfg="cfail2")]
+    #[rustc_metadata_clean(cfg="cfail3")]
+    Variant2 {
+        #[rustc_metadata_dirty(cfg="cfail2")]
+        #[rustc_metadata_clean(cfg="cfail3")]
+        b: &'a u32
+    },
 }
 
 
@@ -653,10 +699,16 @@ mod change_field_type_indirectly_tuple_style {
 
     #[rustc_dirty(label="Hir", cfg="cfail2")]
     #[rustc_clean(label="Hir", cfg="cfail3")]
-    #[rustc_metadata_dirty(cfg="cfail2")]
+    #[rustc_metadata_clean(cfg="cfail2")]
     #[rustc_metadata_clean(cfg="cfail3")]
     enum TupleStyle {
-        Variant1(FieldType)
+        #[rustc_metadata_dirty(cfg="cfail2")]
+        #[rustc_metadata_clean(cfg="cfail3")]
+        Variant1(
+            #[rustc_metadata_dirty(cfg="cfail2")]
+            #[rustc_metadata_clean(cfg="cfail3")]
+            FieldType
+        )
     }
 }
 
@@ -671,10 +723,16 @@ mod change_field_type_indirectly_struct_style {
 
     #[rustc_dirty(label="Hir", cfg="cfail2")]
     #[rustc_clean(label="Hir", cfg="cfail3")]
-    #[rustc_metadata_dirty(cfg="cfail2")]
+    #[rustc_metadata_clean(cfg="cfail2")]
     #[rustc_metadata_clean(cfg="cfail3")]
     enum StructStyle {
-        Variant1 { a: FieldType }
+        #[rustc_metadata_clean(cfg="cfail2")]
+        #[rustc_metadata_clean(cfg="cfail3")]
+        Variant1 {
+            #[rustc_metadata_dirty(cfg="cfail2")]
+            #[rustc_metadata_clean(cfg="cfail3")]
+            a: FieldType
+        }
     }
 }
 
diff --git a/src/test/incremental/hashes/extern_mods.rs b/src/test/incremental/hashes/extern_mods.rs
index 03e621fedbe..1d26e6c07d1 100644
--- a/src/test/incremental/hashes/extern_mods.rs
+++ b/src/test/incremental/hashes/extern_mods.rs
@@ -53,9 +53,11 @@ extern {
 #[cfg(not(cfail1))]
 #[rustc_dirty(label="Hir", cfg="cfail2")]
 #[rustc_clean(label="Hir", cfg="cfail3")]
-#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 extern {
+    #[rustc_metadata_dirty(cfg="cfail2")]
+    #[rustc_metadata_clean(cfg="cfail3")]
     pub fn change_parameter_name(d: i64) -> i32;
 }
 
@@ -70,9 +72,11 @@ extern {
 #[cfg(not(cfail1))]
 #[rustc_dirty(label="Hir", cfg="cfail2")]
 #[rustc_clean(label="Hir", cfg="cfail3")]
-#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 extern {
+    #[rustc_metadata_dirty(cfg="cfail2")]
+    #[rustc_metadata_clean(cfg="cfail3")]
     pub fn change_parameter_type(c: i32) -> i32;
 }
 
@@ -87,9 +91,11 @@ extern {
 #[cfg(not(cfail1))]
 #[rustc_dirty(label="Hir", cfg="cfail2")]
 #[rustc_clean(label="Hir", cfg="cfail3")]
-#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 extern {
+    #[rustc_metadata_dirty(cfg="cfail2")]
+    #[rustc_metadata_clean(cfg="cfail3")]
     pub fn change_return_type(c: i32) -> i8;
 }
 
@@ -104,9 +110,11 @@ extern {
 #[cfg(not(cfail1))]
 #[rustc_dirty(label="Hir", cfg="cfail2")]
 #[rustc_clean(label="Hir", cfg="cfail3")]
-#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 extern {
+    #[rustc_metadata_dirty(cfg="cfail2")]
+    #[rustc_metadata_clean(cfg="cfail3")]
     pub fn add_parameter(c: i32, d: i32) -> i32;
 }
 
@@ -121,9 +129,11 @@ extern {
 #[cfg(not(cfail1))]
 #[rustc_dirty(label="Hir", cfg="cfail2")]
 #[rustc_clean(label="Hir", cfg="cfail3")]
-#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 extern {
+    #[rustc_metadata_dirty(cfg="cfail2")]
+    #[rustc_metadata_clean(cfg="cfail3")]
     pub fn add_return_type(c: i32) -> i32;
 }
 
@@ -138,9 +148,11 @@ extern {
 #[cfg(not(cfail1))]
 #[rustc_dirty(label="Hir", cfg="cfail2")]
 #[rustc_clean(label="Hir", cfg="cfail3")]
-#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 extern {
+    #[rustc_metadata_dirty(cfg="cfail2")]
+    #[rustc_metadata_clean(cfg="cfail3")]
     pub fn make_function_variadic(c: i32, ...);
 }
 
@@ -155,9 +167,11 @@ extern "C" {
 #[cfg(not(cfail1))]
 #[rustc_dirty(label="Hir", cfg="cfail2")]
 #[rustc_clean(label="Hir", cfg="cfail3")]
-#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 extern "rust-call" {
+    #[rustc_metadata_dirty(cfg="cfail2")]
+    #[rustc_metadata_clean(cfg="cfail3")]
     pub fn change_calling_convention(c: i32);
 }
 
@@ -172,9 +186,11 @@ extern {
 #[cfg(not(cfail1))]
 #[rustc_dirty(label="Hir", cfg="cfail2")]
 #[rustc_clean(label="Hir", cfg="cfail3")]
-#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 extern {
+    #[rustc_metadata_dirty(cfg="cfail2")]
+    #[rustc_metadata_clean(cfg="cfail3")]
     pub fn make_function_public(c: i32);
 }
 
@@ -246,9 +262,11 @@ mod indirectly_change_parameter_type {
 
     #[rustc_dirty(label="Hir", cfg="cfail2")]
     #[rustc_clean(label="Hir", cfg="cfail3")]
-    #[rustc_metadata_dirty(cfg="cfail2")]
+    #[rustc_metadata_clean(cfg="cfail2")]
     #[rustc_metadata_clean(cfg="cfail3")]
     extern {
+        #[rustc_metadata_dirty(cfg="cfail2")]
+        #[rustc_metadata_clean(cfg="cfail3")]
         pub fn indirectly_change_parameter_type(c: c_int);
     }
 }
@@ -264,9 +282,11 @@ mod indirectly_change_return_type {
 
     #[rustc_dirty(label="Hir", cfg="cfail2")]
     #[rustc_clean(label="Hir", cfg="cfail3")]
-    #[rustc_metadata_dirty(cfg="cfail2")]
+    #[rustc_metadata_clean(cfg="cfail2")]
     #[rustc_metadata_clean(cfg="cfail3")]
     extern {
+        #[rustc_metadata_dirty(cfg="cfail2")]
+        #[rustc_metadata_clean(cfg="cfail3")]
         pub fn indirectly_change_return_type() -> c_int;
     }
 }
diff --git a/src/test/incremental/hashes/function_interfaces.rs b/src/test/incremental/hashes/function_interfaces.rs
index 93d94cd1a19..2fe3f0d5d1f 100644
--- a/src/test/incremental/hashes/function_interfaces.rs
+++ b/src/test/incremental/hashes/function_interfaces.rs
@@ -50,7 +50,7 @@ fn add_return_type() {}
 #[cfg(not(cfail1))]
 #[rustc_dirty(label="Hir", cfg="cfail2")]
 #[rustc_clean(label="Hir", cfg="cfail3")]
-#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail2")] // The type doesn't change, so metadata is the same
 #[rustc_metadata_clean(cfg="cfail3")]
 fn add_return_type() -> () {}
 
@@ -154,7 +154,7 @@ fn lifetime_parameter() {}
 #[cfg(not(cfail1))]
 #[rustc_dirty(label="Hir", cfg="cfail2")]
 #[rustc_clean(label="Hir", cfg="cfail3")]
-#[rustc_metadata_dirty(cfg="cfail2")]
+// #[rustc_metadata_dirty(cfg="cfail2")] -- Unused lifetime params don't show up in the type?
 #[rustc_metadata_clean(cfg="cfail3")]
 fn lifetime_parameter<'a>() {}
 
@@ -315,16 +315,16 @@ fn return_impl_trait() -> impl Clone {
 
 #[cfg(cfail1)]
 fn change_return_impl_trait() -> impl Clone {
-    0
+    0u32
 }
 
 #[cfg(not(cfail1))]
 #[rustc_dirty(label="Hir", cfg="cfail2")]
 #[rustc_clean(label="Hir", cfg="cfail3")]
-#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail2")] // The actual type is the same, so: clean
 #[rustc_metadata_clean(cfg="cfail3")]
 fn change_return_impl_trait() -> impl Copy {
-    0
+    0u32
 }
 
 
diff --git a/src/test/incremental/hashes/inherent_impls.rs b/src/test/incremental/hashes/inherent_impls.rs
index fd9ac61046e..899aefa24a0 100644
--- a/src/test/incremental/hashes/inherent_impls.rs
+++ b/src/test/incremental/hashes/inherent_impls.rs
@@ -107,7 +107,7 @@ impl Foo {
 #[cfg(not(cfail1))]
 #[rustc_dirty(label="Hir", cfg="cfail2")]
 #[rustc_clean(label="Hir", cfg="cfail3")]
-#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 impl Foo {
     #[rustc_dirty(label="Hir", cfg="cfail2")]
@@ -126,7 +126,7 @@ impl Foo {
 #[cfg(not(cfail1))]
 #[rustc_dirty(label="Hir", cfg="cfail2")]
 #[rustc_clean(label="Hir", cfg="cfail3")]
-#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 impl Foo {
     #[rustc_dirty(label="Hir", cfg="cfail2")]
@@ -171,7 +171,7 @@ impl Foo {
 impl Foo {
     #[rustc_clean(label="Hir", cfg="cfail2")]
     #[rustc_clean(label="Hir", cfg="cfail3")]
-    #[rustc_metadata_dirty(cfg="cfail2")]
+    #[rustc_metadata_clean(cfg="cfail2")]
     #[rustc_metadata_clean(cfg="cfail3")]
     pub fn add_method_to_impl1(&self) { }
 
@@ -219,9 +219,7 @@ impl Foo {
     #[rustc_clean(label="Hir", cfg="cfail3")]
     #[rustc_dirty(label="HirBody", cfg="cfail2")]
     #[rustc_clean(label="HirBody", cfg="cfail3")]
-    // At the moment we explicitly ignore argument names in metadata, since they
-    // are not used in downstream crates (except in rustdoc)
-    #[rustc_metadata_clean(cfg="cfail2")]
+    #[rustc_metadata_dirty(cfg="cfail2")]
     #[rustc_metadata_clean(cfg="cfail3")]
     pub fn change_method_parameter_name(&self, b: i64) { }
 }
@@ -287,9 +285,7 @@ impl Foo {
     #[rustc_clean(label="Hir", cfg="cfail3")]
     #[rustc_dirty(label="HirBody", cfg="cfail2")]
     #[rustc_clean(label="HirBody", cfg="cfail3")]
-    // At the moment we explicitly ignore argument names in metadata, since they
-    // are not used in downstream crates (except in rustdoc)
-    #[rustc_metadata_clean(cfg="cfail2")]
+    #[rustc_metadata_dirty(cfg="cfail2")]
     #[rustc_metadata_clean(cfg="cfail3")]
     pub fn change_method_parameter_order(&self, b: i64, a: i64) { }
 }
@@ -373,7 +369,7 @@ impl Foo {
 impl Foo {
     #[rustc_dirty(label="Hir", cfg="cfail2")]
     #[rustc_clean(label="Hir", cfg="cfail3")]
-    #[rustc_metadata_dirty(cfg="cfail2")]
+    #[rustc_metadata_clean(cfg="cfail2")] // Apparently unused lifetimes don't show up in the type.
     #[rustc_metadata_clean(cfg="cfail3")]
     pub fn add_lifetime_parameter_to_method<'a>(&self) { }
 }
@@ -544,7 +540,7 @@ impl<T> Bar<T> {
 impl<T: 'static> Bar<T> {
     #[rustc_clean(label="Hir", cfg="cfail2")]
     #[rustc_clean(label="Hir", cfg="cfail3")]
-    #[rustc_metadata_dirty(cfg="cfail2")]
+    #[rustc_metadata_clean(cfg="cfail2")]
     #[rustc_metadata_clean(cfg="cfail3")]
     pub fn add_lifetime_bound_to_impl_parameter(&self) { }
 }
@@ -565,7 +561,7 @@ impl<T> Bar<T> {
 impl<T: Clone> Bar<T> {
     #[rustc_clean(label="Hir", cfg="cfail2")]
     #[rustc_clean(label="Hir", cfg="cfail3")]
-    #[rustc_metadata_dirty(cfg="cfail2")]
+    #[rustc_metadata_clean(cfg="cfail2")]
     #[rustc_metadata_clean(cfg="cfail3")]
     pub fn add_trait_bound_to_impl_parameter(&self) { }
 }
diff --git a/src/test/incremental/hashes/struct_defs.rs b/src/test/incremental/hashes/struct_defs.rs
index 2d79987823f..17a5dc16783 100644
--- a/src/test/incremental/hashes/struct_defs.rs
+++ b/src/test/incremental/hashes/struct_defs.rs
@@ -62,9 +62,13 @@ struct TupleStructFieldType(i32);
 #[cfg(not(cfail1))]
 #[rustc_dirty(label="Hir", cfg="cfail2")]
 #[rustc_clean(label="Hir", cfg="cfail3")]
-#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
-struct TupleStructFieldType(u32);
+struct TupleStructFieldType(
+    #[rustc_metadata_dirty(cfg="cfail2")]
+    #[rustc_metadata_clean(cfg="cfail3")]
+    u32
+);
 
 
 // Tuple Struct Add Field ------------------------------------------------------
@@ -77,7 +81,13 @@ struct TupleStructAddField(i32);
 #[rustc_clean(label="Hir", cfg="cfail3")]
 #[rustc_metadata_dirty(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
-struct TupleStructAddField(i32, u32);
+struct TupleStructAddField(
+    #[rustc_metadata_clean(cfg="cfail2")]
+    #[rustc_metadata_clean(cfg="cfail3")]
+    i32,
+    #[rustc_metadata_clean(cfg="cfail3")]
+    u32
+);
 
 
 // Tuple Struct Field Visibility -----------------------------------------------
@@ -101,9 +111,13 @@ struct RecordStructFieldType { x: f32 }
 #[cfg(not(cfail1))]
 #[rustc_dirty(label="Hir", cfg="cfail2")]
 #[rustc_clean(label="Hir", cfg="cfail3")]
-#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
-struct RecordStructFieldType { x: u64 }
+struct RecordStructFieldType {
+    #[rustc_metadata_dirty(cfg="cfail2")]
+    #[rustc_metadata_clean(cfg="cfail3")]
+    x: u64
+}
 
 
 // Record Struct Field Name ----------------------------------------------------
@@ -129,7 +143,12 @@ struct RecordStructAddField { x: f32 }
 #[rustc_clean(label="Hir", cfg="cfail3")]
 #[rustc_metadata_dirty(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
-struct RecordStructAddField { x: f32, y: () }
+struct RecordStructAddField {
+    #[rustc_metadata_clean(cfg="cfail2")]
+    #[rustc_metadata_clean(cfg="cfail3")]
+    x: f32,
+    #[rustc_metadata_clean(cfg="cfail3")]
+    y: () }
 
 
 // Record Struct Field Visibility ----------------------------------------------
@@ -142,7 +161,11 @@ struct RecordStructFieldVisibility { x: f32 }
 #[rustc_clean(label="Hir", cfg="cfail3")]
 #[rustc_metadata_dirty(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
-struct RecordStructFieldVisibility { pub x: f32 }
+struct RecordStructFieldVisibility {
+    #[rustc_metadata_dirty(cfg="cfail2")]
+    #[rustc_metadata_clean(cfg="cfail3")]
+    pub x: f32
+}
 
 
 // Add Lifetime Parameter ------------------------------------------------------
@@ -168,7 +191,14 @@ struct AddLifetimeParameterBound<'a, 'b>(&'a f32, &'b f64);
 #[rustc_clean(label="Hir", cfg="cfail3")]
 #[rustc_metadata_dirty(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
-struct AddLifetimeParameterBound<'a, 'b: 'a>(&'a f32, &'b f64);
+struct AddLifetimeParameterBound<'a, 'b: 'a>(
+    #[rustc_metadata_clean(cfg="cfail2")]
+    #[rustc_metadata_clean(cfg="cfail3")]
+    &'a f32,
+    #[rustc_metadata_clean(cfg="cfail2")]
+    #[rustc_metadata_clean(cfg="cfail3")]
+    &'b f64
+);
 
 #[cfg(cfail1)]
 struct AddLifetimeParameterBoundWhereClause<'a, 'b>(&'a f32, &'b f64);
@@ -178,7 +208,13 @@ struct AddLifetimeParameterBoundWhereClause<'a, 'b>(&'a f32, &'b f64);
 #[rustc_clean(label="Hir", cfg="cfail3")]
 #[rustc_metadata_dirty(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
-struct AddLifetimeParameterBoundWhereClause<'a, 'b>(&'a f32, &'b f64)
+struct AddLifetimeParameterBoundWhereClause<'a, 'b>(
+    #[rustc_metadata_clean(cfg="cfail2")]
+    #[rustc_metadata_clean(cfg="cfail3")]
+    &'a f32,
+    #[rustc_metadata_clean(cfg="cfail2")]
+    #[rustc_metadata_clean(cfg="cfail3")]
+    &'b f64)
     where 'b: 'a;
 
 
@@ -192,7 +228,16 @@ struct AddTypeParameter<T1>(T1, T1);
 #[rustc_clean(label="Hir", cfg="cfail3")]
 #[rustc_metadata_dirty(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
-struct AddTypeParameter<T1, T2>(T1, T2);
+struct AddTypeParameter<T1, T2>(
+     // The field contains the parent's Generics, so it's dirty even though its
+     // type hasn't changed.
+    #[rustc_metadata_dirty(cfg="cfail2")]
+    #[rustc_metadata_clean(cfg="cfail3")]
+    T1,
+    #[rustc_metadata_dirty(cfg="cfail2")]
+    #[rustc_metadata_clean(cfg="cfail3")]
+    T2
+);
 
 
 // Add Type Parameter Bound ----------------------------------------------------
@@ -205,7 +250,11 @@ struct AddTypeParameterBound<T>(T);
 #[rustc_clean(label="Hir", cfg="cfail3")]
 #[rustc_metadata_dirty(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
-struct AddTypeParameterBound<T: Send>(T);
+struct AddTypeParameterBound<T: Send>(
+    #[rustc_metadata_clean(cfg="cfail2")]
+    #[rustc_metadata_clean(cfg="cfail3")]
+    T
+);
 
 
 #[cfg(cfail1)]
@@ -216,7 +265,11 @@ struct AddTypeParameterBoundWhereClause<T>(T);
 #[rustc_clean(label="Hir", cfg="cfail3")]
 #[rustc_metadata_dirty(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
-struct AddTypeParameterBoundWhereClause<T>(T) where T: Sync;
+struct AddTypeParameterBoundWhereClause<T>(
+    #[rustc_metadata_clean(cfg="cfail2")]
+    #[rustc_metadata_clean(cfg="cfail3")]
+    T
+) where T: Sync;
 
 
 // Empty struct ----------------------------------------------------------------
@@ -234,6 +287,7 @@ struct Visibility;
 #[cfg(not(cfail1))]
 #[rustc_dirty(label="Hir", cfg="cfail2")]
 #[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 pub struct Visibility;
 
@@ -252,9 +306,13 @@ mod tuple_struct_change_field_type_indirectly {
 
     #[rustc_dirty(label="Hir", cfg="cfail2")]
     #[rustc_clean(label="Hir", cfg="cfail3")]
-    #[rustc_metadata_dirty(cfg="cfail2")]
+    #[rustc_metadata_clean(cfg="cfail2")]
     #[rustc_metadata_clean(cfg="cfail3")]
-    struct TupleStruct(FieldType);
+    struct TupleStruct(
+        #[rustc_metadata_dirty(cfg="cfail2")]
+        #[rustc_metadata_clean(cfg="cfail3")]
+        FieldType
+    );
 }
 
 
@@ -267,9 +325,11 @@ mod record_struct_change_field_type_indirectly {
 
     #[rustc_dirty(label="Hir", cfg="cfail2")]
     #[rustc_clean(label="Hir", cfg="cfail3")]
-    #[rustc_metadata_dirty(cfg="cfail2")]
+    #[rustc_metadata_clean(cfg="cfail2")]
     #[rustc_metadata_clean(cfg="cfail3")]
     struct RecordStruct {
+        #[rustc_metadata_dirty(cfg="cfail2")]
+        #[rustc_metadata_clean(cfg="cfail3")]
         _x: FieldType
     }
 }
diff --git a/src/test/incremental/hashes/trait_defs.rs b/src/test/incremental/hashes/trait_defs.rs
index 94698506ec5..61a2be054a5 100644
--- a/src/test/incremental/hashes/trait_defs.rs
+++ b/src/test/incremental/hashes/trait_defs.rs
@@ -100,7 +100,7 @@ trait TraitAddReturnType {
 #[cfg(not(cfail1))]
 #[rustc_clean(label="Hir", cfg="cfail2")]
 #[rustc_clean(label="Hir", cfg="cfail3")]
-#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 trait TraitAddReturnType {
     #[rustc_dirty(label="Hir", cfg="cfail2")]
@@ -121,7 +121,7 @@ trait TraitChangeReturnType {
 #[cfg(not(cfail1))]
 #[rustc_clean(label="Hir", cfg="cfail2")]
 #[rustc_clean(label="Hir", cfg="cfail3")]
-#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 trait TraitChangeReturnType {
     #[rustc_dirty(label="Hir", cfg="cfail2")]
@@ -142,7 +142,7 @@ trait TraitAddParameterToMethod {
 #[cfg(not(cfail1))]
 #[rustc_clean(label="Hir", cfg="cfail2")]
 #[rustc_clean(label="Hir", cfg="cfail3")]
-#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 trait TraitAddParameterToMethod {
     #[rustc_dirty(label="Hir", cfg="cfail2")]
@@ -164,7 +164,7 @@ trait TraitChangeMethodParameterName {
 #[cfg(not(cfail1))]
 #[rustc_clean(label="Hir", cfg="cfail2")]
 #[rustc_clean(label="Hir", cfg="cfail3")]
-#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 trait TraitChangeMethodParameterName {
     // FIXME(#38501) This should preferably always be clean.
@@ -194,7 +194,7 @@ trait TraitChangeMethodParameterType {
 #[cfg(not(cfail1))]
 #[rustc_clean(label="Hir", cfg="cfail2")]
 #[rustc_clean(label="Hir", cfg="cfail3")]
-#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 trait TraitChangeMethodParameterType {
     #[rustc_dirty(label="Hir", cfg="cfail2")]
@@ -215,7 +215,7 @@ trait TraitChangeMethodParameterTypeRef {
 #[cfg(not(cfail1))]
 #[rustc_clean(label="Hir", cfg="cfail2")]
 #[rustc_clean(label="Hir", cfg="cfail3")]
-#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 trait TraitChangeMethodParameterTypeRef {
     #[rustc_dirty(label="Hir", cfg="cfail2")]
@@ -236,7 +236,7 @@ trait TraitChangeMethodParametersOrder {
 #[cfg(not(cfail1))]
 #[rustc_clean(label="Hir", cfg="cfail2")]
 #[rustc_clean(label="Hir", cfg="cfail3")]
-#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 trait TraitChangeMethodParametersOrder {
     #[rustc_dirty(label="Hir", cfg="cfail2")]
@@ -257,9 +257,13 @@ trait TraitAddMethodDefaultImplementation {
 #[cfg(not(cfail1))]
 #[rustc_dirty(label="Hir", cfg="cfail2")]
 #[rustc_clean(label="Hir", cfg="cfail3")]
-#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 trait TraitAddMethodDefaultImplementation {
+    #[rustc_dirty(label="Hir", cfg="cfail2")]
+    #[rustc_clean(label="Hir", cfg="cfail3")]
+    #[rustc_metadata_dirty(cfg="cfail2")]
+    #[rustc_metadata_clean(cfg="cfail3")]
     fn method() { }
 }
 
@@ -293,7 +297,7 @@ trait TraitChangeModeSelfRefToMut {
 #[cfg(not(cfail1))]
 #[rustc_clean(label="Hir", cfg="cfail2")]
 #[rustc_clean(label="Hir", cfg="cfail3")]
-#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 trait TraitChangeModeSelfRefToMut {
     #[rustc_dirty(label="Hir", cfg="cfail2")]
@@ -335,7 +339,7 @@ trait TraitChangeModeSelfOwnToRef {
 #[cfg(not(cfail1))]
 #[rustc_clean(label="Hir", cfg="cfail2")]
 #[rustc_clean(label="Hir", cfg="cfail3")]
-#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 trait TraitChangeModeSelfOwnToRef {
     #[rustc_dirty(label="Hir", cfg="cfail2")]
@@ -356,7 +360,7 @@ trait TraitAddUnsafeModifier {
 #[cfg(not(cfail1))]
 #[rustc_clean(label="Hir", cfg="cfail2")]
 #[rustc_clean(label="Hir", cfg="cfail3")]
-#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 trait TraitAddUnsafeModifier {
     #[rustc_dirty(label="Hir", cfg="cfail2")]
@@ -377,7 +381,7 @@ trait TraitAddExternModifier {
 #[cfg(not(cfail1))]
 #[rustc_clean(label="Hir", cfg="cfail2")]
 #[rustc_clean(label="Hir", cfg="cfail3")]
-#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 trait TraitAddExternModifier {
     #[rustc_dirty(label="Hir", cfg="cfail2")]
@@ -398,7 +402,7 @@ trait TraitChangeExternCToRustIntrinsic {
 #[cfg(not(cfail1))]
 #[rustc_clean(label="Hir", cfg="cfail2")]
 #[rustc_clean(label="Hir", cfg="cfail3")]
-#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 trait TraitChangeExternCToRustIntrinsic {
     #[rustc_dirty(label="Hir", cfg="cfail2")]
@@ -419,7 +423,7 @@ trait TraitAddTypeParameterToMethod {
 #[cfg(not(cfail1))]
 #[rustc_clean(label="Hir", cfg="cfail2")]
 #[rustc_clean(label="Hir", cfg="cfail3")]
-#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 trait TraitAddTypeParameterToMethod {
     #[rustc_dirty(label="Hir", cfg="cfail2")]
@@ -440,12 +444,12 @@ trait TraitAddLifetimeParameterToMethod {
 #[cfg(not(cfail1))]
 #[rustc_clean(label="Hir", cfg="cfail2")]
 #[rustc_clean(label="Hir", cfg="cfail3")]
-#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 trait TraitAddLifetimeParameterToMethod {
     #[rustc_dirty(label="Hir", cfg="cfail2")]
     #[rustc_clean(label="Hir", cfg="cfail3")]
-    #[rustc_metadata_dirty(cfg="cfail2")]
+    #[rustc_metadata_clean(cfg="cfail2")] // Unused lifetimes don't seem to show up in type?
     #[rustc_metadata_clean(cfg="cfail3")]
     fn method<'a>();
 }
@@ -465,7 +469,7 @@ trait TraitAddTraitBoundToMethodTypeParameter {
 #[cfg(not(cfail1))]
 #[rustc_clean(label="Hir", cfg="cfail2")]
 #[rustc_clean(label="Hir", cfg="cfail3")]
-#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 trait TraitAddTraitBoundToMethodTypeParameter {
     #[rustc_dirty(label="Hir", cfg="cfail2")]
@@ -486,7 +490,7 @@ trait TraitAddBuiltinBoundToMethodTypeParameter {
 #[cfg(not(cfail1))]
 #[rustc_clean(label="Hir", cfg="cfail2")]
 #[rustc_clean(label="Hir", cfg="cfail3")]
-#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 trait TraitAddBuiltinBoundToMethodTypeParameter {
     #[rustc_dirty(label="Hir", cfg="cfail2")]
@@ -507,7 +511,7 @@ trait TraitAddLifetimeBoundToMethodLifetimeParameter {
 #[cfg(not(cfail1))]
 #[rustc_clean(label="Hir", cfg="cfail2")]
 #[rustc_clean(label="Hir", cfg="cfail3")]
-#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 trait TraitAddLifetimeBoundToMethodLifetimeParameter {
     #[rustc_dirty(label="Hir", cfg="cfail2")]
@@ -528,7 +532,7 @@ trait TraitAddSecondTraitBoundToMethodTypeParameter {
 #[cfg(not(cfail1))]
 #[rustc_clean(label="Hir", cfg="cfail2")]
 #[rustc_clean(label="Hir", cfg="cfail3")]
-#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 trait TraitAddSecondTraitBoundToMethodTypeParameter {
     #[rustc_dirty(label="Hir", cfg="cfail2")]
@@ -549,7 +553,7 @@ trait TraitAddSecondBuiltinBoundToMethodTypeParameter {
 #[cfg(not(cfail1))]
 #[rustc_clean(label="Hir", cfg="cfail2")]
 #[rustc_clean(label="Hir", cfg="cfail3")]
-#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 trait TraitAddSecondBuiltinBoundToMethodTypeParameter {
     #[rustc_dirty(label="Hir", cfg="cfail2")]
@@ -570,7 +574,7 @@ trait TraitAddSecondLifetimeBoundToMethodLifetimeParameter {
 #[cfg(not(cfail1))]
 #[rustc_clean(label="Hir", cfg="cfail2")]
 #[rustc_clean(label="Hir", cfg="cfail3")]
-#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 trait TraitAddSecondLifetimeBoundToMethodLifetimeParameter {
     #[rustc_dirty(label="Hir", cfg="cfail2")]
@@ -585,7 +589,12 @@ trait TraitAddSecondLifetimeBoundToMethodLifetimeParameter {
 // Add associated type ------------------------------------------------------------
 #[cfg(cfail1)]
 trait TraitAddAssociatedType {
-    fn mathod();
+
+    #[rustc_dirty(label="Hir", cfg="cfail2")]
+    #[rustc_clean(label="Hir", cfg="cfail3")]
+    #[rustc_metadata_dirty(cfg="cfail2")]
+    #[rustc_metadata_clean(cfg="cfail3")]
+    fn method();
 }
 
 #[cfg(not(cfail1))]
@@ -596,7 +605,7 @@ trait TraitAddAssociatedType {
 trait TraitAddAssociatedType {
     type Associated;
 
-    fn mathod();
+    fn method();
 }
 
 
@@ -606,9 +615,12 @@ trait TraitAddAssociatedType {
 trait TraitAddTraitBoundToAssociatedType {
     type Associated;
 
-    fn mathod();
+    fn method();
 }
 
+
+// Apparently the type bound contributes to the predicates of the trait, but
+// does not change the associated item itself.
 #[cfg(not(cfail1))]
 #[rustc_clean(label="Hir", cfg="cfail2")]
 #[rustc_clean(label="Hir", cfg="cfail3")]
@@ -617,11 +629,11 @@ trait TraitAddTraitBoundToAssociatedType {
 trait TraitAddTraitBoundToAssociatedType {
     #[rustc_dirty(label="Hir", cfg="cfail2")]
     #[rustc_clean(label="Hir", cfg="cfail3")]
-    #[rustc_metadata_dirty(cfg="cfail2")]
+    #[rustc_metadata_clean(cfg="cfail2")]
     #[rustc_metadata_clean(cfg="cfail3")]
     type Associated: ReferencedTrait0;
 
-    fn mathod();
+    fn method();
 }
 
 
@@ -631,7 +643,7 @@ trait TraitAddTraitBoundToAssociatedType {
 trait TraitAddLifetimeBoundToAssociatedType<'a> {
     type Associated;
 
-    fn mathod();
+    fn method();
 }
 
 #[cfg(not(cfail1))]
@@ -642,11 +654,11 @@ trait TraitAddLifetimeBoundToAssociatedType<'a> {
 trait TraitAddLifetimeBoundToAssociatedType<'a> {
     #[rustc_dirty(label="Hir", cfg="cfail2")]
     #[rustc_clean(label="Hir", cfg="cfail3")]
-    #[rustc_metadata_dirty(cfg="cfail2")]
+    #[rustc_metadata_clean(cfg="cfail2")]
     #[rustc_metadata_clean(cfg="cfail3")]
     type Associated: 'a;
 
-    fn mathod();
+    fn method();
 }
 
 
@@ -656,18 +668,22 @@ trait TraitAddLifetimeBoundToAssociatedType<'a> {
 trait TraitAddDefaultToAssociatedType {
     type Associated;
 
-    fn mathod();
+    fn method();
 }
 
 #[cfg(not(cfail1))]
 #[rustc_dirty(label="Hir", cfg="cfail2")]
 #[rustc_clean(label="Hir", cfg="cfail3")]
-#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 trait TraitAddDefaultToAssociatedType {
+    #[rustc_dirty(label="Hir", cfg="cfail2")]
+    #[rustc_clean(label="Hir", cfg="cfail3")]
+    #[rustc_metadata_dirty(cfg="cfail2")]
+    #[rustc_metadata_clean(cfg="cfail3")]
     type Associated = ReferenceType0;
 
-    fn mathod();
+    fn method();
 }
 
 
@@ -675,7 +691,7 @@ trait TraitAddDefaultToAssociatedType {
 // Add associated constant --------------------------------------------------------
 #[cfg(cfail1)]
 trait TraitAddAssociatedConstant {
-    fn mathod();
+    fn method();
 }
 
 #[cfg(not(cfail1))]
@@ -686,7 +702,7 @@ trait TraitAddAssociatedConstant {
 trait TraitAddAssociatedConstant {
     const Value: u32;
 
-    fn mathod();
+    fn method();
 }
 
 
@@ -696,18 +712,26 @@ trait TraitAddAssociatedConstant {
 trait TraitAddInitializerToAssociatedConstant {
     const Value: u32;
 
-    fn mathod();
+    fn method();
 }
 
 #[cfg(not(cfail1))]
 #[rustc_dirty(label="Hir", cfg="cfail2")]
 #[rustc_clean(label="Hir", cfg="cfail3")]
-#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 trait TraitAddInitializerToAssociatedConstant {
+    #[rustc_dirty(label="Hir", cfg="cfail2")]
+    #[rustc_clean(label="Hir", cfg="cfail3")]
+    #[rustc_metadata_dirty(cfg="cfail2")]
+    #[rustc_metadata_clean(cfg="cfail3")]
     const Value: u32 = 1;
 
-    fn mathod();
+    #[rustc_clean(label="Hir", cfg="cfail2")]
+    #[rustc_clean(label="Hir", cfg="cfail3")]
+    #[rustc_metadata_clean(cfg="cfail2")]
+    #[rustc_metadata_clean(cfg="cfail3")]
+    fn method();
 }
 
 
@@ -717,13 +741,13 @@ trait TraitAddInitializerToAssociatedConstant {
 trait TraitChangeTypeOfAssociatedConstant {
     const Value: u32;
 
-    fn mathod();
+    fn method();
 }
 
 #[cfg(not(cfail1))]
 #[rustc_clean(label="Hir", cfg="cfail2")]
 #[rustc_clean(label="Hir", cfg="cfail3")]
-#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 trait TraitChangeTypeOfAssociatedConstant {
     #[rustc_dirty(label="Hir", cfg="cfail2")]
@@ -732,7 +756,11 @@ trait TraitChangeTypeOfAssociatedConstant {
     #[rustc_metadata_clean(cfg="cfail3")]
     const Value: f64;
 
-    fn mathod();
+    #[rustc_clean(label="Hir", cfg="cfail2")]
+    #[rustc_clean(label="Hir", cfg="cfail3")]
+    #[rustc_metadata_clean(cfg="cfail2")]
+    #[rustc_metadata_clean(cfg="cfail3")]
+    fn method();
 }
 
 
@@ -1111,9 +1139,6 @@ trait TraitAddSecondBuiltinBoundToTypeParameterOfTraitWhere<T> where T: Send { }
 trait TraitAddSecondBuiltinBoundToTypeParameterOfTraitWhere<T> where T: Send + Sync { }
 
 
-
-// EDIT: Some more cases ----------------------------------------------------------
-
 // Change return type of method indirectly by modifying a use statement------------
 mod change_return_type_of_method_indirectly_use {
     #[cfg(cfail1)]
@@ -1123,7 +1148,7 @@ mod change_return_type_of_method_indirectly_use {
 
     #[rustc_clean(label="Hir", cfg="cfail2")]
     #[rustc_clean(label="Hir", cfg="cfail3")]
-    #[rustc_metadata_dirty(cfg="cfail2")]
+    #[rustc_metadata_clean(cfg="cfail2")]
     #[rustc_metadata_clean(cfg="cfail3")]
     trait TraitChangeReturnType {
         #[rustc_dirty(label="Hir", cfg="cfail2")]
@@ -1145,7 +1170,7 @@ mod change_method_parameter_type_indirectly_by_use {
 
     #[rustc_clean(label="Hir", cfg="cfail2")]
     #[rustc_clean(label="Hir", cfg="cfail3")]
-    #[rustc_metadata_dirty(cfg="cfail2")]
+    #[rustc_metadata_clean(cfg="cfail2")]
     #[rustc_metadata_clean(cfg="cfail3")]
     trait TraitChangeArgType {
         #[rustc_dirty(label="Hir", cfg="cfail2")]
@@ -1167,7 +1192,7 @@ mod change_method_parameter_type_bound_indirectly_by_use {
 
     #[rustc_clean(label="Hir", cfg="cfail2")]
     #[rustc_clean(label="Hir", cfg="cfail3")]
-    #[rustc_metadata_dirty(cfg="cfail2")]
+    #[rustc_metadata_clean(cfg="cfail2")]
     #[rustc_metadata_clean(cfg="cfail3")]
     trait TraitChangeBoundOfMethodTypeParameter {
         #[rustc_dirty(label="Hir", cfg="cfail2")]
@@ -1190,7 +1215,7 @@ mod change_method_parameter_type_bound_indirectly_by_use_where {
 
     #[rustc_clean(label="Hir", cfg="cfail2")]
     #[rustc_clean(label="Hir", cfg="cfail3")]
-    #[rustc_metadata_dirty(cfg="cfail2")]
+    #[rustc_metadata_clean(cfg="cfail2")]
     #[rustc_metadata_clean(cfg="cfail3")]
     trait TraitChangeBoundOfMethodTypeParameterWhere {
         #[rustc_dirty(label="Hir", cfg="cfail2")]
diff --git a/src/test/incremental/hashes/trait_impls.rs b/src/test/incremental/hashes/trait_impls.rs
index 30e376f04fb..06c8eb6a878 100644
--- a/src/test/incremental/hashes/trait_impls.rs
+++ b/src/test/incremental/hashes/trait_impls.rs
@@ -120,7 +120,7 @@ impl ChangeMethodBodyTraitInlined for Foo {
     #[rustc_metadata_clean(cfg="cfail3")]
     #[inline]
     fn method_name() {
-        ()
+        panic!()
     }
 }
 
@@ -144,7 +144,7 @@ pub trait ChangeMethodSelfnessTrait {
 #[cfg(not(cfail1))]
 #[rustc_dirty(label="Hir", cfg="cfail2")]
 #[rustc_clean(label="Hir", cfg="cfail3")]
-#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 impl ChangeMethodSelfnessTrait for Foo {
     #[rustc_dirty(label="Hir", cfg="cfail2")]
@@ -176,16 +176,14 @@ pub trait RemoveMethodSelfnessTrait {
 #[cfg(not(cfail1))]
 #[rustc_dirty(label="Hir", cfg="cfail2")]
 #[rustc_clean(label="Hir", cfg="cfail3")]
-#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 impl RemoveMethodSelfnessTrait for Foo {
     #[rustc_dirty(label="Hir", cfg="cfail2")]
     #[rustc_clean(label="Hir", cfg="cfail3")]
     #[rustc_metadata_dirty(cfg="cfail2")]
     #[rustc_metadata_clean(cfg="cfail3")]
-    fn method_name() {
-        ()
-    }
+    fn method_name() {}
 }
 
 // Change Method Selfmutness -----------------------------------------------------------
@@ -208,16 +206,14 @@ pub trait ChangeMethodSelfmutnessTrait {
 #[cfg(not(cfail1))]
 #[rustc_clean(label="Hir", cfg="cfail2")]
 #[rustc_clean(label="Hir", cfg="cfail3")]
-#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 impl ChangeMethodSelfmutnessTrait for Foo {
     #[rustc_dirty(label="Hir", cfg="cfail2")]
     #[rustc_clean(label="Hir", cfg="cfail3")]
     #[rustc_metadata_dirty(cfg="cfail2")]
     #[rustc_metadata_clean(cfg="cfail3")]
-    fn method_name(&mut self) {
-        ()
-    }
+    fn method_name(&mut self) {}
 }
 
 // Change item kind -----------------------------------------------------------
@@ -317,16 +313,20 @@ impl ChangeHasValueTrait for Foo {
 #[cfg(not(cfail1))]
 #[rustc_dirty(label="Hir", cfg="cfail2")]
 #[rustc_clean(label="Hir", cfg="cfail3")]
-#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 pub trait ChangeHasValueTrait {
+    #[rustc_dirty(label="Hir", cfg="cfail2")]
+    #[rustc_clean(label="Hir", cfg="cfail3")]
+    #[rustc_metadata_dirty(cfg="cfail2")]
+    #[rustc_metadata_clean(cfg="cfail3")]
     fn method_name() { }
 }
 
 #[cfg(not(cfail1))]
 #[rustc_clean(label="Hir", cfg="cfail2")]
 #[rustc_clean(label="Hir", cfg="cfail3")]
-#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 impl ChangeHasValueTrait for Foo {
     fn method_name() { }
@@ -346,32 +346,16 @@ impl AddDefaultTrait for Foo {
 #[cfg(not(cfail1))]
 #[rustc_dirty(label="Hir", cfg="cfail2")]
 #[rustc_clean(label="Hir", cfg="cfail3")]
-#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 impl AddDefaultTrait for Foo {
+    #[rustc_dirty(label="Hir", cfg="cfail2")]
+    #[rustc_clean(label="Hir", cfg="cfail3")]
+    #[rustc_metadata_dirty(cfg="cfail2")]
+    #[rustc_metadata_clean(cfg="cfail3")]
     default fn method_name() { }
 }
 
-// Remove default
-
-pub trait RemoveDefaultTrait {
-    fn method_name();
-}
-
-#[cfg(cfail1)]
-impl RemoveDefaultTrait for Foo {
-    default fn method_name() { }
-}
-
-#[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
-#[rustc_clean(label="Hir", cfg="cfail3")]
-#[rustc_metadata_dirty(cfg="cfail2")]
-#[rustc_metadata_clean(cfg="cfail3")]
-impl RemoveDefaultTrait for Foo {
-    fn method_name() { }
-}
-
 // Add arguments
 
 #[cfg(cfail1)]
@@ -392,7 +376,7 @@ pub trait AddArgumentTrait {
 #[cfg(not(cfail1))]
 #[rustc_clean(label="Hir", cfg="cfail2")]
 #[rustc_clean(label="Hir", cfg="cfail3")]
-#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 impl AddArgumentTrait for Foo {
     #[rustc_dirty(label="Hir", cfg="cfail2")]
@@ -422,7 +406,7 @@ pub trait ChangeArgumentTypeTrait {
 #[cfg(not(cfail1))]
 #[rustc_clean(label="Hir", cfg="cfail2")]
 #[rustc_clean(label="Hir", cfg="cfail3")]
-#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 impl ChangeArgumentTypeTrait for Foo {
     #[rustc_dirty(label="Hir", cfg="cfail2")]
@@ -504,7 +488,7 @@ impl<T> AddLifetimeBoundToImplParameter for T {
 impl<T: 'static> AddLifetimeBoundToImplParameter for T {
     #[rustc_clean(label="Hir", cfg="cfail2")]
     #[rustc_clean(label="Hir", cfg="cfail3")]
-    #[rustc_metadata_dirty(cfg="cfail2")]
+    #[rustc_metadata_clean(cfg="cfail2")]
     #[rustc_metadata_clean(cfg="cfail3")]
     fn id(self) -> Self { self }
 }
@@ -529,7 +513,7 @@ impl<T> AddTraitBoundToImplParameter for T {
 impl<T: Clone> AddTraitBoundToImplParameter for T {
     #[rustc_clean(label="Hir", cfg="cfail2")]
     #[rustc_clean(label="Hir", cfg="cfail3")]
-    #[rustc_metadata_dirty(cfg="cfail2")]
+    #[rustc_metadata_clean(cfg="cfail2")]
     #[rustc_metadata_clean(cfg="cfail3")]
     fn id(self) -> Self { self }
 }
diff --git a/src/test/incremental/unchecked_dirty_clean_metadata.rs b/src/test/incremental/unchecked_dirty_clean_metadata.rs
index 4017b4d4ba9..917c2c9dbce 100644
--- a/src/test/incremental/unchecked_dirty_clean_metadata.rs
+++ b/src/test/incremental/unchecked_dirty_clean_metadata.rs
@@ -33,13 +33,3 @@ fn main() {
     }
 }
 
-struct _Struct {
-    #[rustc_metadata_dirty(cfg="cfail2")]
-    //[cfail2]~^ ERROR found unchecked #[rustc_dirty]/#[rustc_clean] attribute
-    _field1: i32,
-
-    #[rustc_metadata_clean(cfg="cfail2")]
-    //[cfail2]~^ ERROR found unchecked #[rustc_dirty]/#[rustc_clean] attribute
-    _field2: i32,
-}
-
diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs
index 2865fa6a792..7fb296c19f6 100644
--- a/src/tools/compiletest/src/runtest.rs
+++ b/src/tools/compiletest/src/runtest.rs
@@ -1589,8 +1589,14 @@ actual:\n\
     }
 
     fn dump_output(&self, out: &str, err: &str) {
-        self.dump_output_file(out, "out");
-        self.dump_output_file(err, "err");
+        let revision = if let Some(r) = self.revision {
+            format!("{}.", r)
+        } else {
+            String::new()
+        };
+
+        self.dump_output_file(out, &format!("{}out", revision));
+        self.dump_output_file(err, &format!("{}err", revision));
         self.maybe_dump_to_stdout(out, err);
     }