about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2017-04-12 13:22:16 +0000
committerbors <bors@rust-lang.org>2017-04-12 13:22:16 +0000
commit910c4816fdee01a1299d11a5e85ebb4aceee6d1a (patch)
tree5413288c2a03b64c62c03782b194d28e2de37739 /src
parent1dca19ae3fd195fa517e326a39bfee729da7cadb (diff)
parentd4d35cfecc7df36d62a0e6dbc66106657667c92e (diff)
Auto merge of #41246 - TimNN:rollup, r=TimNN
Rollup of 9 pull requests

- Successful merges: #41063, #41087, #41141, #41166, #41183, #41205, #41206, #41232, #41243
- Failed merges:
Diffstat (limited to 'src')
-rw-r--r--src/libcollections/str.rs37
-rw-r--r--src/librustc/dep_graph/dep_node.rs8
-rw-r--r--src/librustc/hir/map/mod.rs21
-rw-r--r--src/librustc/ich/hcx.rs52
-rw-r--r--src/librustc/ich/impls_mir.rs3
-rw-r--r--src/librustc/ich/impls_ty.rs301
-rw-r--r--src/librustc/ich/mod.rs4
-rw-r--r--src/librustc/infer/error_reporting/mod.rs288
-rw-r--r--src/librustc/infer/error_reporting/note.rs2
-rw-r--r--src/librustc/lib.rs1
-rw-r--r--src/librustc/middle/cstore.rs23
-rw-r--r--src/librustc/middle/effect.rs3
-rw-r--r--src/librustc/middle/free_region.rs4
-rw-r--r--src/librustc/middle/liveness.rs2
-rw-r--r--src/librustc/mir/mod.rs40
-rw-r--r--src/librustc/mir/visit.rs5
-rw-r--r--src/librustc/ty/maps.rs2
-rw-r--r--src/librustc/ty/mod.rs19
-rw-r--r--src/librustc/ty/util.rs30
-rw-r--r--src/librustc_borrowck/borrowck/mir/elaborate_drops.rs6
-rw-r--r--src/librustc_borrowck/borrowck/mod.rs32
-rw-r--r--src/librustc_borrowck/lib.rs2
-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.rs10
-rw-r--r--src/librustc_errors/diagnostic.rs72
-rw-r--r--src/librustc_errors/diagnostic_builder.rs10
-rw-r--r--src/librustc_errors/lib.rs2
-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_mir/build/expr/as_lvalue.rs3
-rw-r--r--src/librustc_mir/build/expr/as_rvalue.rs14
-rw-r--r--src/librustc_mir/build/expr/as_temp.rs2
-rw-r--r--src/librustc_mir/build/expr/stmt.rs2
-rw-r--r--src/librustc_mir/build/matches/mod.rs3
-rw-r--r--src/librustc_mir/build/matches/test.rs13
-rw-r--r--src/librustc_mir/build/misc.rs6
-rw-r--r--src/librustc_mir/build/mod.rs12
-rw-r--r--src/librustc_mir/diagnostics.rs33
-rw-r--r--src/librustc_mir/shim.rs23
-rw-r--r--src/librustc_mir/transform/inline.rs15
-rw-r--r--src/librustc_mir/transform/promote_consts.rs6
-rw-r--r--src/librustc_mir/transform/qualify_consts.rs2
-rw-r--r--src/librustc_mir/transform/type_check.rs52
-rw-r--r--src/librustc_mir/util/elaborate_drops.rs2
-rw-r--r--src/librustc_mir/util/patch.rs5
-rw-r--r--src/librustc_mir/util/pretty.rs4
-rw-r--r--src/librustc_passes/diagnostics.rs33
-rw-r--r--src/librustc_passes/lib.rs1
-rw-r--r--src/librustc_passes/loops.rs2
-rw-r--r--src/librustc_passes/rvalues.rs103
-rw-r--r--src/librustc_passes/static_recursion.rs3
-rw-r--r--src/librustc_trans/abi.rs2
-rw-r--r--src/librustc_trans/back/link.rs5
-rw-r--r--src/librustc_trans/base.rs11
-rw-r--r--src/librustc_trans/cabi_x86_64.rs17
-rw-r--r--src/librustc_trans/debuginfo/create_scope_map.rs2
-rw-r--r--src/librustc_trans/lib.rs2
-rw-r--r--src/librustc_trans/mir/mod.rs5
-rw-r--r--src/libstd/primitive_docs.rs8
-rw-r--r--src/libsyntax/parse/parser.rs6
-rw-r--r--src/test/compile-fail/issue-41139.rs18
-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/test/run-make/extern-fn-struct-passing-abi/test.c19
-rw-r--r--src/test/run-make/extern-fn-struct-passing-abi/test.rs11
-rw-r--r--src/test/ui/lifetime-errors/ex2a-push-one-existing-name.stderr4
-rw-r--r--src/test/ui/lifetime-errors/ex2b-push-no-existing-names.stderr4
-rw-r--r--src/test/ui/lifetime-errors/ex2c-push-inference-variable.stderr2
-rw-r--r--src/test/ui/mismatched_types/abridged.rs61
-rw-r--r--src/test/ui/mismatched_types/abridged.stderr70
-rw-r--r--src/test/ui/suggestions/tuple-float-index.rs (renamed from src/test/parse-fail/tuple-float-index.rs)4
-rw-r--r--src/test/ui/suggestions/tuple-float-index.stderr11
-rw-r--r--src/tools/compiletest/src/runtest.rs10
-rw-r--r--src/tools/tidy/src/main.rs2
92 files changed, 2048 insertions, 701 deletions
diff --git a/src/libcollections/str.rs b/src/libcollections/str.rs
index d04f414250a..e3808248e22 100644
--- a/src/libcollections/str.rs
+++ b/src/libcollections/str.rs
@@ -325,8 +325,10 @@ impl str {
 
     /// Returns a subslice of `str`.
     ///
-    /// This is the non-panicking alternative to indexing the `str`. Returns `None` whenever
-    /// equivalent indexing operation would panic.
+    /// This is the non-panicking alternative to indexing the `str`. Returns
+    /// [`None`] whenever equivalent indexing operation would panic.
+    ///
+    /// [`None`]: option/enum.Option.html#variant.None
     ///
     /// # Examples
     ///
@@ -346,8 +348,10 @@ impl str {
 
     /// Returns a mutable subslice of `str`.
     ///
-    /// This is the non-panicking alternative to indexing the `str`. Returns `None` whenever
-    /// equivalent indexing operation would panic.
+    /// This is the non-panicking alternative to indexing the `str`. Returns
+    /// [`None`] whenever equivalent indexing operation would panic.
+    ///
+    /// [`None`]: option/enum.Option.html#variant.None
     ///
     /// # Examples
     ///
@@ -570,7 +574,7 @@ impl str {
         core_str::StrExt::split_at_mut(self, mid)
     }
 
-    /// Returns an iterator over the `char`s of a string slice.
+    /// Returns an iterator over the [`char`]s of a string slice.
     ///
     /// As a string slice consists of valid UTF-8, we can iterate through a
     /// string slice by [`char`]. This method returns such an iterator.
@@ -1657,13 +1661,13 @@ impl str {
 
     /// Parses this string slice into another type.
     ///
-    /// Because `parse()` is so general, it can cause problems with type
-    /// inference. As such, `parse()` is one of the few times you'll see
+    /// Because `parse` is so general, it can cause problems with type
+    /// inference. As such, `parse` is one of the few times you'll see
     /// the syntax affectionately known as the 'turbofish': `::<>`. This
     /// helps the inference algorithm understand specifically which type
     /// you're trying to parse into.
     ///
-    /// `parse()` can parse any type that implements the [`FromStr`] trait.
+    /// `parse` can parse any type that implements the [`FromStr`] trait.
     ///
     /// [`FromStr`]: str/trait.FromStr.html
     ///
@@ -1746,7 +1750,7 @@ impl str {
     ///
     /// `replacen` creates a new [`String`], and copies the data from this string slice into it.
     /// While doing so, it attempts to find matches of a pattern. If it finds any, it
-    /// replaces them with the replacement string slice at most `N` times.
+    /// replaces them with the replacement string slice at most `count` times.
     ///
     /// [`String`]: string/struct.String.html
     ///
@@ -1892,7 +1896,9 @@ impl str {
         return s;
     }
 
-    /// Escapes each char in `s` with `char::escape_debug`.
+    /// Escapes each char in `s` with [`char::escape_debug`].
+    ///
+    /// [`char::escape_debug`]: primitive.char.html#method.escape_debug
     #[unstable(feature = "str_escape",
                reason = "return type may change to be an iterator",
                issue = "27791")]
@@ -1900,7 +1906,9 @@ impl str {
         self.chars().flat_map(|c| c.escape_debug()).collect()
     }
 
-    /// Escapes each char in `s` with `char::escape_default`.
+    /// Escapes each char in `s` with [`char::escape_default`].
+    ///
+    /// [`char::escape_default`]: primitive.char.html#method.escape_default
     #[unstable(feature = "str_escape",
                reason = "return type may change to be an iterator",
                issue = "27791")]
@@ -1908,7 +1916,9 @@ impl str {
         self.chars().flat_map(|c| c.escape_default()).collect()
     }
 
-    /// Escapes each char in `s` with `char::escape_unicode`.
+    /// Escapes each char in `s` with [`char::escape_unicode`].
+    ///
+    /// [`char::escape_unicode`]: primitive.char.html#method.escape_unicode
     #[unstable(feature = "str_escape",
                reason = "return type may change to be an iterator",
                issue = "27791")]
@@ -1916,9 +1926,10 @@ impl str {
         self.chars().flat_map(|c| c.escape_unicode()).collect()
     }
 
-    /// Converts a `Box<str>` into a [`String`] without copying or allocating.
+    /// Converts a [`Box<str>`] into a [`String`] without copying or allocating.
     ///
     /// [`String`]: string/struct.String.html
+    /// [`Box<str>`]: boxed/struct.Box.html
     ///
     /// # Examples
     ///
diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs
index 5aea2bcaa4f..59d04ea8c77 100644
--- a/src/librustc/dep_graph/dep_node.rs
+++ b/src/librustc/dep_graph/dep_node.rs
@@ -57,17 +57,13 @@ pub enum DepNode<D: Clone + Debug> {
 
     // Represents different phases in the compiler.
     CollectLanguageItems,
-    CheckStaticRecursion,
     ResolveLifetimes,
     RegionResolveCrate,
-    CheckLoops,
     PluginRegistrar,
     StabilityIndex,
     CollectItem(D),
     CollectItemSig(D),
     Coherence,
-    EffectCheck,
-    Liveness,
     Resolve,
     EntryPoint,
     CheckEntryFn,
@@ -216,15 +212,11 @@ impl<D: Clone + Debug> DepNode<D> {
             MirKrate => Some(MirKrate),
             TypeckBodiesKrate => Some(TypeckBodiesKrate),
             CollectLanguageItems => Some(CollectLanguageItems),
-            CheckStaticRecursion => Some(CheckStaticRecursion),
             ResolveLifetimes => Some(ResolveLifetimes),
             RegionResolveCrate => Some(RegionResolveCrate),
-            CheckLoops => Some(CheckLoops),
             PluginRegistrar => Some(PluginRegistrar),
             StabilityIndex => Some(StabilityIndex),
             Coherence => Some(Coherence),
-            EffectCheck => Some(EffectCheck),
-            Liveness => Some(Liveness),
             Resolve => Some(Resolve),
             EntryPoint => Some(EntryPoint),
             CheckEntryFn => Some(CheckEntryFn),
diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs
index d7aa36b24f9..cfafec00ae2 100644
--- a/src/librustc/hir/map/mod.rs
+++ b/src/librustc/hir/map/mod.rs
@@ -442,6 +442,27 @@ impl<'hir> Map<'hir> {
         self.local_def_id(self.body_owner(id))
     }
 
+    /// Given a body owner's id, returns the `BodyId` associated with it.
+    pub fn body_owned_by(&self, id: NodeId) -> BodyId {
+        if let Some(entry) = self.find_entry(id) {
+            if let Some(body_id) = entry.associated_body() {
+                // For item-like things and closures, the associated
+                // body has its own distinct id, and that is returned
+                // by `associated_body`.
+                body_id
+            } else {
+                // For some expressions, the expression is its own body.
+                if let EntryExpr(_, expr) = entry {
+                    BodyId { node_id: expr.id }
+                } else {
+                    span_bug!(self.span(id), "id `{}` has no associated body", id);
+                }
+            }
+        } else {
+            bug!("no entry for id `{}`", id)
+        }
+    }
+
     pub fn ty_param_owner(&self, id: NodeId) -> NodeId {
         match self.get(id) {
             NodeItem(&Item { node: ItemTrait(..), .. }) => id,
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_mir.rs b/src/librustc/ich/impls_mir.rs
index 401f7e1921a..3ff8ffb3505 100644
--- a/src/librustc/ich/impls_mir.rs
+++ b/src/librustc/ich/impls_mir.rs
@@ -22,7 +22,8 @@ impl_stable_hash_for!(struct mir::SourceInfo { span, scope });
 impl_stable_hash_for!(enum mir::Mutability { Mut, Not });
 impl_stable_hash_for!(enum mir::BorrowKind { Shared, Unique, Mut });
 impl_stable_hash_for!(enum mir::LocalKind { Var, Temp, Arg, ReturnPointer });
-impl_stable_hash_for!(struct mir::LocalDecl<'tcx> { mutability, ty, name, source_info });
+impl_stable_hash_for!(struct mir::LocalDecl<'tcx> { mutability, ty, name, source_info,
+is_user_variable});
 impl_stable_hash_for!(struct mir::UpvarDecl { debug_name, by_ref });
 impl_stable_hash_for!(struct mir::BasicBlockData<'tcx> { statements, terminator, is_cleanup });
 impl_stable_hash_for!(struct mir::Terminator<'tcx> { source_info, kind });
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/infer/error_reporting/mod.rs b/src/librustc/infer/error_reporting/mod.rs
index 9fa2bc8a2a7..dcbe50de2e9 100644
--- a/src/librustc/infer/error_reporting/mod.rs
+++ b/src/librustc/infer/error_reporting/mod.rs
@@ -70,7 +70,7 @@ use ty::{self, TyCtxt, TypeFoldable};
 use ty::{Region, Issue32330};
 use ty::error::TypeError;
 use syntax_pos::{Pos, Span};
-use errors::DiagnosticBuilder;
+use errors::{DiagnosticBuilder, DiagnosticStyledString};
 
 mod note;
 
@@ -365,6 +365,262 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
         }
     }
 
+    /// Given that `other_ty` is the same as a type argument for `name` in `sub`, populate `value`
+    /// highlighting `name` and every type argument that isn't at `pos` (which is `other_ty`), and
+    /// populate `other_value` with `other_ty`.
+    ///
+    /// ```text
+    /// Foo<Bar<Qux>>
+    /// ^^^^--------^ this is highlighted
+    /// |   |
+    /// |   this type argument is exactly the same as the other type, not highlighted
+    /// this is highlighted
+    /// Bar<Qux>
+    /// -------- this type is the same as a type argument in the other type, not highlighted
+    /// ```
+    fn highlight_outer(&self,
+                       mut value: &mut DiagnosticStyledString,
+                       mut other_value: &mut DiagnosticStyledString,
+                       name: String,
+                       sub: &ty::subst::Substs<'tcx>,
+                       pos: usize,
+                       other_ty: &ty::Ty<'tcx>) {
+        // `value` and `other_value` hold two incomplete type representation for display.
+        // `name` is the path of both types being compared. `sub`
+        value.push_highlighted(name);
+        let len = sub.len();
+        if len > 0 {
+            value.push_highlighted("<");
+        }
+
+        // Output the lifetimes fot the first type
+        let lifetimes = sub.regions().map(|lifetime| {
+            let s = format!("{}", lifetime);
+            if s.is_empty() {
+                "'_".to_string()
+            } else {
+                s
+            }
+        }).collect::<Vec<_>>().join(", ");
+        if !lifetimes.is_empty() {
+            if sub.regions().count() < len {
+                value.push_normal(lifetimes + &", ");
+            } else {
+                value.push_normal(lifetimes);
+            }
+        }
+
+        // Highlight all the type arguments that aren't at `pos` and compare the type argument at
+        // `pos` and `other_ty`.
+        for (i, type_arg) in sub.types().enumerate() {
+            if i == pos {
+                let values = self.cmp(type_arg, other_ty);
+                value.0.extend((values.0).0);
+                other_value.0.extend((values.1).0);
+            } else {
+                value.push_highlighted(format!("{}", type_arg));
+            }
+
+            if len > 0 && i != len - 1 {
+                value.push_normal(", ");
+            }
+            //self.push_comma(&mut value, &mut other_value, len, i);
+        }
+        if len > 0 {
+            value.push_highlighted(">");
+        }
+    }
+
+    /// If `other_ty` is the same as a type argument present in `sub`, highlight `path` in `t1_out`,
+    /// as that is the difference to the other type.
+    ///
+    /// For the following code:
+    ///
+    /// ```norun
+    /// let x: Foo<Bar<Qux>> = foo::<Bar<Qux>>();
+    /// ```
+    ///
+    /// The type error output will behave in the following way:
+    ///
+    /// ```text
+    /// Foo<Bar<Qux>>
+    /// ^^^^--------^ this is highlighted
+    /// |   |
+    /// |   this type argument is exactly the same as the other type, not highlighted
+    /// this is highlighted
+    /// Bar<Qux>
+    /// -------- this type is the same as a type argument in the other type, not highlighted
+    /// ```
+    fn cmp_type_arg(&self,
+                    mut t1_out: &mut DiagnosticStyledString,
+                    mut t2_out: &mut DiagnosticStyledString,
+                    path: String,
+                    sub: &ty::subst::Substs<'tcx>,
+                    other_path: String,
+                    other_ty: &ty::Ty<'tcx>) -> Option<()> {
+        for (i, ta) in sub.types().enumerate() {
+            if &ta == other_ty {
+                self.highlight_outer(&mut t1_out, &mut t2_out, path, sub, i, &other_ty);
+                return Some(());
+            }
+            if let &ty::TyAdt(def, _) = &ta.sty {
+                let path_ = self.tcx.item_path_str(def.did.clone());
+                if path_ == other_path {
+                    self.highlight_outer(&mut t1_out, &mut t2_out, path, sub, i, &other_ty);
+                    return Some(());
+                }
+            }
+        }
+        None
+    }
+
+    /// Add a `,` to the type representation only if it is appropriate.
+    fn push_comma(&self,
+                  value: &mut DiagnosticStyledString,
+                  other_value: &mut DiagnosticStyledString,
+                  len: usize,
+                  pos: usize) {
+        if len > 0 && pos != len - 1 {
+            value.push_normal(", ");
+            other_value.push_normal(", ");
+        }
+    }
+
+    /// Compare two given types, eliding parts that are the same between them and highlighting
+    /// relevant differences, and return two representation of those types for highlighted printing.
+    fn cmp(&self, t1: ty::Ty<'tcx>, t2: ty::Ty<'tcx>)
+        -> (DiagnosticStyledString, DiagnosticStyledString)
+    {
+        match (&t1.sty, &t2.sty) {
+            (&ty::TyAdt(def1, sub1), &ty::TyAdt(def2, sub2)) => {
+                let mut values = (DiagnosticStyledString::new(), DiagnosticStyledString::new());
+                let path1 = self.tcx.item_path_str(def1.did.clone());
+                let path2 = self.tcx.item_path_str(def2.did.clone());
+                if def1.did == def2.did {
+                    // Easy case. Replace same types with `_` to shorten the output and highlight
+                    // the differing ones.
+                    //     let x: Foo<Bar, Qux> = y::<Foo<Quz, Qux>>();
+                    //     Foo<Bar, _>
+                    //     Foo<Quz, _>
+                    //         ---  ^ type argument elided
+                    //         |
+                    //         highlighted in output
+                    values.0.push_normal(path1);
+                    values.1.push_normal(path2);
+
+                    // Only draw `<...>` if there're lifetime/type arguments.
+                    let len = sub1.len();
+                    if len > 0 {
+                        values.0.push_normal("<");
+                        values.1.push_normal("<");
+                    }
+
+                    fn lifetime_display(lifetime: &Region) -> String {
+                        let s = format!("{}", lifetime);
+                        if s.is_empty() {
+                            "'_".to_string()
+                        } else {
+                            s
+                        }
+                    }
+                    // At one point we'd like to elide all lifetimes here, they are irrelevant for
+                    // all diagnostics that use this output
+                    //
+                    //     Foo<'x, '_, Bar>
+                    //     Foo<'y, '_, Qux>
+                    //         ^^  ^^  --- type arguments are not elided
+                    //         |   |
+                    //         |   elided as they were the same
+                    //         not elided, they were different, but irrelevant
+                    let lifetimes = sub1.regions().zip(sub2.regions());
+                    for (i, lifetimes) in lifetimes.enumerate() {
+                        let l1 = lifetime_display(lifetimes.0);
+                        let l2 = lifetime_display(lifetimes.1);
+                        if l1 == l2 {
+                            values.0.push_normal("'_");
+                            values.1.push_normal("'_");
+                        } else {
+                            values.0.push_highlighted(l1);
+                            values.1.push_highlighted(l2);
+                        }
+                        self.push_comma(&mut values.0, &mut values.1, len, i);
+                    }
+
+                    // We're comparing two types with the same path, so we compare the type
+                    // arguments for both. If they are the same, do not highlight and elide from the
+                    // output.
+                    //     Foo<_, Bar>
+                    //     Foo<_, Qux>
+                    //         ^ elided type as this type argument was the same in both sides
+                    let type_arguments = sub1.types().zip(sub2.types());
+                    let regions_len = sub1.regions().collect::<Vec<_>>().len();
+                    for (i, (ta1, ta2)) in type_arguments.enumerate() {
+                        let i = i + regions_len;
+                        if ta1 == ta2 {
+                            values.0.push_normal("_");
+                            values.1.push_normal("_");
+                        } else {
+                            let (x1, x2) = self.cmp(ta1, ta2);
+                            (values.0).0.extend(x1.0);
+                            (values.1).0.extend(x2.0);
+                        }
+                        self.push_comma(&mut values.0, &mut values.1, len, i);
+                    }
+
+                    // Close the type argument bracket.
+                    // Only draw `<...>` if there're lifetime/type arguments.
+                    if len > 0 {
+                        values.0.push_normal(">");
+                        values.1.push_normal(">");
+                    }
+                    values
+                } else {
+                    // Check for case:
+                    //     let x: Foo<Bar<Qux> = foo::<Bar<Qux>>();
+                    //     Foo<Bar<Qux>
+                    //         ------- this type argument is exactly the same as the other type
+                    //     Bar<Qux>
+                    if self.cmp_type_arg(&mut values.0,
+                                         &mut values.1,
+                                         path1.clone(),
+                                         sub1,
+                                         path2.clone(),
+                                         &t2).is_some() {
+                        return values;
+                    }
+                    // Check for case:
+                    //     let x: Bar<Qux> = y:<Foo<Bar<Qux>>>();
+                    //     Bar<Qux>
+                    //     Foo<Bar<Qux>>
+                    //         ------- this type argument is exactly the same as the other type
+                    if self.cmp_type_arg(&mut values.1,
+                                         &mut values.0,
+                                         path2,
+                                         sub2,
+                                         path1,
+                                         &t1).is_some() {
+                        return values;
+                    }
+
+                    // We couldn't find anything in common, highlight everything.
+                    //     let x: Bar<Qux> = y::<Foo<Zar>>();
+                    (DiagnosticStyledString::highlighted(format!("{}", t1)),
+                     DiagnosticStyledString::highlighted(format!("{}", t2)))
+                }
+            }
+            _ => {
+                if t1 == t2 {
+                    // The two types are the same, elide and don't highlight.
+                    (DiagnosticStyledString::normal("_"), DiagnosticStyledString::normal("_"))
+                } else {
+                    // We couldn't find anything in common, highlight everything.
+                    (DiagnosticStyledString::highlighted(format!("{}", t1)),
+                     DiagnosticStyledString::highlighted(format!("{}", t2)))
+                }
+            }
+        }
+    }
+
     pub fn note_type_err(&self,
                          diag: &mut DiagnosticBuilder<'tcx>,
                          cause: &ObligationCause<'tcx>,
@@ -397,14 +653,14 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
 
         if let Some((expected, found)) = expected_found {
             match (terr, is_simple_error, expected == found) {
-                (&TypeError::Sorts(ref values), false,  true) => {
+                (&TypeError::Sorts(ref values), false, true) => {
                     diag.note_expected_found_extra(
-                        &"type", &expected, &found,
+                        &"type", expected, found,
                         &format!(" ({})", values.expected.sort_string(self.tcx)),
                         &format!(" ({})", values.found.sort_string(self.tcx)));
                 }
                 (_, false,  _) => {
-                    diag.note_expected_found(&"type", &expected, &found);
+                    diag.note_expected_found(&"type", expected, found);
                 }
                 _ => (),
             }
@@ -472,26 +728,40 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
         diag
     }
 
-    /// Returns a string of the form "expected `{}`, found `{}`".
-    fn values_str(&self, values: &ValuePairs<'tcx>) -> Option<(String, String)> {
+    fn values_str(&self, values: &ValuePairs<'tcx>)
+        -> Option<(DiagnosticStyledString, DiagnosticStyledString)>
+    {
         match *values {
-            infer::Types(ref exp_found) => self.expected_found_str(exp_found),
+            infer::Types(ref exp_found) => self.expected_found_str_ty(exp_found),
             infer::TraitRefs(ref exp_found) => self.expected_found_str(exp_found),
             infer::PolyTraitRefs(ref exp_found) => self.expected_found_str(exp_found),
         }
     }
 
+    fn expected_found_str_ty(&self,
+                             exp_found: &ty::error::ExpectedFound<ty::Ty<'tcx>>)
+                             -> Option<(DiagnosticStyledString, DiagnosticStyledString)> {
+        let exp_found = self.resolve_type_vars_if_possible(exp_found);
+        if exp_found.references_error() {
+            return None;
+        }
+
+        Some(self.cmp(exp_found.expected, exp_found.found))
+    }
+
+    /// Returns a string of the form "expected `{}`, found `{}`".
     fn expected_found_str<T: fmt::Display + TypeFoldable<'tcx>>(
         &self,
         exp_found: &ty::error::ExpectedFound<T>)
-        -> Option<(String, String)>
+        -> Option<(DiagnosticStyledString, DiagnosticStyledString)>
     {
         let exp_found = self.resolve_type_vars_if_possible(exp_found);
         if exp_found.references_error() {
             return None;
         }
 
-        Some((format!("{}", exp_found.expected), format!("{}", exp_found.found)))
+        Some((DiagnosticStyledString::highlighted(format!("{}", exp_found.expected)),
+              DiagnosticStyledString::highlighted(format!("{}", exp_found.found))))
     }
 
     fn report_generic_bound_failure(&self,
diff --git a/src/librustc/infer/error_reporting/note.rs b/src/librustc/infer/error_reporting/note.rs
index 8f8b2603dad..8b753e0d22b 100644
--- a/src/librustc/infer/error_reporting/note.rs
+++ b/src/librustc/infer/error_reporting/note.rs
@@ -20,6 +20,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
         match *origin {
             infer::Subtype(ref trace) => {
                 if let Some((expected, found)) = self.values_str(&trace.values) {
+                    let expected = expected.content();
+                    let found = found.content();
                     // FIXME: do we want a "the" here?
                     err.span_note(trace.cause.span,
                                   &format!("...so that {} (expected {}, found {})",
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/effect.rs b/src/librustc/middle/effect.rs
index 5af8e7e52d8..d2b8ed8c297 100644
--- a/src/librustc/middle/effect.rs
+++ b/src/librustc/middle/effect.rs
@@ -12,7 +12,6 @@
 //! `unsafe`.
 use self::RootUnsafeContext::*;
 
-use dep_graph::DepNode;
 use ty::{self, Ty, TyCtxt};
 use ty::MethodCall;
 use lint;
@@ -241,8 +240,6 @@ impl<'a, 'tcx> Visitor<'tcx> for EffectCheckVisitor<'a, 'tcx> {
 }
 
 pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
-    let _task = tcx.dep_graph.in_task(DepNode::EffectCheck);
-
     let mut visitor = EffectCheckVisitor {
         tcx: tcx,
         tables: &ty::TypeckTables::empty(),
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/middle/liveness.rs b/src/librustc/middle/liveness.rs
index 7cae08efc0d..b7da8480c1c 100644
--- a/src/librustc/middle/liveness.rs
+++ b/src/librustc/middle/liveness.rs
@@ -109,7 +109,6 @@ use self::LoopKind::*;
 use self::LiveNodeKind::*;
 use self::VarKind::*;
 
-use dep_graph::DepNode;
 use hir::def::*;
 use ty::{self, TyCtxt, ParameterEnvironment};
 use traits::{self, Reveal};
@@ -196,7 +195,6 @@ impl<'a, 'tcx> Visitor<'tcx> for IrMaps<'a, 'tcx> {
 }
 
 pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
-    let _task = tcx.dep_graph.in_task(DepNode::Liveness);
     tcx.hir.krate().visit_all_item_likes(&mut IrMaps::new(tcx).as_deep_visitor());
     tcx.sess.abort_if_errors();
 }
diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs
index aea4684e526..9ff64b295b7 100644
--- a/src/librustc/mir/mod.rs
+++ b/src/librustc/mir/mod.rs
@@ -197,10 +197,10 @@ impl<'tcx> Mir<'tcx> {
     pub fn temps_iter<'a>(&'a self) -> impl Iterator<Item=Local> + 'a {
         (self.arg_count+1..self.local_decls.len()).filter_map(move |index| {
             let local = Local::new(index);
-            if self.local_decls[local].source_info.is_none() {
-                Some(local)
-            } else {
+            if self.local_decls[local].is_user_variable {
                 None
+            } else {
+                Some(local)
             }
         })
     }
@@ -210,10 +210,10 @@ impl<'tcx> Mir<'tcx> {
     pub fn vars_iter<'a>(&'a self) -> impl Iterator<Item=Local> + 'a {
         (self.arg_count+1..self.local_decls.len()).filter_map(move |index| {
             let local = Local::new(index);
-            if self.local_decls[local].source_info.is_none() {
-                None
-            } else {
+            if self.local_decls[local].is_user_variable {
                 Some(local)
+            } else {
+                None
             }
         })
     }
@@ -370,6 +370,9 @@ pub struct LocalDecl<'tcx> {
     /// Temporaries and the return pointer are always mutable.
     pub mutability: Mutability,
 
+    /// True if this corresponds to a user-declared local variable.
+    pub is_user_variable: bool,
+
     /// Type of this local.
     pub ty: Ty<'tcx>,
 
@@ -379,24 +382,23 @@ pub struct LocalDecl<'tcx> {
     /// to generate better debuginfo.
     pub name: Option<Name>,
 
-    /// For user-declared variables, stores their source information.
-    ///
-    /// For temporaries, this is `None`.
-    ///
-    /// This is the primary way to differentiate between user-declared
-    /// variables and compiler-generated temporaries.
-    pub source_info: Option<SourceInfo>,
+    /// Source info of the local.
+    pub source_info: SourceInfo,
 }
 
 impl<'tcx> LocalDecl<'tcx> {
     /// Create a new `LocalDecl` for a temporary.
     #[inline]
-    pub fn new_temp(ty: Ty<'tcx>) -> Self {
+    pub fn new_temp(ty: Ty<'tcx>, span: Span) -> Self {
         LocalDecl {
             mutability: Mutability::Mut,
             ty: ty,
             name: None,
-            source_info: None,
+            source_info: SourceInfo {
+                span: span,
+                scope: ARGUMENT_VISIBILITY_SCOPE
+            },
+            is_user_variable: false
         }
     }
 
@@ -404,12 +406,16 @@ impl<'tcx> LocalDecl<'tcx> {
     ///
     /// This must be inserted into the `local_decls` list as the first local.
     #[inline]
-    pub fn new_return_pointer(return_ty: Ty) -> LocalDecl {
+    pub fn new_return_pointer(return_ty: Ty, span: Span) -> LocalDecl {
         LocalDecl {
             mutability: Mutability::Mut,
             ty: return_ty,
-            source_info: None,
+            source_info: SourceInfo {
+                span: span,
+                scope: ARGUMENT_VISIBILITY_SCOPE
+            },
             name: None,     // FIXME maybe we do want some name here?
+            is_user_variable: false
         }
     }
 }
diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs
index 733ad36de90..83963de8b00 100644
--- a/src/librustc/mir/visit.rs
+++ b/src/librustc/mir/visit.rs
@@ -630,12 +630,11 @@ macro_rules! make_mir_visitor {
                     ref $($mutability)* ty,
                     name: _,
                     ref $($mutability)* source_info,
+                    is_user_variable: _,
                 } = *local_decl;
 
                 self.visit_ty(ty);
-                if let Some(ref $($mutability)* info) = *source_info {
-                    self.visit_source_info(info);
-                }
+                self.visit_source_info(source_info);
             }
 
             fn super_visibility_scope(&mut self,
diff --git a/src/librustc/ty/maps.rs b/src/librustc/ty/maps.rs
index 823bdc9e092..868ccad8a3a 100644
--- a/src/librustc/ty/maps.rs
+++ b/src/librustc/ty/maps.rs
@@ -429,6 +429,8 @@ define_maps! { <'tcx>
 
     pub coherent_trait: coherent_trait_dep_node((CrateNum, DefId)) -> (),
 
+    pub borrowck: BorrowCheck(DefId) -> (),
+
     /// Gets a complete map from all types to their inherent impls.
     /// Not meant to be used directly outside of coherence.
     /// (Defined only for LOCAL_CRATE)
diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs
index a2c356c20db..bbeb1f1fe5f 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> {}
@@ -2224,7 +2241,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
     /// `DefId` is really just an interned def-path).
     ///
     /// Note that if `id` is not local to this crate, the result will
-    //  be a non-local `DefPath`.
+    ///  be a non-local `DefPath`.
     pub fn def_path(self, id: DefId) -> hir_map::DefPath {
         if id.is_local() {
             self.hir.def_path(id)
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_borrowck/borrowck/mir/elaborate_drops.rs b/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs
index 713e6566662..ca313622a3a 100644
--- a/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs
+++ b/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs
@@ -307,12 +307,12 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
         data
     }
 
-    fn create_drop_flag(&mut self, index: MovePathIndex) {
+    fn create_drop_flag(&mut self, index: MovePathIndex, span: Span) {
         let tcx = self.tcx;
         let patch = &mut self.patch;
         debug!("create_drop_flag({:?})", self.mir.span);
         self.drop_flags.entry(index).or_insert_with(|| {
-            patch.new_temp(tcx.types.bool)
+            patch.new_temp(tcx.types.bool, span)
         });
     }
 
@@ -374,7 +374,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
                 debug!("collect_drop_flags: collecting {:?} from {:?}@{:?} - {:?}",
                        child, location, path, (maybe_live, maybe_dead));
                 if maybe_live && maybe_dead {
-                    self.create_drop_flag(child)
+                    self.create_drop_flag(child, terminator.source_info.span)
                 }
             });
         }
diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs
index 0915c57b588..142286bd834 100644
--- a/src/librustc_borrowck/borrowck/mod.rs
+++ b/src/librustc_borrowck/borrowck/mod.rs
@@ -22,7 +22,6 @@ pub use self::mir::elaborate_drops::ElaborateDrops;
 
 use self::InteriorKind::*;
 
-use rustc::dep_graph::DepNode;
 use rustc::hir::map as hir_map;
 use rustc::hir::map::blocks::FnLikeNode;
 use rustc::cfg;
@@ -37,12 +36,13 @@ use rustc::middle::mem_categorization::Categorization;
 use rustc::middle::mem_categorization::ImmutabilityBlame;
 use rustc::middle::region;
 use rustc::ty::{self, TyCtxt};
+use rustc::ty::maps::Providers;
 
 use std::fmt;
 use std::rc::Rc;
 use std::hash::{Hash, Hasher};
 use syntax::ast;
-use syntax_pos::{MultiSpan, Span};
+use syntax_pos::{DUMMY_SP, MultiSpan, Span};
 use errors::DiagnosticBuilder;
 
 use rustc::hir;
@@ -62,16 +62,16 @@ pub struct LoanDataFlowOperator;
 pub type LoanDataFlow<'a, 'tcx> = DataFlowContext<'a, 'tcx, LoanDataFlowOperator>;
 
 pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
-    tcx.dep_graph.with_task(DepNode::BorrowCheckKrate, tcx, (), check_crate_task);
-
-    fn check_crate_task<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, (): ()) {
-        tcx.visit_all_bodies_in_krate(|body_owner_def_id, body_id| {
-            tcx.dep_graph.with_task(DepNode::BorrowCheck(body_owner_def_id),
-                                    tcx,
-                                    body_id,
-                                    borrowck_fn);
-        });
-    }
+    tcx.visit_all_bodies_in_krate(|body_owner_def_id, _body_id| {
+        ty::queries::borrowck::get(tcx, DUMMY_SP, body_owner_def_id);
+    });
+}
+
+pub fn provide(providers: &mut Providers) {
+    *providers = Providers {
+        borrowck,
+        ..*providers
+    };
 }
 
 /// Collection of conclusions determined via borrow checker analyses.
@@ -81,11 +81,11 @@ pub struct AnalysisData<'a, 'tcx: 'a> {
     pub move_data: move_data::FlowedMoveData<'a, 'tcx>,
 }
 
-fn borrowck_fn<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, body_id: hir::BodyId) {
-    debug!("borrowck_fn(body_id={:?})", body_id);
+fn borrowck<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, owner_def_id: DefId) {
+    debug!("borrowck(body_owner_def_id={:?})", owner_def_id);
 
-    let owner_id = tcx.hir.body_owner(body_id);
-    let owner_def_id = tcx.hir.local_def_id(owner_id);
+    let owner_id = tcx.hir.as_local_node_id(owner_def_id).unwrap();
+    let body_id = tcx.hir.body_owned_by(owner_id);
     let attributes = tcx.get_attrs(owner_def_id);
     let tables = tcx.item_tables(owner_def_id);
 
diff --git a/src/librustc_borrowck/lib.rs b/src/librustc_borrowck/lib.rs
index d3b22884a3d..a1d3357faf5 100644
--- a/src/librustc_borrowck/lib.rs
+++ b/src/librustc_borrowck/lib.rs
@@ -51,4 +51,6 @@ mod borrowck;
 
 pub mod graphviz;
 
+pub use borrowck::provide;
+
 __build_diagnostic_array! { librustc_borrowck, DIAGNOSTICS }
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 bdb05d06b0b..20ae561431b 100644
--- a/src/librustc_driver/driver.rs
+++ b/src/librustc_driver/driver.rs
@@ -35,7 +35,7 @@ use rustc_typeck as typeck;
 use rustc_privacy;
 use rustc_plugin::registry::Registry;
 use rustc_plugin as plugin;
-use rustc_passes::{ast_validation, no_asm, loops, consts, rvalues,
+use rustc_passes::{ast_validation, no_asm, loops, consts,
                    static_recursion, hir_stats, mir_stats};
 use rustc_const_eval::check_match;
 use super::Compilation;
@@ -891,6 +891,7 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session,
     let mut local_providers = ty::maps::Providers::default();
     mir::provide(&mut local_providers);
     rustc_privacy::provide(&mut local_providers);
+    borrowck::provide(&mut local_providers);
     typeck::provide(&mut local_providers);
     ty::provide(&mut local_providers);
     reachable::provide(&mut local_providers);
@@ -958,10 +959,6 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session,
              || middle::liveness::check_crate(tcx));
 
         time(time_passes,
-             "rvalue checking",
-             || rvalues::check_crate(tcx));
-
-        time(time_passes,
              "MIR dump",
              || mir::mir_map::build_mir_for_crate(tcx));
 
@@ -976,8 +973,8 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session,
             // in stage 4 below.
             passes.push_hook(box mir::transform::dump_mir::DumpMir);
             passes.push_pass(box mir::transform::simplify::SimplifyCfg::new("initial"));
-            passes.push_pass(box mir::transform::qualify_consts::QualifyAndPromoteConstants);
             passes.push_pass(box mir::transform::type_check::TypeckMir);
+            passes.push_pass(box mir::transform::qualify_consts::QualifyAndPromoteConstants);
             passes.push_pass(
                 box mir::transform::simplify_branches::SimplifyBranches::new("initial"));
             passes.push_pass(box mir::transform::simplify::SimplifyCfg::new("qualify-consts"));
@@ -1083,6 +1080,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_errors/diagnostic.rs b/src/librustc_errors/diagnostic.rs
index 1b77ead92de..9715ace3e2e 100644
--- a/src/librustc_errors/diagnostic.rs
+++ b/src/librustc_errors/diagnostic.rs
@@ -35,6 +35,46 @@ pub struct SubDiagnostic {
     pub render_span: Option<RenderSpan>,
 }
 
+#[derive(PartialEq, Eq)]
+pub struct DiagnosticStyledString(pub Vec<StringPart>);
+
+impl DiagnosticStyledString {
+    pub fn new() -> DiagnosticStyledString {
+        DiagnosticStyledString(vec![])
+    }
+    pub fn push_normal<S: Into<String>>(&mut self, t: S) {
+        self.0.push(StringPart::Normal(t.into()));
+    }
+    pub fn push_highlighted<S: Into<String>>(&mut self, t: S) {
+        self.0.push(StringPart::Highlighted(t.into()));
+    }
+    pub fn normal<S: Into<String>>(t: S) -> DiagnosticStyledString {
+        DiagnosticStyledString(vec![StringPart::Normal(t.into())])
+    }
+
+    pub fn highlighted<S: Into<String>>(t: S) -> DiagnosticStyledString {
+        DiagnosticStyledString(vec![StringPart::Highlighted(t.into())])
+    }
+
+    pub fn content(&self) -> String {
+        self.0.iter().map(|x| x.content()).collect::<String>()
+    }
+}
+
+#[derive(PartialEq, Eq)]
+pub enum StringPart {
+    Normal(String),
+    Highlighted(String),
+}
+
+impl StringPart {
+    pub fn content(&self) -> String {
+        match self {
+            &StringPart::Normal(ref s) | & StringPart::Highlighted(ref s) => s.to_owned()
+        }
+    }
+}
+
 impl Diagnostic {
     pub fn new(level: Level, message: &str) -> Self {
         Diagnostic::new_with_code(level, None, message)
@@ -81,8 +121,8 @@ impl Diagnostic {
 
     pub fn note_expected_found(&mut self,
                                label: &fmt::Display,
-                               expected: &fmt::Display,
-                               found: &fmt::Display)
+                               expected: DiagnosticStyledString,
+                               found: DiagnosticStyledString)
                                -> &mut Self
     {
         self.note_expected_found_extra(label, expected, found, &"", &"")
@@ -90,21 +130,29 @@ impl Diagnostic {
 
     pub fn note_expected_found_extra(&mut self,
                                      label: &fmt::Display,
-                                     expected: &fmt::Display,
-                                     found: &fmt::Display,
+                                     expected: DiagnosticStyledString,
+                                     found: DiagnosticStyledString,
                                      expected_extra: &fmt::Display,
                                      found_extra: &fmt::Display)
                                      -> &mut Self
     {
+        let mut msg: Vec<_> = vec![(format!("expected {} `", label), Style::NoStyle)];
+        msg.extend(expected.0.iter()
+                   .map(|x| match *x {
+                       StringPart::Normal(ref s) => (s.to_owned(), Style::NoStyle),
+                       StringPart::Highlighted(ref s) => (s.to_owned(), Style::Highlight),
+                   }));
+        msg.push((format!("`{}\n", expected_extra), Style::NoStyle));
+        msg.push((format!("   found {} `", label), Style::NoStyle));
+        msg.extend(found.0.iter()
+                   .map(|x| match *x {
+                       StringPart::Normal(ref s) => (s.to_owned(), Style::NoStyle),
+                       StringPart::Highlighted(ref s) => (s.to_owned(), Style::Highlight),
+                   }));
+        msg.push((format!("`{}", found_extra), Style::NoStyle));
+
         // For now, just attach these as notes
-        self.highlighted_note(vec![
-            (format!("expected {} `", label), Style::NoStyle),
-            (format!("{}", expected), Style::Highlight),
-            (format!("`{}\n", expected_extra), Style::NoStyle),
-            (format!("   found {} `", label), Style::NoStyle),
-            (format!("{}", found), Style::Highlight),
-            (format!("`{}", found_extra), Style::NoStyle),
-        ]);
+        self.highlighted_note(msg);
         self
     }
 
diff --git a/src/librustc_errors/diagnostic_builder.rs b/src/librustc_errors/diagnostic_builder.rs
index 7dfea6b8951..7b27f13951b 100644
--- a/src/librustc_errors/diagnostic_builder.rs
+++ b/src/librustc_errors/diagnostic_builder.rs
@@ -9,6 +9,8 @@
 // except according to those terms.
 
 use Diagnostic;
+use DiagnosticStyledString;
+
 use Level;
 use Handler;
 use std::fmt::{self, Debug};
@@ -115,14 +117,14 @@ impl<'a> DiagnosticBuilder<'a> {
 
     forward!(pub fn note_expected_found(&mut self,
                                         label: &fmt::Display,
-                                        expected: &fmt::Display,
-                                        found: &fmt::Display)
+                                        expected: DiagnosticStyledString,
+                                        found: DiagnosticStyledString)
                                         -> &mut Self);
 
     forward!(pub fn note_expected_found_extra(&mut self,
                                               label: &fmt::Display,
-                                              expected: &fmt::Display,
-                                              found: &fmt::Display,
+                                              expected: DiagnosticStyledString,
+                                              found: DiagnosticStyledString,
                                               expected_extra: &fmt::Display,
                                               found_extra: &fmt::Display)
                                               -> &mut Self);
diff --git a/src/librustc_errors/lib.rs b/src/librustc_errors/lib.rs
index 2efdaa57fba..da29e354a70 100644
--- a/src/librustc_errors/lib.rs
+++ b/src/librustc_errors/lib.rs
@@ -203,7 +203,7 @@ impl error::Error for ExplicitBug {
     }
 }
 
-pub use diagnostic::{Diagnostic, SubDiagnostic};
+pub use diagnostic::{Diagnostic, SubDiagnostic, DiagnosticStyledString, StringPart};
 pub use diagnostic_builder::DiagnosticBuilder;
 
 /// A handler deals with errors; certain errors
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_mir/build/expr/as_lvalue.rs b/src/librustc_mir/build/expr/as_lvalue.rs
index 1cd9a1b25ba..df2841a6682 100644
--- a/src/librustc_mir/build/expr/as_lvalue.rs
+++ b/src/librustc_mir/build/expr/as_lvalue.rs
@@ -62,7 +62,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                 let idx = unpack!(block = this.as_operand(block, None, index));
 
                 // bounds check:
-                let (len, lt) = (this.temp(usize_ty.clone()), this.temp(bool_ty));
+                let (len, lt) = (this.temp(usize_ty.clone(), expr_span),
+                                 this.temp(bool_ty, expr_span));
                 this.cfg.push_assign(block, source_info, // len = len(slice)
                                      &len, Rvalue::Len(slice.clone()));
                 this.cfg.push_assign(block, source_info, // lt = idx < len
diff --git a/src/librustc_mir/build/expr/as_rvalue.rs b/src/librustc_mir/build/expr/as_rvalue.rs
index 6694107a8d4..fb547332c5f 100644
--- a/src/librustc_mir/build/expr/as_rvalue.rs
+++ b/src/librustc_mir/build/expr/as_rvalue.rs
@@ -82,7 +82,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                     let bool_ty = this.hir.bool_ty();
 
                     let minval = this.minval_literal(expr_span, expr.ty);
-                    let is_min = this.temp(bool_ty);
+                    let is_min = this.temp(bool_ty, expr_span);
 
                     this.cfg.push_assign(block, source_info, &is_min,
                                          Rvalue::BinaryOp(BinOp::Eq, arg.clone(), minval));
@@ -95,7 +95,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
             }
             ExprKind::Box { value, value_extents } => {
                 let value = this.hir.mirror(value);
-                let result = this.temp(expr.ty);
+                let result = this.temp(expr.ty, expr_span);
                 // to start, malloc some memory of suitable type (thus far, uninitialized):
                 this.cfg.push_assign(block, source_info, &result, Rvalue::Box(value.ty));
                 this.in_scope(value_extents, block, |this| {
@@ -260,7 +260,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
         let bool_ty = self.hir.bool_ty();
         if self.hir.check_overflow() && op.is_checkable() && ty.is_integral() {
             let result_tup = self.hir.tcx().intern_tup(&[ty, bool_ty], false);
-            let result_value = self.temp(result_tup);
+            let result_value = self.temp(result_tup, span);
 
             self.cfg.push_assign(block, source_info,
                                  &result_value, Rvalue::CheckedBinaryOp(op,
@@ -301,7 +301,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                 };
 
                 // Check for / 0
-                let is_zero = self.temp(bool_ty);
+                let is_zero = self.temp(bool_ty, span);
                 let zero = self.zero_literal(span, ty);
                 self.cfg.push_assign(block, source_info, &is_zero,
                                      Rvalue::BinaryOp(BinOp::Eq, rhs.clone(), zero));
@@ -315,9 +315,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                     let neg_1 = self.neg_1_literal(span, ty);
                     let min = self.minval_literal(span, ty);
 
-                    let is_neg_1 = self.temp(bool_ty);
-                    let is_min   = self.temp(bool_ty);
-                    let of       = self.temp(bool_ty);
+                    let is_neg_1 = self.temp(bool_ty, span);
+                    let is_min   = self.temp(bool_ty, span);
+                    let of       = self.temp(bool_ty, span);
 
                     // this does (rhs == -1) & (lhs == MIN). It could short-circuit instead
 
diff --git a/src/librustc_mir/build/expr/as_temp.rs b/src/librustc_mir/build/expr/as_temp.rs
index 42d9ab4d2bf..e4598b41438 100644
--- a/src/librustc_mir/build/expr/as_temp.rs
+++ b/src/librustc_mir/build/expr/as_temp.rs
@@ -44,8 +44,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
         }
 
         let expr_ty = expr.ty.clone();
-        let temp = this.temp(expr_ty.clone());
         let expr_span = expr.span;
+        let temp = this.temp(expr_ty.clone(), expr_span);
         let source_info = this.source_info(expr_span);
 
         if expr.temp_lifetime_was_shrunk && this.hir.needs_drop(expr_ty) {
diff --git a/src/librustc_mir/build/expr/stmt.rs b/src/librustc_mir/build/expr/stmt.rs
index 7336da654c1..c03432312b0 100644
--- a/src/librustc_mir/build/expr/stmt.rs
+++ b/src/librustc_mir/build/expr/stmt.rs
@@ -138,7 +138,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
             }
             _ => {
                 let expr_ty = expr.ty;
-                let temp = this.temp(expr.ty.clone());
+                let temp = this.temp(expr.ty.clone(), expr_span);
                 unpack!(block = this.into(&temp, block, expr));
                 unpack!(block = this.build_drop(block, expr_span, temp, expr_ty));
                 block.unit()
diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs
index 705eb1f5660..ddeec1fe6d0 100644
--- a/src/librustc_mir/build/matches/mod.rs
+++ b/src/librustc_mir/build/matches/mod.rs
@@ -710,7 +710,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
             mutability: mutability,
             ty: var_ty.clone(),
             name: Some(name),
-            source_info: Some(source_info),
+            source_info: source_info,
+            is_user_variable: true,
         });
         self.var_indices.insert(var_id, var);
 
diff --git a/src/librustc_mir/build/matches/test.rs b/src/librustc_mir/build/matches/test.rs
index f4fdf8ade90..5fece4d6a5d 100644
--- a/src/librustc_mir/build/matches/test.rs
+++ b/src/librustc_mir/build/matches/test.rs
@@ -210,7 +210,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                 debug!("num_enum_variants: {}, tested variants: {:?}, variants: {:?}",
                        num_enum_variants, values, variants);
                 let discr_ty = adt_def.repr.discr_type().to_ty(tcx);
-                let discr = self.temp(discr_ty);
+                let discr = self.temp(discr_ty, test.span);
                 self.cfg.push_assign(block, source_info, &discr,
                                      Rvalue::Discriminant(lvalue.clone()));
                 assert_eq!(values.len() + 1, targets.len());
@@ -270,7 +270,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                     if let ty::TyRef(region, mt) = ty.sty {
                         if let ty::TyArray(_, _) = mt.ty.sty {
                             ty = tcx.mk_imm_ref(region, tcx.mk_slice(tcx.types.u8));
-                            let val_slice = self.temp(ty);
+                            let val_slice = self.temp(ty, test.span);
                             self.cfg.push_assign(block, source_info, &val_slice,
                                                  Rvalue::Cast(CastKind::Unsize, val, ty));
                             val = Operand::Consume(val_slice);
@@ -285,7 +285,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                         value: value.clone()
                     });
 
-                    let slice = self.temp(ty);
+                    let slice = self.temp(ty, test.span);
                     self.cfg.push_assign(block, source_info, &slice,
                                          Rvalue::Cast(CastKind::Unsize, array, ty));
                     Operand::Consume(slice)
@@ -304,7 +304,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                     let (mty, method) = self.hir.trait_method(eq_def_id, "eq", ty, &[ty]);
 
                     let bool_ty = self.hir.bool_ty();
-                    let eq_result = self.temp(bool_ty);
+                    let eq_result = self.temp(bool_ty, test.span);
                     let eq_block = self.cfg.start_new_block();
                     let cleanup = self.diverge_cleanup();
                     self.cfg.terminate(block, source_info, TerminatorKind::Call {
@@ -349,7 +349,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
 
             TestKind::Len { len, op } => {
                 let (usize_ty, bool_ty) = (self.hir.usize_ty(), self.hir.bool_ty());
-                let (actual, result) = (self.temp(usize_ty), self.temp(bool_ty));
+                let (actual, result) = (self.temp(usize_ty, test.span),
+                                        self.temp(bool_ty, test.span));
 
                 // actual = len(lvalue)
                 self.cfg.push_assign(block, source_info,
@@ -383,7 +384,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                left: Operand<'tcx>,
                right: Operand<'tcx>) -> BasicBlock {
         let bool_ty = self.hir.bool_ty();
-        let result = self.temp(bool_ty);
+        let result = self.temp(bool_ty, span);
 
         // result = op(left, right)
         let source_info = self.source_info(span);
diff --git a/src/librustc_mir/build/misc.rs b/src/librustc_mir/build/misc.rs
index 99aa5cb0fa8..35a8b245f2b 100644
--- a/src/librustc_mir/build/misc.rs
+++ b/src/librustc_mir/build/misc.rs
@@ -27,8 +27,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
     ///
     /// NB: **No cleanup is scheduled for this temporary.** You should
     /// call `schedule_drop` once the temporary is initialized.
-    pub fn temp(&mut self, ty: Ty<'tcx>) -> Lvalue<'tcx> {
-        let temp = self.local_decls.push(LocalDecl::new_temp(ty));
+    pub fn temp(&mut self, ty: Ty<'tcx>, span: Span) -> Lvalue<'tcx> {
+        let temp = self.local_decls.push(LocalDecl::new_temp(ty, span));
         let lvalue = Lvalue::Local(temp);
         debug!("temp: created temp {:?} with type {:?}",
                lvalue, self.local_decls[temp].ty);
@@ -106,7 +106,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                       value: u64)
                       -> Lvalue<'tcx> {
         let usize_ty = self.hir.usize_ty();
-        let temp = self.temp(usize_ty);
+        let temp = self.temp(usize_ty, source_info.span);
         self.cfg.push_assign_constant(
             block, source_info, &temp,
             Constant {
diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs
index db03a1c68f7..ef3fa23500b 100644
--- a/src/librustc_mir/build/mod.rs
+++ b/src/librustc_mir/build/mod.rs
@@ -249,7 +249,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
             visibility_scopes: IndexVec::new(),
             visibility_scope: ARGUMENT_VISIBILITY_SCOPE,
             breakable_scopes: vec![],
-            local_decls: IndexVec::from_elem_n(LocalDecl::new_return_pointer(return_ty), 1),
+            local_decls: IndexVec::from_elem_n(LocalDecl::new_return_pointer(return_ty,
+                                                                             span), 1),
             var_indices: NodeMap(),
             unit_temp: None,
             cached_resume_block: None,
@@ -304,8 +305,12 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
             self.local_decls.push(LocalDecl {
                 mutability: Mutability::Not,
                 ty: ty,
-                source_info: None,
+                source_info: SourceInfo {
+                    scope: ARGUMENT_VISIBILITY_SCOPE,
+                    span: pattern.map_or(self.fn_span, |pat| pat.span)
+                },
                 name: name,
+                is_user_variable: false,
             });
         }
 
@@ -341,7 +346,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
             Some(ref tmp) => tmp.clone(),
             None => {
                 let ty = self.hir.unit_ty();
-                let tmp = self.temp(ty);
+                let fn_span = self.fn_span;
+                let tmp = self.temp(ty, fn_span);
                 self.unit_temp = Some(tmp.clone());
                 tmp
             }
diff --git a/src/librustc_mir/diagnostics.rs b/src/librustc_mir/diagnostics.rs
index eb16812af9b..bb07081fe43 100644
--- a/src/librustc_mir/diagnostics.rs
+++ b/src/librustc_mir/diagnostics.rs
@@ -244,6 +244,39 @@ let baz: bool = { (&FOO as *const i32) == (&BAR as *const i32) };
 ```
 "##,
 
+E0161: r##"
+A value was moved. However, its size was not known at compile time, and only
+values of a known size can be moved.
+
+Erroneous code example:
+
+```compile_fail
+#![feature(box_syntax)]
+
+fn main() {
+    let array: &[isize] = &[1, 2, 3];
+    let _x: Box<[isize]> = box *array;
+    // error: cannot move a value of type [isize]: the size of [isize] cannot
+    //        be statically determined
+}
+```
+
+In Rust, you can only move a value when its size is known at compile time.
+
+To work around this restriction, consider "hiding" the value behind a reference:
+either `&x` or `&mut x`. Since a reference has a fixed size, this lets you move
+it around as usual. Example:
+
+```
+#![feature(box_syntax)]
+
+fn main() {
+    let array: &[isize] = &[1, 2, 3];
+    let _x: Box<&[isize]> = box array; // ok!
+}
+```
+"##,
+
 E0396: r##"
 The value behind a raw pointer can't be determined at compile-time
 (or even link-time), which means it can't be used in a constant
diff --git a/src/librustc_mir/shim.rs b/src/librustc_mir/shim.rs
index 63d20be88fe..0cec84d16a8 100644
--- a/src/librustc_mir/shim.rs
+++ b/src/librustc_mir/shim.rs
@@ -137,16 +137,20 @@ enum CallKind {
     Direct(DefId),
 }
 
-fn temp_decl(mutability: Mutability, ty: Ty) -> LocalDecl {
-    LocalDecl { mutability, ty, name: None, source_info: None }
+fn temp_decl(mutability: Mutability, ty: Ty, span: Span) -> LocalDecl {
+    LocalDecl {
+        mutability, ty, name: None,
+        source_info: SourceInfo { scope: ARGUMENT_VISIBILITY_SCOPE, span },
+        is_user_variable: false
+    }
 }
 
-fn local_decls_for_sig<'tcx>(sig: &ty::FnSig<'tcx>)
+fn local_decls_for_sig<'tcx>(sig: &ty::FnSig<'tcx>, span: Span)
     -> IndexVec<Local, LocalDecl<'tcx>>
 {
-    iter::once(temp_decl(Mutability::Mut, sig.output()))
+    iter::once(temp_decl(Mutability::Mut, sig.output(), span))
         .chain(sig.inputs().iter().map(
-            |ity| temp_decl(Mutability::Not, ity)))
+            |ity| temp_decl(Mutability::Not, ity, span)))
         .collect()
 }
 
@@ -188,7 +192,7 @@ fn build_drop_shim<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>,
         ),
         IndexVec::new(),
         sig.output(),
-        local_decls_for_sig(&sig),
+        local_decls_for_sig(&sig, span),
         sig.inputs().len(),
         vec![],
         span
@@ -297,7 +301,7 @@ fn build_call_shim<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>,
 
     debug!("build_call_shim: sig={:?}", sig);
 
-    let mut local_decls = local_decls_for_sig(&sig);
+    let mut local_decls = local_decls_for_sig(&sig, span);
     let source_info = SourceInfo { span, scope: ARGUMENT_VISIBILITY_SCOPE };
 
     let rcvr_arg = Local::new(1+0);
@@ -317,7 +321,8 @@ fn build_call_shim<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>,
                 tcx.mk_ref(re_erased, ty::TypeAndMut {
                     ty: sig.inputs()[0],
                     mutbl: hir::Mutability::MutMutable
-                })
+                }),
+                span
             ));
             statements.push(Statement {
                 source_info: source_info,
@@ -442,7 +447,7 @@ pub fn build_adt_ctor<'a, 'gcx, 'tcx>(infcx: &infer::InferCtxt<'a, 'gcx, 'tcx>,
 
     debug!("build_ctor: def_id={:?} sig={:?} fields={:?}", def_id, sig, fields);
 
-    let local_decls = local_decls_for_sig(&sig);
+    let local_decls = local_decls_for_sig(&sig, span);
 
     let source_info = SourceInfo {
         span: span,
diff --git a/src/librustc_mir/transform/inline.rs b/src/librustc_mir/transform/inline.rs
index 80a9c06f11b..ac2bdaad24f 100644
--- a/src/librustc_mir/transform/inline.rs
+++ b/src/librustc_mir/transform/inline.rs
@@ -461,11 +461,8 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> {
                 for loc in callee_mir.vars_and_temps_iter() {
                     let mut local = callee_mir.local_decls[loc].clone();
 
-                    if let Some(ref mut source_info) = local.source_info {
-                        source_info.scope = scope_map[source_info.scope];
-
-                        source_info.span = callsite.location.span;
-                    }
+                    local.source_info.scope = scope_map[local.source_info.scope];
+                    local.source_info.span = callsite.location.span;
 
                     let idx = caller_mir.local_decls.push(local);
                     local_map.push(idx);
@@ -506,7 +503,7 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> {
 
                     let ty = dest.ty(caller_mir, self.tcx);
 
-                    let temp = LocalDecl::new_temp(ty);
+                    let temp = LocalDecl::new_temp(ty, callsite.location.span);
 
                     let tmp = caller_mir.local_decls.push(temp);
                     let tmp = Lvalue::Local(tmp);
@@ -590,7 +587,7 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> {
             arg.deref());
 
         let ty = arg.ty(caller_mir, self.tcx);
-        let ref_tmp = LocalDecl::new_temp(ty);
+        let ref_tmp = LocalDecl::new_temp(ty, callsite.location.span);
         let ref_tmp = caller_mir.local_decls.push(ref_tmp);
         let ref_tmp = Lvalue::Local(ref_tmp);
 
@@ -611,7 +608,7 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> {
 
         let raw_ptr = Rvalue::Cast(CastKind::Misc, Operand::Consume(ref_tmp), ptr_ty);
 
-        let cast_tmp = LocalDecl::new_temp(ptr_ty);
+        let cast_tmp = LocalDecl::new_temp(ptr_ty, callsite.location.span);
         let cast_tmp = caller_mir.local_decls.push(cast_tmp);
         let cast_tmp = Lvalue::Local(cast_tmp);
 
@@ -645,7 +642,7 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> {
 
             let ty = arg.ty(caller_mir, tcx);
 
-            let arg_tmp = LocalDecl::new_temp(ty);
+            let arg_tmp = LocalDecl::new_temp(ty, callsite.location.span);
             let arg_tmp = caller_mir.local_decls.push(arg_tmp);
             let arg_tmp = Lvalue::Local(arg_tmp);
 
diff --git a/src/librustc_mir/transform/promote_consts.rs b/src/librustc_mir/transform/promote_consts.rs
index 57cf4b1e8b0..ed9a0d3809f 100644
--- a/src/librustc_mir/transform/promote_consts.rs
+++ b/src/librustc_mir/transform/promote_consts.rs
@@ -208,7 +208,8 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
 
         let no_stmts = self.source[loc.block].statements.len();
         let new_temp = self.promoted.local_decls.push(
-            LocalDecl::new_temp(self.source.local_decls[temp].ty));
+            LocalDecl::new_temp(self.source.local_decls[temp].ty,
+                                self.source.local_decls[temp].source_info.span));
 
         debug!("promote({:?} @ {:?}/{:?}, {:?})",
                temp, loc, no_stmts, self.keep_original);
@@ -379,7 +380,8 @@ pub fn promote_candidates<'a, 'tcx>(mir: &mut Mir<'tcx>,
         };
 
         // Declare return pointer local
-        let initial_locals = iter::once(LocalDecl::new_return_pointer(ty)).collect();
+        let initial_locals = iter::once(LocalDecl::new_return_pointer(ty, span))
+            .collect();
 
         let mut promoter = Promoter {
             promoted: Mir::new(
diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs
index 8eabe92fb98..1313b24fa74 100644
--- a/src/librustc_mir/transform/qualify_consts.rs
+++ b/src/librustc_mir/transform/qualify_consts.rs
@@ -881,7 +881,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
                 // Avoid a generic error for other uses of arguments.
                 if self.qualif.intersects(Qualif::FN_ARGUMENT) {
                     let decl = &self.mir.local_decls[index];
-                    span_err!(self.tcx.sess, decl.source_info.unwrap().span, E0022,
+                    span_err!(self.tcx.sess, decl.source_info.span, E0022,
                               "arguments of constant functions can only \
                                be immutable by-value bindings");
                     return;
diff --git a/src/librustc_mir/transform/type_check.rs b/src/librustc_mir/transform/type_check.rs
index 3d604affbfe..bfb08de56d8 100644
--- a/src/librustc_mir/transform/type_check.rs
+++ b/src/librustc_mir/transform/type_check.rs
@@ -24,6 +24,7 @@ use std::fmt;
 use syntax::ast;
 use syntax_pos::{Span, DUMMY_SP};
 
+use rustc_data_structures::fx::FxHashSet;
 use rustc_data_structures::indexed_vec::Idx;
 
 fn mirbug(tcx: TyCtxt, span: Span, msg: &str) {
@@ -87,6 +88,11 @@ impl<'a, 'b, 'gcx, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'gcx, 'tcx> {
         self.sanitize_type(rvalue, rval_ty);
     }
 
+    fn visit_local_decl(&mut self, local_decl: &LocalDecl<'tcx>) {
+        self.super_local_decl(local_decl);
+        self.sanitize_type(local_decl, local_decl.ty);
+    }
+
     fn visit_mir(&mut self, mir: &Mir<'tcx>) {
         self.sanitize_type(&"return type", mir.return_ty);
         for local_decl in &mir.local_decls {
@@ -317,6 +323,7 @@ pub struct TypeChecker<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
     fulfillment_cx: traits::FulfillmentContext<'tcx>,
     last_span: Span,
     body_id: ast::NodeId,
+    reported_errors: FxHashSet<(Ty<'tcx>, Span)>,
 }
 
 impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
@@ -326,6 +333,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
             fulfillment_cx: traits::FulfillmentContext::new(),
             last_span: DUMMY_SP,
             body_id: body_id,
+            reported_errors: FxHashSet(),
         }
     }
 
@@ -641,9 +649,43 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
         }
     }
 
-    fn typeck_mir(&mut self, mir: &Mir<'tcx>) {
+    fn check_local(&mut self, mir: &Mir<'gcx>, local: Local, local_decl: &LocalDecl<'gcx>) {
+        match mir.local_kind(local) {
+            LocalKind::ReturnPointer | LocalKind::Arg => {
+                // return values of normal functions are required to be
+                // sized by typeck, but return values of ADT constructors are
+                // not because we don't include a `Self: Sized` bounds on them.
+                //
+                // Unbound parts of arguments were never required to be Sized
+                // - maybe we should make that a warning.
+                return
+            }
+            LocalKind::Var | LocalKind::Temp => {}
+        }
+
+        let span = local_decl.source_info.span;
+        let ty = local_decl.ty;
+        if !ty.is_sized(self.tcx().global_tcx(), self.infcx.param_env(), span) {
+            // in current MIR construction, all non-control-flow rvalue
+            // expressions evaluate through `as_temp` or `into` a return
+            // slot or local, so to find all unsized rvalues it is enough
+            // to check all temps, return slots and locals.
+            if let None = self.reported_errors.replace((ty, span)) {
+                span_err!(self.tcx().sess, span, E0161,
+                          "cannot move a value of type {0}: the size of {0} \
+                           cannot be statically determined", ty);
+            }
+        }
+    }
+
+    fn typeck_mir(&mut self, mir: &Mir<'gcx>) {
         self.last_span = mir.span;
         debug!("run_on_mir: {:?}", mir.span);
+
+        for (local, local_decl) in mir.local_decls.iter_enumerated() {
+            self.check_local(mir, local, local_decl);
+        }
+
         for block in mir.basic_blocks() {
             for stmt in &block.statements {
                 if stmt.source_info.span != DUMMY_SP {
@@ -698,16 +740,18 @@ impl TypeckMir {
 impl<'tcx> MirPass<'tcx> for TypeckMir {
     fn run_pass<'a>(&mut self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
                     src: MirSource, mir: &mut Mir<'tcx>) {
-        debug!("run_pass: {}", tcx.node_path_str(src.item_id()));
+        let item_id = src.item_id();
+        let def_id = tcx.hir.local_def_id(item_id);
+        debug!("run_pass: {}", tcx.item_path_str(def_id));
 
         if tcx.sess.err_count() > 0 {
             // compiling a broken program can obviously result in a
             // broken MIR, so try not to report duplicate errors.
             return;
         }
-        let param_env = ty::ParameterEnvironment::for_item(tcx, src.item_id());
+        let param_env = ty::ParameterEnvironment::for_item(tcx, item_id);
         tcx.infer_ctxt(param_env, Reveal::UserFacing).enter(|infcx| {
-            let mut checker = TypeChecker::new(&infcx, src.item_id());
+            let mut checker = TypeChecker::new(&infcx, item_id);
             {
                 let mut verifier = TypeVerifier::new(&mut checker, mir);
                 verifier.visit_mir(mir);
diff --git a/src/librustc_mir/util/elaborate_drops.rs b/src/librustc_mir/util/elaborate_drops.rs
index ccbc6700d89..04a1fc891cf 100644
--- a/src/librustc_mir/util/elaborate_drops.rs
+++ b/src/librustc_mir/util/elaborate_drops.rs
@@ -686,7 +686,7 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D>
     }
 
     fn new_temp(&mut self, ty: Ty<'tcx>) -> Local {
-        self.elaborator.patch().new_temp(ty)
+        self.elaborator.patch().new_temp(ty, self.source_info.span)
     }
 
     fn terminator_loc(&mut self, bb: BasicBlock) -> Location {
diff --git a/src/librustc_mir/util/patch.rs b/src/librustc_mir/util/patch.rs
index 19f240da730..7898d93c22e 100644
--- a/src/librustc_mir/util/patch.rs
+++ b/src/librustc_mir/util/patch.rs
@@ -11,6 +11,7 @@
 use rustc::ty::Ty;
 use rustc::mir::*;
 use rustc_data_structures::indexed_vec::{IndexVec, Idx};
+use syntax_pos::Span;
 
 /// This struct represents a patch to MIR, which can add
 /// new statements and basic blocks and patch over block
@@ -92,10 +93,10 @@ impl<'tcx> MirPatch<'tcx> {
         }
     }
 
-    pub fn new_temp(&mut self, ty: Ty<'tcx>) -> Local {
+    pub fn new_temp(&mut self, ty: Ty<'tcx>, span: Span) -> Local {
         let index = self.next_local;
         self.next_local += 1;
-        self.new_locals.push(LocalDecl::new_temp(ty));
+        self.new_locals.push(LocalDecl::new_temp(ty, span));
         Local::new(index as usize)
     }
 
diff --git a/src/librustc_mir/util/pretty.rs b/src/librustc_mir/util/pretty.rs
index ef2bf6e5434..b202e149510 100644
--- a/src/librustc_mir/util/pretty.rs
+++ b/src/librustc_mir/util/pretty.rs
@@ -196,8 +196,8 @@ fn write_scope_tree(tcx: TyCtxt,
         // User variable types (including the user's name in a comment).
         for local in mir.vars_iter() {
             let var = &mir.local_decls[local];
-            let (name, source_info) = if var.source_info.unwrap().scope == child {
-                (var.name.unwrap(), var.source_info.unwrap())
+            let (name, source_info) = if var.source_info.scope == child {
+                (var.name.unwrap(), var.source_info)
             } else {
                 // Not a variable or not declared in this scope.
                 continue;
diff --git a/src/librustc_passes/diagnostics.rs b/src/librustc_passes/diagnostics.rs
index 5f06eadb84a..036a52d5a3d 100644
--- a/src/librustc_passes/diagnostics.rs
+++ b/src/librustc_passes/diagnostics.rs
@@ -82,39 +82,6 @@ extern {
 ```
 "##,
 
-E0161: r##"
-A value was moved. However, its size was not known at compile time, and only
-values of a known size can be moved.
-
-Erroneous code example:
-
-```compile_fail
-#![feature(box_syntax)]
-
-fn main() {
-    let array: &[isize] = &[1, 2, 3];
-    let _x: Box<[isize]> = box *array;
-    // error: cannot move a value of type [isize]: the size of [isize] cannot
-    //        be statically determined
-}
-```
-
-In Rust, you can only move a value when its size is known at compile time.
-
-To work around this restriction, consider "hiding" the value behind a reference:
-either `&x` or `&mut x`. Since a reference has a fixed size, this lets you move
-it around as usual. Example:
-
-```
-#![feature(box_syntax)]
-
-fn main() {
-    let array: &[isize] = &[1, 2, 3];
-    let _x: Box<&[isize]> = box array; // ok!
-}
-```
-"##,
-
 E0265: r##"
 This error indicates that a static or constant references itself.
 All statics and constants need to resolve to a value in an acyclic manner.
diff --git a/src/librustc_passes/lib.rs b/src/librustc_passes/lib.rs
index 7a465f0ec42..22566c813d8 100644
--- a/src/librustc_passes/lib.rs
+++ b/src/librustc_passes/lib.rs
@@ -47,5 +47,4 @@ pub mod hir_stats;
 pub mod loops;
 pub mod mir_stats;
 pub mod no_asm;
-pub mod rvalues;
 pub mod static_recursion;
diff --git a/src/librustc_passes/loops.rs b/src/librustc_passes/loops.rs
index 421181c68c4..2ea235af103 100644
--- a/src/librustc_passes/loops.rs
+++ b/src/librustc_passes/loops.rs
@@ -11,7 +11,6 @@ use self::Context::*;
 
 use rustc::session::Session;
 
-use rustc::dep_graph::DepNode;
 use rustc::hir::map::Map;
 use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap};
 use rustc::hir;
@@ -50,7 +49,6 @@ struct CheckLoopVisitor<'a, 'hir: 'a> {
 }
 
 pub fn check_crate(sess: &Session, map: &Map) {
-    let _task = map.dep_graph.in_task(DepNode::CheckLoops);
     let krate = map.krate();
     krate.visit_all_item_likes(&mut CheckLoopVisitor {
         sess: sess,
diff --git a/src/librustc_passes/rvalues.rs b/src/librustc_passes/rvalues.rs
deleted file mode 100644
index c367e71fcd2..00000000000
--- a/src/librustc_passes/rvalues.rs
+++ /dev/null
@@ -1,103 +0,0 @@
-// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// Checks that all rvalues in a crate have statically known size. check_crate
-// is the public starting point.
-
-use rustc::dep_graph::DepNode;
-use rustc::middle::expr_use_visitor as euv;
-use rustc::middle::mem_categorization as mc;
-use rustc::ty::{self, TyCtxt};
-use rustc::traits::Reveal;
-
-use rustc::hir;
-use rustc::hir::intravisit::{Visitor, NestedVisitorMap};
-use syntax::ast;
-use syntax_pos::Span;
-
-pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
-    let mut rvcx = RvalueContext { tcx: tcx };
-    tcx.visit_all_item_likes_in_krate(DepNode::RvalueCheck, &mut rvcx.as_deep_visitor());
-}
-
-struct RvalueContext<'a, 'tcx: 'a> {
-    tcx: TyCtxt<'a, 'tcx, 'tcx>,
-}
-
-impl<'a, 'tcx> Visitor<'tcx> for RvalueContext<'a, 'tcx> {
-    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
-        NestedVisitorMap::None
-    }
-
-    fn visit_nested_body(&mut self, body_id: hir::BodyId) {
-        let body = self.tcx.hir.body(body_id);
-        self.tcx.infer_ctxt(body_id, Reveal::UserFacing).enter(|infcx| {
-            let mut delegate = RvalueContextDelegate {
-                tcx: infcx.tcx,
-                param_env: &infcx.parameter_environment
-            };
-            euv::ExprUseVisitor::new(&mut delegate, &infcx).consume_body(body);
-        });
-        self.visit_body(body);
-    }
-}
-
-struct RvalueContextDelegate<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
-    tcx: TyCtxt<'a, 'gcx, 'tcx>,
-    param_env: &'a ty::ParameterEnvironment<'gcx>,
-}
-
-impl<'a, 'gcx, 'tcx> euv::Delegate<'tcx> for RvalueContextDelegate<'a, 'gcx, 'tcx> {
-    fn consume(&mut self,
-               _: ast::NodeId,
-               span: Span,
-               cmt: mc::cmt<'tcx>,
-               _: euv::ConsumeMode) {
-        debug!("consume; cmt: {:?}; type: {:?}", *cmt, cmt.ty);
-        let ty = self.tcx.lift_to_global(&cmt.ty).unwrap();
-        if !ty.is_sized(self.tcx.global_tcx(), self.param_env, span) {
-            span_err!(self.tcx.sess, span, E0161,
-                "cannot move a value of type {0}: the size of {0} cannot be statically determined",
-                ty);
-        }
-    }
-
-    fn matched_pat(&mut self,
-                   _matched_pat: &hir::Pat,
-                   _cmt: mc::cmt,
-                   _mode: euv::MatchMode) {}
-
-    fn consume_pat(&mut self,
-                   _consume_pat: &hir::Pat,
-                   _cmt: mc::cmt,
-                   _mode: euv::ConsumeMode) {
-    }
-
-    fn borrow(&mut self,
-              _borrow_id: ast::NodeId,
-              _borrow_span: Span,
-              _cmt: mc::cmt,
-              _loan_region: &'tcx ty::Region,
-              _bk: ty::BorrowKind,
-              _loan_cause: euv::LoanCause) {
-    }
-
-    fn decl_without_init(&mut self,
-                         _id: ast::NodeId,
-                         _span: Span) {
-    }
-
-    fn mutate(&mut self,
-              _assignment_id: ast::NodeId,
-              _assignment_span: Span,
-              _assignee_cmt: mc::cmt,
-              _mode: euv::MutateMode) {
-    }
-}
diff --git a/src/librustc_passes/static_recursion.rs b/src/librustc_passes/static_recursion.rs
index fc05471ead3..d0bf49b7b33 100644
--- a/src/librustc_passes/static_recursion.rs
+++ b/src/librustc_passes/static_recursion.rs
@@ -11,7 +11,6 @@
 // This compiler pass detects constants that refer to themselves
 // recursively.
 
-use rustc::dep_graph::DepNode;
 use rustc::hir::map as hir_map;
 use rustc::session::{CompileResult, Session};
 use rustc::hir::def::{Def, CtorKind};
@@ -88,8 +87,6 @@ impl<'a, 'hir: 'a> Visitor<'hir> for CheckCrateVisitor<'a, 'hir> {
 }
 
 pub fn check_crate<'hir>(sess: &Session, hir_map: &hir_map::Map<'hir>) -> CompileResult {
-    let _task = hir_map.dep_graph.in_task(DepNode::CheckStaticRecursion);
-
     let mut visitor = CheckCrateVisitor {
         sess: sess,
         hir_map: hir_map,
diff --git a/src/librustc_trans/abi.rs b/src/librustc_trans/abi.rs
index 7be80a757ca..c4fdc46d030 100644
--- a/src/librustc_trans/abi.rs
+++ b/src/librustc_trans/abi.rs
@@ -283,7 +283,7 @@ impl<'tcx> LayoutExt<'tcx> for TyLayout<'tcx> {
 
             Layout::Vector { .. } => {
                 Some(Reg {
-                    kind: RegKind::Integer,
+                    kind: RegKind::Vector,
                     size: self.size(ccx)
                 })
             }
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/cabi_x86_64.rs b/src/librustc_trans/cabi_x86_64.rs
index cbe170d8583..2daebf5cf3d 100644
--- a/src/librustc_trans/cabi_x86_64.rs
+++ b/src/librustc_trans/cabi_x86_64.rs
@@ -173,14 +173,15 @@ fn reg_component(cls: &[Class], i: &mut usize, size: u64) -> Option<Reg> {
         Class::Sse => {
             let vec_len = 1 + cls[*i+1..].iter().take_while(|&&c| c == Class::SseUp).count();
             *i += vec_len;
-            Some(match size {
-                4 => Reg::f32(),
-                8 => Reg::f64(),
-                _ => {
-                    Reg {
-                        kind: RegKind::Vector,
-                        size: Size::from_bytes(vec_len as u64 * 8)
-                    }
+            Some(if vec_len == 1 {
+                match size {
+                    4 => Reg::f32(),
+                    _ => Reg::f64()
+                }
+            } else {
+                Reg {
+                    kind: RegKind::Vector,
+                    size: Size::from_bytes(vec_len as u64 * 8)
                 }
             })
         }
diff --git a/src/librustc_trans/debuginfo/create_scope_map.rs b/src/librustc_trans/debuginfo/create_scope_map.rs
index c6f8ba7b6dc..3d074c31c8a 100644
--- a/src/librustc_trans/debuginfo/create_scope_map.rs
+++ b/src/librustc_trans/debuginfo/create_scope_map.rs
@@ -65,7 +65,7 @@ pub fn create_mir_scopes(ccx: &CrateContext, mir: &Mir, debug_context: &Function
     let mut has_variables = BitVector::new(mir.visibility_scopes.len());
     for var in mir.vars_iter() {
         let decl = &mir.local_decls[var];
-        has_variables.insert(decl.source_info.unwrap().scope.index());
+        has_variables.insert(decl.source_info.scope.index());
     }
 
     // Instantiate all scopes.
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/librustc_trans/mir/mod.rs b/src/librustc_trans/mir/mod.rs
index f4c9a136ace..c51e1fb0028 100644
--- a/src/librustc_trans/mir/mod.rs
+++ b/src/librustc_trans/mir/mod.rs
@@ -255,8 +255,7 @@ pub fn trans_mir<'a, 'tcx: 'a>(
 
             if let Some(name) = decl.name {
                 // User variable
-                let source_info = decl.source_info.unwrap();
-                let debug_scope = mircx.scopes[source_info.scope];
+                let debug_scope = mircx.scopes[decl.source_info.scope];
                 let dbg = debug_scope.is_valid() && bcx.sess().opts.debuginfo == FullDebugInfo;
 
                 if !lvalue_locals.contains(local.index()) && !dbg {
@@ -268,7 +267,7 @@ pub fn trans_mir<'a, 'tcx: 'a>(
                 assert!(!ty.has_erasable_regions());
                 let lvalue = LvalueRef::alloca(&bcx, ty, &name.as_str());
                 if dbg {
-                    let (scope, span) = mircx.debug_loc(source_info);
+                    let (scope, span) = mircx.debug_loc(decl.source_info);
                     declare_local(&bcx, &mircx.debug_context, name, ty, scope,
                         VariableAccess::DirectVariable { alloca: lvalue.llval },
                         VariableKind::LocalVariable, span);
diff --git a/src/libstd/primitive_docs.rs b/src/libstd/primitive_docs.rs
index 052340a0f25..61ff8daddf0 100644
--- a/src/libstd/primitive_docs.rs
+++ b/src/libstd/primitive_docs.rs
@@ -406,7 +406,7 @@ mod prim_slice { }
 ///
 /// This documentation describes a number of methods and trait implementations
 /// on the `str` type. For technical reasons, there is additional, separate
-/// documentation in [the `std::str` module](str/index.html) as well.
+/// documentation in the [`std::str`](str/index.html) module as well.
 ///
 /// # Examples
 ///
@@ -425,7 +425,7 @@ mod prim_slice { }
 /// # Representation
 ///
 /// A `&str` is made up of two components: a pointer to some bytes, and a
-/// length. You can look at these with the [`.as_ptr`] and [`len`] methods:
+/// length. You can look at these with the [`as_ptr`] and [`len`] methods:
 ///
 /// ```
 /// use std::slice;
@@ -452,11 +452,11 @@ mod prim_slice { }
 /// assert_eq!(s, Ok(story));
 /// ```
 ///
-/// [`.as_ptr`]: #method.as_ptr
+/// [`as_ptr`]: #method.as_ptr
 /// [`len`]: #method.len
 ///
 /// Note: This example shows the internals of `&str`. `unsafe` should not be
-/// used to get a string slice under normal circumstances. Use `.as_slice()`
+/// used to get a string slice under normal circumstances. Use `as_slice`
 /// instead.
 #[stable(feature = "rust1", since = "1.0.0")]
 mod prim_str { }
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index 58be43526fd..3b928ea93c7 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -2552,10 +2552,10 @@ impl<'a> Parser<'a> {
                   }
                   token::Literal(token::Float(n), _suf) => {
                     self.bump();
-                    let prev_span = self.prev_span;
                     let fstr = n.as_str();
-                    let mut err = self.diagnostic().struct_span_err(prev_span,
+                    let mut err = self.diagnostic().struct_span_err(self.prev_span,
                         &format!("unexpected token: `{}`", n));
+                    err.span_label(self.prev_span, &"unexpected token");
                     if fstr.chars().all(|x| "0123456789.".contains(x)) {
                         let float = match fstr.parse::<f64>().ok() {
                             Some(f) => f,
@@ -2573,7 +2573,7 @@ impl<'a> Parser<'a> {
                             word(&mut s.s, fstr.splitn(2, ".").last().unwrap())
                         });
                         err.span_suggestion(
-                            prev_span,
+                            lo.to(self.prev_span),
                             "try parenthesizing the first index",
                             sugg);
                     }
diff --git a/src/test/compile-fail/issue-41139.rs b/src/test/compile-fail/issue-41139.rs
new file mode 100644
index 00000000000..15ca151c49a
--- /dev/null
+++ b/src/test/compile-fail/issue-41139.rs
@@ -0,0 +1,18 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+trait Trait {}
+
+fn get_function<'a>() -> &'a Fn() -> Trait { panic!("") }
+
+fn main() {
+    let t : &Trait = &get_function()();
+    //~^ ERROR cannot move a value of type Trait + 'static
+}
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/test/run-make/extern-fn-struct-passing-abi/test.c b/src/test/run-make/extern-fn-struct-passing-abi/test.c
index 4253767ee76..4e09928edc6 100644
--- a/src/test/run-make/extern-fn-struct-passing-abi/test.c
+++ b/src/test/run-make/extern-fn-struct-passing-abi/test.c
@@ -38,6 +38,11 @@ struct Huge {
     int32_t e;
 };
 
+struct FloatPoint {
+    double x;
+    double y;
+};
+
 // System V x86_64 ABI:
 // a, b, c, d, e should be in registers
 // s should be byval pointer
@@ -258,3 +263,17 @@ struct Huge huge_struct(struct Huge s) {
 
     return s;
 }
+
+// System V x86_64 ABI:
+// p should be in registers
+// return should be in registers
+//
+// Win64 ABI:
+// p should be a byval pointer
+// return should be in a hidden sret pointer
+struct FloatPoint float_point(struct FloatPoint p) {
+    assert(p.x == 5.);
+    assert(p.y == -3.);
+
+    return p;
+}
diff --git a/src/test/run-make/extern-fn-struct-passing-abi/test.rs b/src/test/run-make/extern-fn-struct-passing-abi/test.rs
index b91362b8edc..ff845a644b1 100644
--- a/src/test/run-make/extern-fn-struct-passing-abi/test.rs
+++ b/src/test/run-make/extern-fn-struct-passing-abi/test.rs
@@ -46,6 +46,13 @@ struct Huge {
     e: i32
 }
 
+#[derive(Clone, Copy, Debug, PartialEq)]
+#[repr(C)]
+struct FloatPoint {
+    x: f64,
+    y: f64
+}
+
 #[link(name = "test", kind = "static")]
 extern {
     fn byval_rect(a: i32, b: i32, c: i32, d: i32, e: i32, s: Rect);
@@ -72,6 +79,8 @@ extern {
     fn sret_split_struct(a: i32, b: i32, s: Rect) -> BiggerRect;
 
     fn huge_struct(s: Huge) -> Huge;
+
+    fn float_point(p: FloatPoint) -> FloatPoint;
 }
 
 fn main() {
@@ -79,6 +88,7 @@ fn main() {
     let t = BiggerRect { s: s, a: 27834, b: 7657 };
     let u = FloatRect { a: 3489, b: 3490, c: 8. };
     let v = Huge { a: 5647, b: 5648, c: 5649, d: 5650, e: 5651 };
+    let p = FloatPoint { x: 5., y: -3. };
 
     unsafe {
         byval_rect(1, 2, 3, 4, 5, s);
@@ -94,5 +104,6 @@ fn main() {
         assert_eq!(split_ret_byval_struct(1, 2, s), s);
         assert_eq!(sret_byval_struct(1, 2, 3, 4, s), t);
         assert_eq!(sret_split_struct(1, 2, s), t);
+        assert_eq!(float_point(p), p);
     }
 }
diff --git a/src/test/ui/lifetime-errors/ex2a-push-one-existing-name.stderr b/src/test/ui/lifetime-errors/ex2a-push-one-existing-name.stderr
index 6f42a9f679a..6956a043cc6 100644
--- a/src/test/ui/lifetime-errors/ex2a-push-one-existing-name.stderr
+++ b/src/test/ui/lifetime-errors/ex2a-push-one-existing-name.stderr
@@ -4,8 +4,8 @@ error[E0308]: mismatched types
 16 |     x.push(y);
    |            ^ lifetime mismatch
    |
-   = note: expected type `Ref<'a, i32>`
-              found type `Ref<'_, i32>`
+   = note: expected type `Ref<'a, _>`
+              found type `Ref<'_, _>`
 note: the anonymous lifetime #2 defined on the body at 15:51...
   --> $DIR/ex2a-push-one-existing-name.rs:15:52
    |
diff --git a/src/test/ui/lifetime-errors/ex2b-push-no-existing-names.stderr b/src/test/ui/lifetime-errors/ex2b-push-no-existing-names.stderr
index edc1c2362de..990ae65ba98 100644
--- a/src/test/ui/lifetime-errors/ex2b-push-no-existing-names.stderr
+++ b/src/test/ui/lifetime-errors/ex2b-push-no-existing-names.stderr
@@ -4,8 +4,8 @@ error[E0308]: mismatched types
 16 |     x.push(y);
    |            ^ lifetime mismatch
    |
-   = note: expected type `Ref<'_, i32>`
-              found type `Ref<'_, i32>`
+   = note: expected type `Ref<'_, _>`
+              found type `Ref<'_, _>`
 note: the anonymous lifetime #3 defined on the body at 15:43...
   --> $DIR/ex2b-push-no-existing-names.rs:15:44
    |
diff --git a/src/test/ui/lifetime-errors/ex2c-push-inference-variable.stderr b/src/test/ui/lifetime-errors/ex2c-push-inference-variable.stderr
index 755b71d4a1d..82f6c71ec1c 100644
--- a/src/test/ui/lifetime-errors/ex2c-push-inference-variable.stderr
+++ b/src/test/ui/lifetime-errors/ex2c-push-inference-variable.stderr
@@ -27,7 +27,7 @@ note: but, the lifetime must be valid for the lifetime 'b as defined on the body
 17 | |     x.push(z);
 18 | | }
    | |_^ ...ending here
-note: ...so that expression is assignable (expected Ref<'b, i32>, found Ref<'_, i32>)
+note: ...so that expression is assignable (expected Ref<'b, _>, found Ref<'_, _>)
   --> $DIR/ex2c-push-inference-variable.rs:17:12
    |
 17 |     x.push(z);
diff --git a/src/test/ui/mismatched_types/abridged.rs b/src/test/ui/mismatched_types/abridged.rs
new file mode 100644
index 00000000000..c448ad955fa
--- /dev/null
+++ b/src/test/ui/mismatched_types/abridged.rs
@@ -0,0 +1,61 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+enum Bar {
+    Qux,
+    Zar,
+}
+
+struct Foo {
+    bar: usize,
+}
+
+struct X<T1, T2> {
+    x: T1,
+    y: T2,
+}
+
+fn a() -> Foo {
+    Some(Foo { bar: 1 })
+}
+
+fn a2() -> Foo {
+    Ok(Foo { bar: 1})
+}
+
+fn b() -> Option<Foo> {
+    Foo { bar: 1 }
+}
+
+fn c() -> Result<Foo, Bar> {
+    Foo { bar: 1 }
+}
+
+fn d() -> X<X<String, String>, String> {
+    X {
+        x: X {
+            x: "".to_string(),
+            y: 2,
+        },
+        y: 3,
+    }
+}
+
+fn e() -> X<X<String, String>, String> {
+    X {
+        x: X {
+            x: "".to_string(),
+            y: 2,
+        },
+        y: "".to_string(),
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/mismatched_types/abridged.stderr b/src/test/ui/mismatched_types/abridged.stderr
new file mode 100644
index 00000000000..c67c6113d17
--- /dev/null
+++ b/src/test/ui/mismatched_types/abridged.stderr
@@ -0,0 +1,70 @@
+error[E0308]: mismatched types
+  --> $DIR/abridged.rs:26:5
+   |
+26 |     Some(Foo { bar: 1 })
+   |     ^^^^^^^^^^^^^^^^^^^^ expected struct `Foo`, found enum `std::option::Option`
+   |
+   = note: expected type `Foo`
+              found type `std::option::Option<Foo>`
+
+error[E0308]: mismatched types
+  --> $DIR/abridged.rs:30:5
+   |
+30 |     Ok(Foo { bar: 1})
+   |     ^^^^^^^^^^^^^^^^^ expected struct `Foo`, found enum `std::result::Result`
+   |
+   = note: expected type `Foo`
+              found type `std::result::Result<Foo, _>`
+
+error[E0308]: mismatched types
+  --> $DIR/abridged.rs:34:5
+   |
+34 |     Foo { bar: 1 }
+   |     ^^^^^^^^^^^^^^ expected enum `std::option::Option`, found struct `Foo`
+   |
+   = note: expected type `std::option::Option<Foo>`
+              found type `Foo`
+
+error[E0308]: mismatched types
+  --> $DIR/abridged.rs:38:5
+   |
+38 |     Foo { bar: 1 }
+   |     ^^^^^^^^^^^^^^ expected enum `std::result::Result`, found struct `Foo`
+   |
+   = note: expected type `std::result::Result<Foo, Bar>`
+              found type `Foo`
+
+error[E0308]: mismatched types
+  --> $DIR/abridged.rs:42:5
+   |
+42 |       X {
+   |  _____^ starting here...
+43 | |         x: X {
+44 | |             x: "".to_string(),
+45 | |             y: 2,
+46 | |         },
+47 | |         y: 3,
+48 | |     }
+   | |_____^ ...ending here: expected struct `std::string::String`, found integral variable
+   |
+   = note: expected type `X<X<_, std::string::String>, std::string::String>`
+              found type `X<X<_, {integer}>, {integer}>`
+
+error[E0308]: mismatched types
+  --> $DIR/abridged.rs:52:5
+   |
+52 |       X {
+   |  _____^ starting here...
+53 | |         x: X {
+54 | |             x: "".to_string(),
+55 | |             y: 2,
+56 | |         },
+57 | |         y: "".to_string(),
+58 | |     }
+   | |_____^ ...ending here: expected struct `std::string::String`, found integral variable
+   |
+   = note: expected type `X<X<_, std::string::String>, _>`
+              found type `X<X<_, {integer}>, _>`
+
+error: aborting due to 6 previous errors
+
diff --git a/src/test/parse-fail/tuple-float-index.rs b/src/test/ui/suggestions/tuple-float-index.rs
index 57ad89ad374..8bfbd0e74db 100644
--- a/src/test/parse-fail/tuple-float-index.rs
+++ b/src/test/ui/suggestions/tuple-float-index.rs
@@ -11,7 +11,5 @@
 // compile-flags: -Z parse-only
 
 fn main () {
-    (1, (2, 3)).1.1; //~ ERROR unexpected token
-                     //~^ HELP try parenthesizing the first index
-                     //~| SUGGESTION ((1, (2, 3)).1).1
+    (1, (2, 3)).1.1;
 }
diff --git a/src/test/ui/suggestions/tuple-float-index.stderr b/src/test/ui/suggestions/tuple-float-index.stderr
new file mode 100644
index 00000000000..abe04dc1aa2
--- /dev/null
+++ b/src/test/ui/suggestions/tuple-float-index.stderr
@@ -0,0 +1,11 @@
+error: unexpected token: `1.1`
+  --> $DIR/tuple-float-index.rs:14:17
+   |
+14 |     (1, (2, 3)).1.1;
+   |                 ^^^ unexpected token
+   |
+help: try parenthesizing the first index
+   |     ((1, (2, 3)).1).1;
+
+error: aborting due to previous error
+
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);
     }
 
diff --git a/src/tools/tidy/src/main.rs b/src/tools/tidy/src/main.rs
index dee37341051..17f8b62117a 100644
--- a/src/tools/tidy/src/main.rs
+++ b/src/tools/tidy/src/main.rs
@@ -82,11 +82,9 @@ fn filter_dirs(path: &Path) -> bool {
         "src/llvm",
         "src/libbacktrace",
         "src/compiler-rt",
-        "src/rt/hoedown",
         "src/rustllvm",
         "src/rust-installer",
         "src/liblibc",
-        "src/tools/cargo",
         "src/vendor",
     ];
     skip.iter().any(|p| path.ends_with(p))