about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2019-11-20 19:15:41 +0000
committerbors <bors@rust-lang.org>2019-11-20 19:15:41 +0000
commitf1b882b55805c342e46ee4ca3beeef1d1fa2044b (patch)
treea76cffee5474f8b62ff9218cf85852304acd6cb4
parentb9cf5417892ef242c783ef963deff5436205b0f6 (diff)
parent8754409159112776e9da43c62e2e66bbfabf59ab (diff)
downloadrust-f1b882b55805c342e46ee4ca3beeef1d1fa2044b.tar.gz
rust-f1b882b55805c342e46ee4ca3beeef1d1fa2044b.zip
Auto merge of #66578 - Centril:rollup-pgz1v7t, r=Centril
Rollup of 7 pull requests

Successful merges:

 - #66060 (Making ICEs and test them in incremental)
 - #66298 (rustdoc: fixes #64305: disable search field instead of hidding it)
 - #66457 (Just derive Hashstable in librustc)
 - #66496 (rustc_metadata: Privatize more things)
 - #66514 (Fix selected crate search filter)
 - #66535 (Avoid ICE when `break`ing to an unreachable label)
 - #66573 (Ignore run-make reproducible-build-2 on Mac)

Failed merges:

r? @ghost
-rw-r--r--Cargo.lock1
-rw-r--r--src/librustc/dep_graph/dep_node.rs6
-rw-r--r--src/librustc/hir/map/definitions.rs4
-rw-r--r--src/librustc/hir/mod.rs2
-rw-r--r--src/librustc/ich/impls_hir.rs7
-rw-r--r--src/librustc/infer/outlives/free_region_map.rs6
-rw-r--r--src/librustc/lint/mod.rs17
-rw-r--r--src/librustc/middle/exported_symbols.rs7
-rw-r--r--src/librustc/middle/resolve_lifetime.rs8
-rw-r--r--src/librustc/middle/stability.rs15
-rw-r--r--src/librustc/mir/interpret/allocation.rs6
-rw-r--r--src/librustc/mir/interpret/value.rs7
-rw-r--r--src/librustc/mir/mod.rs62
-rw-r--r--src/librustc/mir/mono.rs24
-rw-r--r--src/librustc/query/mod.rs6
-rw-r--r--src/librustc/traits/query/dropck_outlives.rs13
-rw-r--r--src/librustc/traits/query/method_autoderef.rs18
-rw-r--r--src/librustc/traits/query/mod.rs4
-rw-r--r--src/librustc/traits/query/normalize.rs6
-rw-r--r--src/librustc/traits/query/type_op/ascribe_user_type.rs8
-rw-r--r--src/librustc/traits/query/type_op/eq.rs6
-rw-r--r--src/librustc/traits/query/type_op/implied_outlives_bounds.rs6
-rw-r--r--src/librustc/traits/query/type_op/normalize.rs8
-rw-r--r--src/librustc/traits/query/type_op/outlives.rs6
-rw-r--r--src/librustc/traits/query/type_op/prove_predicate.rs6
-rw-r--r--src/librustc/traits/query/type_op/subtype.rs6
-rw-r--r--src/librustc/traits/select.rs15
-rw-r--r--src/librustc/traits/specialize/specialization_graph.rs7
-rw-r--r--src/librustc/ty/binding.rs7
-rw-r--r--src/librustc/ty/mod.rs39
-rw-r--r--src/librustc/ty/sty.rs12
-rw-r--r--src/librustc_codegen_utils/lib.rs38
-rw-r--r--src/librustc_metadata/creader.rs132
-rw-r--r--src/librustc_metadata/cstore.rs100
-rw-r--r--src/librustc_metadata/locator.rs186
-rw-r--r--src/librustc_metadata/rmeta/decoder.rs180
-rw-r--r--src/librustc_metadata/rmeta/decoder/cstore_impl.rs4
-rw-r--r--src/librustc_metadata/rmeta/mod.rs23
-rw-r--r--src/librustc_mir/Cargo.toml1
-rw-r--r--src/librustc_mir/interpret/eval_context.rs8
-rw-r--r--src/librustc_mir/interpret/operand.rs5
-rw-r--r--src/librustc_mir/interpret/place.rs5
-rw-r--r--src/librustc_mir/interpret/snapshot.rs42
-rw-r--r--src/librustc_passes/liveness.rs13
-rw-r--r--src/librustdoc/html/layout.rs3
-rw-r--r--src/librustdoc/html/render.rs4
-rw-r--r--src/librustdoc/html/static/main.js33
-rw-r--r--src/librustdoc/html/static/rustdoc.css2
-rw-r--r--src/librustdoc/html/static/themes/dark.css4
-rw-r--r--src/librustdoc/html/static/themes/light.css4
-rw-r--r--src/libsyntax/feature_gate/builtin_attrs.rs5
-rw-r--r--src/libsyntax_pos/symbol.rs1
-rw-r--r--src/test/incremental/delayed_span_bug.rs8
-rw-r--r--src/test/run-make-fulldeps/reproducible-build-2/Makefile1
-rw-r--r--src/test/ui/associated-types/bound-lifetime-constrained.rs2
-rw-r--r--src/test/ui/associated-types/bound-lifetime-in-binding-only.ok.stderr2
-rw-r--r--src/test/ui/associated-types/bound-lifetime-in-binding-only.rs2
-rw-r--r--src/test/ui/associated-types/bound-lifetime-in-return-only.ok.stderr2
-rw-r--r--src/test/ui/associated-types/bound-lifetime-in-return-only.rs2
-rw-r--r--src/test/ui/associated-types/cache/project-fn-ret-contravariant.ok.stderr2
-rw-r--r--src/test/ui/associated-types/cache/project-fn-ret-contravariant.oneuse.stderr2
-rw-r--r--src/test/ui/associated-types/cache/project-fn-ret-contravariant.rs4
-rw-r--r--src/test/ui/associated-types/cache/project-fn-ret-invariant.ok.stderr2
-rw-r--r--src/test/ui/associated-types/cache/project-fn-ret-invariant.rs2
-rw-r--r--src/test/ui/associated-types/higher-ranked-projection.good.stderr2
-rw-r--r--src/test/ui/associated-types/higher-ranked-projection.rs2
-rw-r--r--src/test/ui/hr-subtype/hr-subtype.bound_a_vs_bound_a.stderr2
-rw-r--r--src/test/ui/hr-subtype/hr-subtype.bound_a_vs_bound_b.stderr2
-rw-r--r--src/test/ui/hr-subtype/hr-subtype.bound_co_a_vs_bound_co_b.stderr2
-rw-r--r--src/test/ui/hr-subtype/hr-subtype.bound_inv_a_vs_bound_inv_b.stderr2
-rw-r--r--src/test/ui/hr-subtype/hr-subtype.free_x_vs_free_x.stderr2
-rw-r--r--src/test/ui/hr-subtype/hr-subtype.rs10
-rw-r--r--src/test/ui/issues/issue-62480.rs10
-rw-r--r--src/test/ui/issues/issue-62480.stderr8
-rw-r--r--src/test/ui/proc-macro/no-macro-use-attr.rs2
-rw-r--r--src/test/ui/proc-macro/no-macro-use-attr.stderr2
-rw-r--r--src/test/ui/rfc1445/feature-gate.rs2
-rw-r--r--src/test/ui/rfc1445/feature-gate.with_gate.stderr2
-rw-r--r--src/test/ui/rustc-error.rs2
-rw-r--r--src/test/ui/rustc-error.stderr2
-rw-r--r--src/tools/compiletest/src/header.rs13
-rw-r--r--src/tools/compiletest/src/runtest.rs28
82 files changed, 590 insertions, 674 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 84e0d44d938..d5d66f89987 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -3719,6 +3719,7 @@ dependencies = [
  "rustc_errors",
  "rustc_index",
  "rustc_lexer",
+ "rustc_macros",
  "rustc_target",
  "serialize",
  "smallvec 1.0.0",
diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs
index cea790375fc..17ab0c187a2 100644
--- a/src/librustc/dep_graph/dep_node.rs
+++ b/src/librustc/dep_graph/dep_node.rs
@@ -578,7 +578,7 @@ impl<'tcx> DepNodeParams<'tcx> for HirId {
 /// the need to be mapped or unmapped. (This ensures we can serialize
 /// them even in the absence of a tcx.)
 #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash,
-         RustcEncodable, RustcDecodable)]
+         RustcEncodable, RustcDecodable, HashStable)]
 pub struct WorkProductId {
     hash: Fingerprint
 }
@@ -599,7 +599,3 @@ impl WorkProductId {
         }
     }
 }
-
-impl_stable_hash_for!(struct crate::dep_graph::WorkProductId {
-    hash
-});
diff --git a/src/librustc/hir/map/definitions.rs b/src/librustc/hir/map/definitions.rs
index 1e444e8a5b8..2b3bc37c87c 100644
--- a/src/librustc/hir/map/definitions.rs
+++ b/src/librustc/hir/map/definitions.rs
@@ -313,11 +313,9 @@ pub enum DefPathData {
 }
 
 #[derive(Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord, Debug,
-         RustcEncodable, RustcDecodable)]
+         RustcEncodable, RustcDecodable, HashStable)]
 pub struct DefPathHash(pub Fingerprint);
 
-impl_stable_hash_for!(tuple_struct DefPathHash { fingerprint });
-
 impl Borrow<Fingerprint> for DefPathHash {
     #[inline]
     fn borrow(&self) -> &Fingerprint {
diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs
index bbd3b40e1be..465673082e5 100644
--- a/src/librustc/hir/mod.rs
+++ b/src/librustc/hir/mod.rs
@@ -1215,7 +1215,7 @@ impl UnOp {
 }
 
 /// A statement.
-#[derive(RustcEncodable, RustcDecodable)]
+#[derive(RustcEncodable, RustcDecodable, HashStable)]
 pub struct Stmt {
     pub hir_id: HirId,
     pub kind: StmtKind,
diff --git a/src/librustc/ich/impls_hir.rs b/src/librustc/ich/impls_hir.rs
index c0255e5b8a4..816e93698bc 100644
--- a/src/librustc/ich/impls_hir.rs
+++ b/src/librustc/ich/impls_hir.rs
@@ -140,13 +140,6 @@ impl<'a> HashStable<StableHashingContext<'a>> for hir::Ty {
 
 impl_stable_hash_for_spanned!(hir::BinOpKind);
 
-impl_stable_hash_for!(struct hir::Stmt {
-    hir_id,
-    kind,
-    span,
-});
-
-
 impl_stable_hash_for_spanned!(ast::Name);
 
 impl<'a> HashStable<StableHashingContext<'a>> for hir::Expr {
diff --git a/src/librustc/infer/outlives/free_region_map.rs b/src/librustc/infer/outlives/free_region_map.rs
index c085df6a6e7..fd8ccce6833 100644
--- a/src/librustc/infer/outlives/free_region_map.rs
+++ b/src/librustc/infer/outlives/free_region_map.rs
@@ -1,7 +1,7 @@
 use crate::ty::{self, Lift, TyCtxt, Region};
 use rustc_data_structures::transitive_relation::TransitiveRelation;
 
-#[derive(Clone, RustcEncodable, RustcDecodable, Debug, Default)]
+#[derive(Clone, RustcEncodable, RustcDecodable, Debug, Default, HashStable)]
 pub struct FreeRegionMap<'tcx> {
     // Stores the relation `a < b`, where `a` and `b` are regions.
     //
@@ -89,10 +89,6 @@ fn is_free_or_static(r: Region<'_>) -> bool {
     }
 }
 
-impl_stable_hash_for!(struct FreeRegionMap<'tcx> {
-    relation
-});
-
 impl<'a, 'tcx> Lift<'tcx> for FreeRegionMap<'a> {
     type Lifted = FreeRegionMap<'tcx>;
     fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<FreeRegionMap<'tcx>> {
diff --git a/src/librustc/lint/mod.rs b/src/librustc/lint/mod.rs
index 11d0d0d90fa..d84102ff3c5 100644
--- a/src/librustc/lint/mod.rs
+++ b/src/librustc/lint/mod.rs
@@ -543,18 +543,11 @@ impl LintId {
 }
 
 /// Setting for how to handle a lint.
-#[derive(Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Debug, Hash)]
+#[derive(Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Debug, Hash, HashStable)]
 pub enum Level {
     Allow, Warn, Deny, Forbid,
 }
 
-impl_stable_hash_for!(enum self::Level {
-    Allow,
-    Warn,
-    Deny,
-    Forbid
-});
-
 impl Level {
     /// Converts a level to a lower-case string.
     pub fn as_str(self) -> &'static str {
@@ -590,7 +583,7 @@ impl Level {
 }
 
 /// How a lint level was set.
-#[derive(Clone, Copy, PartialEq, Eq)]
+#[derive(Clone, Copy, PartialEq, Eq, HashStable)]
 pub enum LintSource {
     /// Lint is at the default level as declared
     /// in rustc or a plugin.
@@ -603,12 +596,6 @@ pub enum LintSource {
     CommandLine(Symbol),
 }
 
-impl_stable_hash_for!(enum self::LintSource {
-    Default,
-    Node(name, span, reason),
-    CommandLine(text)
-});
-
 pub type LevelSource = (Level, LintSource);
 
 pub mod builtin;
diff --git a/src/librustc/middle/exported_symbols.rs b/src/librustc/middle/exported_symbols.rs
index 4d14299751c..7182f031824 100644
--- a/src/librustc/middle/exported_symbols.rs
+++ b/src/librustc/middle/exported_symbols.rs
@@ -11,17 +11,12 @@ use crate::ty::subst::SubstsRef;
 /// kind of crate, including cdylibs which export very few things.
 /// `Rust` will only be exported if the crate produced is a Rust
 /// dylib.
-#[derive(Eq, PartialEq, Debug, Copy, Clone, RustcEncodable, RustcDecodable)]
+#[derive(Eq, PartialEq, Debug, Copy, Clone, RustcEncodable, RustcDecodable, HashStable)]
 pub enum SymbolExportLevel {
     C,
     Rust,
 }
 
-impl_stable_hash_for!(enum self::SymbolExportLevel {
-    C,
-    Rust
-});
-
 impl SymbolExportLevel {
     pub fn is_below_threshold(self, threshold: SymbolExportLevel) -> bool {
         threshold == SymbolExportLevel::Rust // export everything from Rust dylibs
diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs
index a70fe2be96c..c13c44c413d 100644
--- a/src/librustc/middle/resolve_lifetime.rs
+++ b/src/librustc/middle/resolve_lifetime.rs
@@ -207,7 +207,7 @@ struct NamedRegionMap {
 }
 
 /// See [`NamedRegionMap`].
-#[derive(Default)]
+#[derive(Default, HashStable)]
 pub struct ResolveLifetimes {
     defs: FxHashMap<LocalDefId, FxHashMap<ItemLocalId, Region>>,
     late_bound: FxHashMap<LocalDefId, FxHashSet<ItemLocalId>>,
@@ -215,12 +215,6 @@ pub struct ResolveLifetimes {
         FxHashMap<LocalDefId, FxHashMap<ItemLocalId, Vec<ObjectLifetimeDefault>>>,
 }
 
-impl_stable_hash_for!(struct crate::middle::resolve_lifetime::ResolveLifetimes {
-    defs,
-    late_bound,
-    object_lifetime_defaults
-});
-
 struct LifetimeContext<'a, 'tcx> {
     tcx: TyCtxt<'tcx>,
     map: &'a mut NamedRegionMap,
diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs
index 8f8b4ed98bd..411a47423c5 100644
--- a/src/librustc/middle/stability.rs
+++ b/src/librustc/middle/stability.rs
@@ -52,7 +52,7 @@ enum AnnotationKind {
 }
 
 /// An entry in the `depr_map`.
-#[derive(Clone)]
+#[derive(Clone, HashStable)]
 pub struct DeprecationEntry {
     /// The metadata of the attribute associated with this entry.
     pub attr: Deprecation,
@@ -61,11 +61,6 @@ pub struct DeprecationEntry {
     origin: Option<HirId>,
 }
 
-impl_stable_hash_for!(struct self::DeprecationEntry {
-    attr,
-    origin
-});
-
 impl DeprecationEntry {
     fn local(attr: Deprecation, id: HirId) -> DeprecationEntry {
         DeprecationEntry {
@@ -90,6 +85,7 @@ impl DeprecationEntry {
 }
 
 /// A stability index, giving the stability level for items and methods.
+#[derive(HashStable)]
 pub struct Index<'tcx> {
     /// This is mostly a cache, except the stabilities of local items
     /// are filled by the annotator.
@@ -103,13 +99,6 @@ pub struct Index<'tcx> {
     active_features: FxHashSet<Symbol>,
 }
 
-impl_stable_hash_for!(struct self::Index<'tcx> {
-    stab_map,
-    depr_map,
-    staged_api,
-    active_features
-});
-
 // A private tree-walker for producing an Index.
 struct Annotator<'a, 'tcx> {
     tcx: TyCtxt<'tcx>,
diff --git a/src/librustc/mir/interpret/allocation.rs b/src/librustc/mir/interpret/allocation.rs
index aa8ac4902a8..f849361e08b 100644
--- a/src/librustc/mir/interpret/allocation.rs
+++ b/src/librustc/mir/interpret/allocation.rs
@@ -4,7 +4,6 @@ use super::{
     Pointer, InterpResult, AllocId, ScalarMaybeUndef, write_target_uint, read_target_uint, Scalar,
 };
 
-use crate::mir;
 use crate::ty::layout::{Size, Align};
 
 use rustc_data_structures::sorted_map::SortedMap;
@@ -787,14 +786,13 @@ type Block = u64;
 
 /// A bitmask where each bit refers to the byte with the same index. If the bit is `true`, the byte
 /// is defined. If it is `false` the byte is undefined.
-#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)]
+#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Hash,
+         RustcEncodable, RustcDecodable, HashStable)]
 pub struct UndefMask {
     blocks: Vec<Block>,
     len: Size,
 }
 
-impl_stable_hash_for!(struct mir::interpret::UndefMask{blocks, len});
-
 impl UndefMask {
     pub const BLOCK_SIZE: u64 = 64;
 
diff --git a/src/librustc/mir/interpret/value.rs b/src/librustc/mir/interpret/value.rs
index a0367154b75..52c72de7579 100644
--- a/src/librustc/mir/interpret/value.rs
+++ b/src/librustc/mir/interpret/value.rs
@@ -458,7 +458,7 @@ impl<Tag> From<Pointer<Tag>> for Scalar<Tag> {
     }
 }
 
-#[derive(Clone, Copy, Eq, PartialEq, RustcEncodable, RustcDecodable)]
+#[derive(Clone, Copy, Eq, PartialEq, RustcEncodable, RustcDecodable, HashStable)]
 pub enum ScalarMaybeUndef<Tag = (), Id = AllocId> {
     Scalar(Scalar<Tag, Id>),
     Undef,
@@ -583,11 +583,6 @@ impl<'tcx, Tag> ScalarMaybeUndef<Tag> {
     }
 }
 
-impl_stable_hash_for!(enum crate::mir::interpret::ScalarMaybeUndef {
-    Scalar(v),
-    Undef
-});
-
 /// Gets the bytes of a constant slice value.
 pub fn get_slice_bytes<'tcx>(cx: &impl HasDataLayout, val: ConstValue<'tcx>) -> &'tcx [u8] {
     if let ConstValue::Slice { data, start, end } = val {
diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs
index 5997e4367bf..79468b68055 100644
--- a/src/librustc/mir/mod.rs
+++ b/src/librustc/mir/mod.rs
@@ -70,7 +70,8 @@ impl<'tcx> HasLocalDecls<'tcx> for Body<'tcx> {
 /// The various "big phases" that MIR goes through.
 ///
 /// Warning: ordering of variants is significant.
-#[derive(Copy, Clone, RustcEncodable, RustcDecodable, Debug, PartialEq, Eq, PartialOrd, Ord)]
+#[derive(Copy, Clone, RustcEncodable, RustcDecodable, HashStable,
+         Debug, PartialEq, Eq, PartialOrd, Ord)]
 pub enum MirPhase {
     Build = 0,
     Const = 1,
@@ -86,7 +87,7 @@ impl MirPhase {
 }
 
 /// The lowered representation of a single function.
-#[derive(Clone, RustcEncodable, RustcDecodable, Debug, TypeFoldable)]
+#[derive(Clone, RustcEncodable, RustcDecodable, Debug, HashStable, TypeFoldable)]
 pub struct Body<'tcx> {
     /// A list of basic blocks. References to basic block use a newtyped index type `BasicBlock`
     /// that indexes into this vector.
@@ -412,24 +413,6 @@ pub enum Safety {
     ExplicitUnsafe(hir::HirId),
 }
 
-impl_stable_hash_for!(struct Body<'tcx> {
-    phase,
-    basic_blocks,
-    source_scopes,
-    source_scope_local_data,
-    yield_ty,
-    generator_drop,
-    generator_layout,
-    local_decls,
-    user_type_annotations,
-    arg_count,
-    __upvar_debuginfo_codegen_only_do_not_use,
-    spread_arg,
-    control_flow_destroyed,
-    span,
-    cache
-});
-
 impl<'tcx> Index<BasicBlock> for Body<'tcx> {
     type Output = BasicBlockData<'tcx>;
 
@@ -609,7 +592,7 @@ pub enum LocalKind {
     ReturnPointer,
 }
 
-#[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
+#[derive(Clone, Debug, RustcEncodable, RustcDecodable, HashStable)]
 pub struct VarBindingForm<'tcx> {
     /// Is variable bound via `x`, `mut x`, `ref x`, or `ref mut x`?
     pub binding_mode: ty::BindingMode,
@@ -642,7 +625,7 @@ pub enum BindingForm<'tcx> {
 }
 
 /// Represents what type of implicit self a function has, if any.
-#[derive(Clone, Copy, PartialEq, Debug, RustcEncodable, RustcDecodable)]
+#[derive(Clone, Copy, PartialEq, Debug, RustcEncodable, RustcDecodable, HashStable)]
 pub enum ImplicitSelfKind {
     /// Represents a `fn x(self);`.
     Imm,
@@ -659,28 +642,6 @@ pub enum ImplicitSelfKind {
 
 CloneTypeFoldableAndLiftImpls! { BindingForm<'tcx>, }
 
-impl_stable_hash_for!(struct self::VarBindingForm<'tcx> {
-    binding_mode,
-    opt_ty_info,
-    opt_match_place,
-    pat_span
-});
-
-impl_stable_hash_for!(enum self::ImplicitSelfKind {
-    Imm,
-    Mut,
-    ImmRef,
-    MutRef,
-    None
-});
-
-impl_stable_hash_for!(enum self::MirPhase {
-    Build,
-    Const,
-    Validated,
-    Optimized,
-});
-
 mod binding_form_impl {
     use crate::ich::StableHashingContext;
     use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
@@ -707,7 +668,7 @@ mod binding_form_impl {
 /// involved in borrow_check errors, e.g., explanations of where the
 /// temporaries come from, when their destructors are run, and/or how
 /// one might revise the code to satisfy the borrow checker's rules.
-#[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
+#[derive(Clone, Debug, RustcEncodable, RustcDecodable, HashStable)]
 pub struct BlockTailInfo {
     /// If `true`, then the value resulting from evaluating this tail
     /// expression is ignored by the block's expression context.
@@ -717,8 +678,6 @@ pub struct BlockTailInfo {
     pub tail_result_is_ignored: bool,
 }
 
-impl_stable_hash_for!(struct BlockTailInfo { tail_result_is_ignored });
-
 /// A MIR local.
 ///
 /// This can be a binding declared by the user, a temporary inserted by the compiler, a function
@@ -1746,7 +1705,8 @@ pub enum PlaceBase<'tcx> {
 }
 
 /// We store the normalized type to avoid requiring normalization when reading MIR
-#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)]
+#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash,
+         RustcEncodable, RustcDecodable, HashStable)]
 pub struct Static<'tcx> {
     pub ty: Ty<'tcx>,
     pub kind: StaticKind<'tcx>,
@@ -1768,12 +1728,6 @@ pub enum StaticKind<'tcx> {
     Static,
 }
 
-impl_stable_hash_for!(struct Static<'tcx> {
-    ty,
-    kind,
-    def_id
-});
-
 #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
 #[derive(RustcEncodable, RustcDecodable, HashStable)]
 pub enum ProjectionElem<V, T> {
diff --git a/src/librustc/mir/mono.rs b/src/librustc/mir/mono.rs
index a54635c3d51..34daf185b29 100644
--- a/src/librustc/mir/mono.rs
+++ b/src/librustc/mir/mono.rs
@@ -251,7 +251,7 @@ pub struct CodegenUnit<'tcx> {
     size_estimate: Option<usize>,
 }
 
-#[derive(Copy, Clone, PartialEq, Debug, RustcEncodable, RustcDecodable)]
+#[derive(Copy, Clone, PartialEq, Debug, RustcEncodable, RustcDecodable, HashStable)]
 pub enum Linkage {
     External,
     AvailableExternally,
@@ -266,33 +266,13 @@ pub enum Linkage {
     Common,
 }
 
-impl_stable_hash_for!(enum self::Linkage {
-    External,
-    AvailableExternally,
-    LinkOnceAny,
-    LinkOnceODR,
-    WeakAny,
-    WeakODR,
-    Appending,
-    Internal,
-    Private,
-    ExternalWeak,
-    Common
-});
-
-#[derive(Copy, Clone, PartialEq, Debug)]
+#[derive(Copy, Clone, PartialEq, Debug, HashStable)]
 pub enum Visibility {
     Default,
     Hidden,
     Protected,
 }
 
-impl_stable_hash_for!(enum self::Visibility {
-    Default,
-    Hidden,
-    Protected
-});
-
 impl<'tcx> CodegenUnit<'tcx> {
     pub fn new(name: Symbol) -> CodegenUnit<'tcx> {
         CodegenUnit {
diff --git a/src/librustc/query/mod.rs b/src/librustc/query/mod.rs
index e07726bfa2a..cd93fed8e1e 100644
--- a/src/librustc/query/mod.rs
+++ b/src/librustc/query/mod.rs
@@ -30,6 +30,12 @@ use syntax_pos::symbol::Symbol;
 // as they will raise an fatal error on query cycles instead.
 rustc_queries! {
     Other {
+        query trigger_delay_span_bug(key: DefId) -> () {
+            desc { "trigger a delay span bug" }
+        }
+    }
+
+    Other {
         /// Records the type of every item.
         query type_of(key: DefId) -> Ty<'tcx> {
             cache_on_disk_if { key.is_local() }
diff --git a/src/librustc/traits/query/dropck_outlives.rs b/src/librustc/traits/query/dropck_outlives.rs
index 93f56804a9f..785b4122d08 100644
--- a/src/librustc/traits/query/dropck_outlives.rs
+++ b/src/librustc/traits/query/dropck_outlives.rs
@@ -79,7 +79,7 @@ impl<'cx, 'tcx> At<'cx, 'tcx> {
     }
 }
 
-#[derive(Clone, Debug, Default, TypeFoldable, Lift)]
+#[derive(Clone, Debug, Default, HashStable, TypeFoldable, Lift)]
 pub struct DropckOutlivesResult<'tcx> {
     pub kinds: Vec<GenericArg<'tcx>>,
     pub overflows: Vec<Ty<'tcx>>,
@@ -114,7 +114,7 @@ impl<'tcx> DropckOutlivesResult<'tcx> {
 
 /// A set of constraints that need to be satisfied in order for
 /// a type to be valid for destruction.
-#[derive(Clone, Debug)]
+#[derive(Clone, Debug, HashStable)]
 pub struct DtorckConstraint<'tcx> {
     /// Types that are required to be alive in order for this
     /// type to be valid for destruction.
@@ -152,15 +152,6 @@ impl<'tcx> FromIterator<DtorckConstraint<'tcx>> for DtorckConstraint<'tcx> {
         result
     }
 }
-impl_stable_hash_for!(struct DropckOutlivesResult<'tcx> {
-    kinds, overflows
-});
-
-impl_stable_hash_for!(struct DtorckConstraint<'tcx> {
-    outlives,
-    dtorck_types,
-    overflows
-});
 
 /// This returns true if the type `ty` is "trivial" for
 /// dropck-outlives -- that is, if it doesn't require any types to
diff --git a/src/librustc/traits/query/method_autoderef.rs b/src/librustc/traits/query/method_autoderef.rs
index 039dea1ffcd..be846287e29 100644
--- a/src/librustc/traits/query/method_autoderef.rs
+++ b/src/librustc/traits/query/method_autoderef.rs
@@ -2,7 +2,7 @@ use rustc_data_structures::sync::Lrc;
 use crate::infer::canonical::{Canonical, QueryResponse};
 use crate::ty::Ty;
 
-#[derive(Debug)]
+#[derive(Debug, HashStable)]
 pub struct CandidateStep<'tcx> {
     pub self_ty: Canonical<'tcx, QueryResponse<'tcx, Ty<'tcx>>>,
     pub autoderefs: usize,
@@ -15,7 +15,7 @@ pub struct CandidateStep<'tcx> {
     pub unsize: bool,
 }
 
-#[derive(Clone, Debug)]
+#[derive(Clone, Debug, HashStable)]
 pub struct MethodAutoderefStepsResult<'tcx> {
     /// The valid autoderef steps that could be find.
     pub steps: Lrc<Vec<CandidateStep<'tcx>>>,
@@ -26,20 +26,8 @@ pub struct MethodAutoderefStepsResult<'tcx> {
     pub reached_recursion_limit: bool,
 }
 
-#[derive(Debug)]
+#[derive(Debug, HashStable)]
 pub struct MethodAutoderefBadTy<'tcx> {
     pub reached_raw_pointer: bool,
     pub ty: Canonical<'tcx, QueryResponse<'tcx, Ty<'tcx>>>,
 }
-
-impl_stable_hash_for!(struct MethodAutoderefBadTy<'tcx> {
-    reached_raw_pointer, ty
-});
-
-impl_stable_hash_for!(struct MethodAutoderefStepsResult<'tcx> {
-    reached_recursion_limit, steps, opt_bad_ty
-});
-
-impl_stable_hash_for!(struct CandidateStep<'tcx> {
-    self_ty, autoderefs, from_unsafe_deref, unsize
-});
diff --git a/src/librustc/traits/query/mod.rs b/src/librustc/traits/query/mod.rs
index f6ea77dc5cc..66683cab959 100644
--- a/src/librustc/traits/query/mod.rs
+++ b/src/librustc/traits/query/mod.rs
@@ -40,7 +40,7 @@ pub type CanonicalTypeOpProvePredicateGoal<'tcx> =
 pub type CanonicalTypeOpNormalizeGoal<'tcx, T> =
     Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::normalize::Normalize<T>>>;
 
-#[derive(Clone, Debug)]
+#[derive(Clone, Debug, HashStable)]
 pub struct NoSolution;
 
 pub type Fallible<T> = Result<T, NoSolution>;
@@ -50,5 +50,3 @@ impl<'tcx> From<TypeError<'tcx>> for NoSolution {
         NoSolution
     }
 }
-
-impl_stable_hash_for!(struct NoSolution { });
diff --git a/src/librustc/traits/query/normalize.rs b/src/librustc/traits/query/normalize.rs
index 30528dcebda..09c7f45c22b 100644
--- a/src/librustc/traits/query/normalize.rs
+++ b/src/librustc/traits/query/normalize.rs
@@ -66,7 +66,7 @@ impl<'cx, 'tcx> At<'cx, 'tcx> {
 }
 
 /// Result from the `normalize_projection_ty` query.
-#[derive(Clone, Debug, TypeFoldable, Lift)]
+#[derive(Clone, Debug, HashStable, TypeFoldable, Lift)]
 pub struct NormalizationResult<'tcx> {
     /// Result of normalization.
     pub normalized_ty: Ty<'tcx>,
@@ -193,7 +193,3 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> {
         constant.eval(self.infcx.tcx, self.param_env)
     }
 }
-
-impl_stable_hash_for!(struct NormalizationResult<'tcx> {
-    normalized_ty
-});
diff --git a/src/librustc/traits/query/type_op/ascribe_user_type.rs b/src/librustc/traits/query/type_op/ascribe_user_type.rs
index 8b0ee5feed7..ee8b73f86a6 100644
--- a/src/librustc/traits/query/type_op/ascribe_user_type.rs
+++ b/src/librustc/traits/query/type_op/ascribe_user_type.rs
@@ -4,7 +4,7 @@ use crate::hir::def_id::DefId;
 use crate::ty::{ParamEnvAnd, Ty, TyCtxt};
 use crate::ty::subst::UserSubsts;
 
-#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, TypeFoldable, Lift)]
+#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, TypeFoldable, Lift)]
 pub struct AscribeUserType<'tcx> {
     pub mir_ty: Ty<'tcx>,
     pub def_id: DefId,
@@ -38,9 +38,3 @@ impl<'tcx> super::QueryTypeOp<'tcx> for AscribeUserType<'tcx> {
         tcx.type_op_ascribe_user_type(canonicalized)
     }
 }
-
-impl_stable_hash_for! {
-    struct AscribeUserType<'tcx> {
-        mir_ty, def_id, user_substs
-    }
-}
diff --git a/src/librustc/traits/query/type_op/eq.rs b/src/librustc/traits/query/type_op/eq.rs
index 5086994fbb6..8ea800cced2 100644
--- a/src/librustc/traits/query/type_op/eq.rs
+++ b/src/librustc/traits/query/type_op/eq.rs
@@ -2,7 +2,7 @@ use crate::infer::canonical::{Canonicalized, CanonicalizedQueryResponse};
 use crate::traits::query::Fallible;
 use crate::ty::{ParamEnvAnd, Ty, TyCtxt};
 
-#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, TypeFoldable, Lift)]
+#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, TypeFoldable, Lift)]
 pub struct Eq<'tcx> {
     pub a: Ty<'tcx>,
     pub b: Ty<'tcx>,
@@ -35,7 +35,3 @@ impl<'tcx> super::QueryTypeOp<'tcx> for Eq<'tcx> {
         tcx.type_op_eq(canonicalized)
     }
 }
-
-impl_stable_hash_for! {
-    struct Eq<'tcx> { a, b }
-}
diff --git a/src/librustc/traits/query/type_op/implied_outlives_bounds.rs b/src/librustc/traits/query/type_op/implied_outlives_bounds.rs
index f97b34f9e9a..6f45d76a8e9 100644
--- a/src/librustc/traits/query/type_op/implied_outlives_bounds.rs
+++ b/src/librustc/traits/query/type_op/implied_outlives_bounds.rs
@@ -3,7 +3,7 @@ use crate::traits::query::outlives_bounds::OutlivesBound;
 use crate::traits::query::Fallible;
 use crate::ty::{ParamEnvAnd, Ty, TyCtxt};
 
-#[derive(Clone, Debug, TypeFoldable, Lift)]
+#[derive(Clone, Debug, HashStable, TypeFoldable, Lift)]
 pub struct ImpliedOutlivesBounds<'tcx> {
     pub ty: Ty<'tcx>,
 }
@@ -39,7 +39,3 @@ impl<'tcx> super::QueryTypeOp<'tcx> for ImpliedOutlivesBounds<'tcx> {
         tcx.implied_outlives_bounds(canonicalized)
     }
 }
-
-impl_stable_hash_for! {
-    struct ImpliedOutlivesBounds<'tcx> { ty }
-}
diff --git a/src/librustc/traits/query/type_op/normalize.rs b/src/librustc/traits/query/type_op/normalize.rs
index 798fc5224cc..f905d5a019e 100644
--- a/src/librustc/traits/query/type_op/normalize.rs
+++ b/src/librustc/traits/query/type_op/normalize.rs
@@ -4,7 +4,7 @@ use crate::traits::query::Fallible;
 use crate::ty::fold::TypeFoldable;
 use crate::ty::{self, Lift, ParamEnvAnd, Ty, TyCtxt};
 
-#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, TypeFoldable, Lift)]
+#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, TypeFoldable, Lift)]
 pub struct Normalize<T> {
     pub value: T,
 }
@@ -82,9 +82,3 @@ impl Normalizable<'tcx> for ty::FnSig<'tcx> {
         tcx.type_op_normalize_fn_sig(canonicalized)
     }
 }
-
-impl_stable_hash_for! {
-    impl<T> for struct Normalize<T> {
-        value
-    }
-}
diff --git a/src/librustc/traits/query/type_op/outlives.rs b/src/librustc/traits/query/type_op/outlives.rs
index d2a7fdc8946..83d51b6d3eb 100644
--- a/src/librustc/traits/query/type_op/outlives.rs
+++ b/src/librustc/traits/query/type_op/outlives.rs
@@ -3,7 +3,7 @@ use crate::traits::query::dropck_outlives::{DropckOutlivesResult, trivial_dropck
 use crate::traits::query::Fallible;
 use crate::ty::{ParamEnvAnd, Ty, TyCtxt};
 
-#[derive(Copy, Clone, Debug, TypeFoldable, Lift)]
+#[derive(Copy, Clone, Debug, HashStable, TypeFoldable, Lift)]
 pub struct DropckOutlives<'tcx> {
     dropped_ty: Ty<'tcx>,
 }
@@ -53,7 +53,3 @@ impl super::QueryTypeOp<'tcx> for DropckOutlives<'tcx> {
         tcx.dropck_outlives(canonicalized)
     }
 }
-
-impl_stable_hash_for! {
-    struct DropckOutlives<'tcx> { dropped_ty }
-}
diff --git a/src/librustc/traits/query/type_op/prove_predicate.rs b/src/librustc/traits/query/type_op/prove_predicate.rs
index cbf485fcfe0..c0a0cbe9a38 100644
--- a/src/librustc/traits/query/type_op/prove_predicate.rs
+++ b/src/librustc/traits/query/type_op/prove_predicate.rs
@@ -2,7 +2,7 @@ use crate::infer::canonical::{Canonicalized, CanonicalizedQueryResponse};
 use crate::traits::query::Fallible;
 use crate::ty::{ParamEnvAnd, Predicate, TyCtxt};
 
-#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, TypeFoldable, Lift)]
+#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, TypeFoldable, Lift)]
 pub struct ProvePredicate<'tcx> {
     pub predicate: Predicate<'tcx>,
 }
@@ -44,7 +44,3 @@ impl<'tcx> super::QueryTypeOp<'tcx> for ProvePredicate<'tcx> {
         tcx.type_op_prove_predicate(canonicalized)
     }
 }
-
-impl_stable_hash_for! {
-    struct ProvePredicate<'tcx> { predicate }
-}
diff --git a/src/librustc/traits/query/type_op/subtype.rs b/src/librustc/traits/query/type_op/subtype.rs
index bd53e234a6a..76292f9dea0 100644
--- a/src/librustc/traits/query/type_op/subtype.rs
+++ b/src/librustc/traits/query/type_op/subtype.rs
@@ -2,7 +2,7 @@ use crate::infer::canonical::{Canonicalized, CanonicalizedQueryResponse};
 use crate::traits::query::Fallible;
 use crate::ty::{ParamEnvAnd, Ty, TyCtxt};
 
-#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, TypeFoldable, Lift)]
+#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, TypeFoldable, Lift)]
 pub struct Subtype<'tcx> {
     pub sub: Ty<'tcx>,
     pub sup: Ty<'tcx>,
@@ -35,7 +35,3 @@ impl<'tcx> super::QueryTypeOp<'tcx> for Subtype<'tcx> {
         tcx.type_op_subtype(canonicalized)
     }
 }
-
-impl_stable_hash_for! {
-    struct Subtype<'tcx> { sub, sup }
-}
diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs
index 608883d609f..ffc94cf2b12 100644
--- a/src/librustc/traits/select.rs
+++ b/src/librustc/traits/select.rs
@@ -367,7 +367,6 @@ enum BuiltinImplConditions<'tcx> {
     Ambiguous,
 }
 
-#[derive(Copy, Clone, Debug, PartialOrd, Ord, PartialEq, Eq)]
 /// The result of trait evaluation. The order is important
 /// here as the evaluation of a list is the maximum of the
 /// evaluations.
@@ -380,6 +379,7 @@ enum BuiltinImplConditions<'tcx> {
 ///     all the "potential success" candidates can potentially succeed,
 ///     so they are noops when unioned with a definite error, and within
 ///     the categories it's easy to see that the unions are correct.
+#[derive(Copy, Clone, Debug, PartialOrd, Ord, PartialEq, Eq, HashStable)]
 pub enum EvaluationResult {
     /// Evaluation successful
     EvaluatedToOk,
@@ -478,21 +478,10 @@ impl EvaluationResult {
     }
 }
 
-impl_stable_hash_for!(enum self::EvaluationResult {
-    EvaluatedToOk,
-    EvaluatedToOkModuloRegions,
-    EvaluatedToAmbig,
-    EvaluatedToUnknown,
-    EvaluatedToRecur,
-    EvaluatedToErr
-});
-
-#[derive(Copy, Clone, Debug, PartialEq, Eq)]
 /// Indicates that trait evaluation caused overflow.
+#[derive(Copy, Clone, Debug, PartialEq, Eq, HashStable)]
 pub struct OverflowError;
 
-impl_stable_hash_for!(struct OverflowError {});
-
 impl<'tcx> From<OverflowError> for SelectionError<'tcx> {
     fn from(OverflowError: OverflowError) -> SelectionError<'tcx> {
         SelectionError::Overflow
diff --git a/src/librustc/traits/specialize/specialization_graph.rs b/src/librustc/traits/specialize/specialization_graph.rs
index c64d6748ea9..d945c756f66 100644
--- a/src/librustc/traits/specialize/specialization_graph.rs
+++ b/src/librustc/traits/specialize/specialization_graph.rs
@@ -24,7 +24,7 @@ use crate::util::nodemap::{DefIdMap, FxHashMap};
 ///   parents of a given specializing impl, which is needed for extracting
 ///   default items amongst other things. In the simple "chain" rule, every impl
 ///   has at most one parent.
-#[derive(RustcEncodable, RustcDecodable)]
+#[derive(RustcEncodable, RustcDecodable, HashStable)]
 pub struct Graph {
     // All impls have a parent; the "root" impls have as their parent the `def_id`
     // of the trait.
@@ -535,8 +535,3 @@ impl<'a> HashStable<StableHashingContext<'a>> for Children {
         ich::hash_stable_trait_impls(hcx, hasher, blanket_impls, nonblanket_impls);
     }
 }
-
-impl_stable_hash_for!(struct self::Graph {
-    parent,
-    children
-});
diff --git a/src/librustc/ty/binding.rs b/src/librustc/ty/binding.rs
index 905d7abb782..491e09dff09 100644
--- a/src/librustc/ty/binding.rs
+++ b/src/librustc/ty/binding.rs
@@ -2,7 +2,7 @@ use crate::hir::BindingAnnotation::*;
 use crate::hir::BindingAnnotation;
 use crate::hir::Mutability;
 
-#[derive(Clone, PartialEq, RustcEncodable, RustcDecodable, Debug, Copy)]
+#[derive(Clone, PartialEq, RustcEncodable, RustcDecodable, Debug, Copy, HashStable)]
 pub enum BindingMode {
     BindByReference(Mutability),
     BindByValue(Mutability),
@@ -20,8 +20,3 @@ impl BindingMode {
         }
     }
 }
-
-impl_stable_hash_for!(enum self::BindingMode {
-    BindByReference(mutability),
-    BindByValue(mutability)
-});
diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs
index 031d6f09b44..a54bf5079ca 100644
--- a/src/librustc/ty/mod.rs
+++ b/src/librustc/ty/mod.rs
@@ -1590,12 +1590,11 @@ rustc_index::newtype_index! {
     /// type -- an idealized representative of "types in general" that we
     /// use for checking generic functions.
     pub struct UniverseIndex {
+        derive [HashStable]
         DEBUG_FORMAT = "U{}",
     }
 }
 
-impl_stable_hash_for!(struct UniverseIndex { private });
-
 impl UniverseIndex {
     pub const ROOT: UniverseIndex = UniverseIndex::from_u32_const(0);
 
@@ -1839,7 +1838,7 @@ bitflags! {
 }
 
 /// Definition of a variant -- a struct's fields or a enum variant.
-#[derive(Debug)]
+#[derive(Debug, HashStable)]
 pub struct VariantDef {
     /// `DefId` that identifies the variant itself.
     /// If this variant belongs to a struct or union, then this is a copy of its `DefId`.
@@ -1848,6 +1847,7 @@ pub struct VariantDef {
     /// If this variant is a struct variant, then this is `None`.
     pub ctor_def_id: Option<DefId>,
     /// Variant or struct name.
+    #[stable_hasher(project(name))]
     pub ident: Ident,
     /// Discriminant of this variant.
     pub discr: VariantDiscr,
@@ -1927,17 +1927,6 @@ impl<'tcx> VariantDef {
     }
 }
 
-impl_stable_hash_for!(struct VariantDef {
-    def_id,
-    ctor_def_id,
-    ident -> (ident.name),
-    discr,
-    fields,
-    ctor_kind,
-    flags,
-    recovered
-});
-
 #[derive(Copy, Clone, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable, HashStable)]
 pub enum VariantDiscr {
     /// Explicit value for this variant, i.e., `X = 123`.
@@ -2061,7 +2050,7 @@ impl Into<DataTypeKind> for AdtKind {
 }
 
 bitflags! {
-    #[derive(RustcEncodable, RustcDecodable, Default)]
+    #[derive(RustcEncodable, RustcDecodable, Default, HashStable)]
     pub struct ReprFlags: u8 {
         const IS_C               = 1 << 0;
         const IS_SIMD            = 1 << 1;
@@ -2076,12 +2065,9 @@ bitflags! {
     }
 }
 
-impl_stable_hash_for!(struct ReprFlags {
-    bits
-});
-
 /// Represents the repr options provided by the user,
-#[derive(Copy, Clone, Debug, Eq, PartialEq, RustcEncodable, RustcDecodable, Default)]
+#[derive(Copy, Clone, Debug, Eq, PartialEq, RustcEncodable, RustcDecodable,
+         Default, HashStable)]
 pub struct ReprOptions {
     pub int: Option<attr::IntType>,
     pub align: Option<Align>,
@@ -2089,13 +2075,6 @@ pub struct ReprOptions {
     pub flags: ReprFlags,
 }
 
-impl_stable_hash_for!(struct ReprOptions {
-    align,
-    pack,
-    int,
-    flags
-});
-
 impl ReprOptions {
     pub fn new(tcx: TyCtxt<'_>, did: DefId) -> ReprOptions {
         let mut flags = ReprFlags::empty();
@@ -3439,17 +3418,13 @@ pub struct CrateInherentImpls {
     pub inherent_impls: DefIdMap<Vec<DefId>>,
 }
 
-#[derive(Clone, Copy, PartialEq, Eq, RustcEncodable, RustcDecodable)]
+#[derive(Clone, Copy, PartialEq, Eq, RustcEncodable, RustcDecodable, HashStable)]
 pub struct SymbolName {
     // FIXME: we don't rely on interning or equality here - better have
     // this be a `&'tcx str`.
     pub name: Symbol
 }
 
-impl_stable_hash_for!(struct self::SymbolName {
-    name
-});
-
 impl SymbolName {
     pub fn new(name: &str) -> SymbolName {
         SymbolName {
diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs
index fa22709d66f..07258717cd9 100644
--- a/src/librustc/ty/sty.rs
+++ b/src/librustc/ty/sty.rs
@@ -1204,6 +1204,7 @@ rustc_index::newtype_index! {
     /// is the outer fn.
     ///
     /// [dbi]: http://en.wikipedia.org/wiki/De_Bruijn_index
+    #[derive(HashStable)]
     pub struct DebruijnIndex {
         DEBUG_FORMAT = "DebruijnIndex({})",
         const INNERMOST = 0,
@@ -1379,21 +1380,20 @@ rustc_index::newtype_index! {
     pub struct BoundVar { .. }
 }
 
-#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, RustcEncodable, RustcDecodable)]
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug,
+         RustcEncodable, RustcDecodable, HashStable)]
 pub struct BoundTy {
     pub var: BoundVar,
     pub kind: BoundTyKind,
 }
 
-#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, RustcEncodable, RustcDecodable)]
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug,
+         RustcEncodable, RustcDecodable, HashStable)]
 pub enum BoundTyKind {
     Anon,
     Param(Symbol),
 }
 
-impl_stable_hash_for!(struct BoundTy { var, kind });
-impl_stable_hash_for!(enum self::BoundTyKind { Anon, Param(a) });
-
 impl From<BoundVar> for BoundTy {
     fn from(var: BoundVar) -> Self {
         BoundTy {
@@ -1518,8 +1518,6 @@ impl DebruijnIndex {
     }
 }
 
-impl_stable_hash_for!(struct DebruijnIndex { private });
-
 /// Region utilities
 impl RegionKind {
     /// Is this region named by the user?
diff --git a/src/librustc_codegen_utils/lib.rs b/src/librustc_codegen_utils/lib.rs
index 66920342ff6..fb2099e71a3 100644
--- a/src/librustc_codegen_utils/lib.rs
+++ b/src/librustc_codegen_utils/lib.rs
@@ -19,7 +19,7 @@ extern crate rustc;
 
 use rustc::ty::TyCtxt;
 use rustc::ty::query::Providers;
-use rustc::hir::def_id::LOCAL_CRATE;
+use rustc::hir::def_id::{LOCAL_CRATE, DefId};
 use syntax::symbol::sym;
 
 pub mod link;
@@ -27,18 +27,50 @@ pub mod codegen_backend;
 pub mod symbol_names;
 pub mod symbol_names_test;
 
+
+pub fn trigger_delay_span_bug(tcx: TyCtxt<'_>, key: DefId) {
+    tcx.sess.delay_span_bug(
+        tcx.def_span(key),
+        "delayed span bug triggered by #[rustc_error(delay_span_bug_from_inside_query)]"
+    );
+}
+
 /// check for the #[rustc_error] annotation, which forces an
 /// error in codegen. This is used to write compile-fail tests
 /// that actually test that compilation succeeds without
 /// reporting an error.
 pub fn check_for_rustc_errors_attr(tcx: TyCtxt<'_>) {
     if let Some((def_id, _)) = tcx.entry_fn(LOCAL_CRATE) {
-        if tcx.has_attr(def_id, sym::rustc_error) {
-            tcx.sess.span_fatal(tcx.def_span(def_id), "compilation successful");
+        let attrs = &*tcx.get_attrs(def_id);
+        for attr in attrs {
+            if attr.check_name(sym::rustc_error) {
+                match attr.meta_item_list() {
+                    // check if there is a #[rustc_error(delayed)]
+                    Some(list) => {
+                        if list.iter().any(|list_item| {
+                            list_item.ident().map(|i| i.name) ==
+                                Some(sym::delay_span_bug_from_inside_query)
+                        }) {
+                            tcx.ensure().trigger_delay_span_bug(def_id);
+                        }
+                    }
+                    // bare #[rustc_error]
+                    None => {
+                        tcx.sess.span_fatal(
+                            tcx.def_span(def_id),
+                            "fatal error triggered by #[rustc_error]"
+                        );
+                    }
+                }
+            }
         }
     }
 }
 
 pub fn provide(providers: &mut Providers<'_>) {
     crate::symbol_names::provide(providers);
+    *providers = Providers {
+        trigger_delay_span_bug,
+        ..*providers
+    };
 }
diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs
index 6dfb2409775..a721e381b4e 100644
--- a/src/librustc_metadata/creader.rs
+++ b/src/librustc_metadata/creader.rs
@@ -1,21 +1,17 @@
 //! Validates all used crates and extern libraries and loads their metadata
 
-use crate::cstore::{self, CStore, MetadataBlob};
-use crate::locator::{self, CratePaths};
-use crate::rmeta::{CrateRoot, CrateDep};
-use rustc_data_structures::sync::{Lock, Once, AtomicCell};
+use crate::cstore::CStore;
+use crate::locator::{CrateLocator, CratePaths};
+use crate::rmeta::{CrateMetadata, CrateNumMap, CrateRoot, CrateDep, MetadataBlob};
 
 use rustc::hir::def_id::CrateNum;
 use rustc_data_structures::svh::Svh;
-use rustc::dep_graph::DepNodeIndex;
 use rustc::middle::cstore::DepKind;
-use rustc::mir::interpret::AllocDecodingState;
 use rustc::session::{Session, CrateDisambiguator};
 use rustc::session::config::{Sanitizer, self};
 use rustc_target::spec::{PanicStrategy, TargetTriple};
 use rustc::session::search_paths::PathKind;
 use rustc::middle::cstore::{CrateSource, ExternCrate, ExternCrateSource, MetadataLoaderDyn};
-use rustc::util::common::record_time;
 use rustc::util::nodemap::FxHashSet;
 use rustc::hir::map::Definitions;
 use rustc::hir::def_id::LOCAL_CRATE;
@@ -50,9 +46,9 @@ pub struct CrateLoader<'a> {
 
 fn dump_crates(cstore: &CStore) {
     info!("resolved crates:");
-    cstore.iter_crate_data(|_, data| {
+    cstore.iter_crate_data(|cnum, data| {
         info!("  name: {}", data.root.name);
-        info!("  cnum: {}", data.cnum);
+        info!("  cnum: {}", cnum);
         info!("  hash: {}", data.root.hash);
         info!("  reqd: {:?}", *data.dep_kind.lock());
         let CrateSource { dylib, rlib, rmeta } = data.source.clone();
@@ -68,13 +64,13 @@ enum LoadResult {
 }
 
 enum LoadError<'a> {
-    LocatorError(locator::Context<'a>),
+    LocatorError(CrateLocator<'a>),
 }
 
 impl<'a> LoadError<'a> {
     fn report(self) -> ! {
         match self {
-            LoadError::LocatorError(locate_ctxt) => locate_ctxt.report_errs(),
+            LoadError::LocatorError(locator) => locator.report_errs(),
         }
     }
 }
@@ -145,7 +141,7 @@ impl<'a> CrateLoader<'a> {
             let prev_kind = source.dylib.as_ref().or(source.rlib.as_ref())
                                   .or(source.rmeta.as_ref())
                                   .expect("No sources for crate").1;
-            if ret.is_none() && (prev_kind == kind || prev_kind == PathKind::All) {
+            if kind.matches(prev_kind) {
                 ret = Some(cnum);
             }
         });
@@ -211,15 +207,13 @@ impl<'a> CrateLoader<'a> {
         let root = if let Some(root) = root {
             root
         } else {
-            crate_paths = CratePaths { name: crate_root.name, source: source.clone() };
+            crate_paths = CratePaths::new(crate_root.name, source.clone());
             &crate_paths
         };
 
         let cnum_map = self.resolve_crate_deps(root, &crate_root, &metadata, cnum, span, dep_kind);
 
-        let dependencies: Vec<CrateNum> = cnum_map.iter().cloned().collect();
-
-        let raw_proc_macros =  crate_root.proc_macro_data.map(|_| {
+        let raw_proc_macros = if crate_root.is_proc_macro_crate() {
             let temp_root;
             let (dlsym_source, dlsym_root) = match &host_lib {
                 Some(host_lib) =>
@@ -227,55 +221,38 @@ impl<'a> CrateLoader<'a> {
                 None => (&source, &crate_root),
             };
             let dlsym_dylib = dlsym_source.dylib.as_ref().expect("no dylib for a proc-macro crate");
-            self.dlsym_proc_macros(&dlsym_dylib.0, dlsym_root.disambiguator, span)
-        });
-
-        let interpret_alloc_index: Vec<u32> = crate_root.interpret_alloc_index
-                                                        .decode(&metadata)
-                                                        .collect();
-        let trait_impls = crate_root
-            .impls
-            .decode((&metadata, self.sess))
-            .map(|trait_impls| (trait_impls.trait_id, trait_impls.impls))
-            .collect();
-
-        let def_path_table = record_time(&self.sess.perf_stats.decode_def_path_tables_time, || {
-            crate_root.def_path_table.decode((&metadata, self.sess))
-        });
+            Some(self.dlsym_proc_macros(&dlsym_dylib.0, dlsym_root.disambiguator, span))
+        } else {
+            None
+        };
 
-        self.cstore.set_crate_data(cnum, cstore::CrateMetadata {
-            extern_crate: Lock::new(None),
-            def_path_table,
-            trait_impls,
-            root: crate_root,
-            host_hash,
-            blob: metadata,
-            cnum_map,
+        self.cstore.set_crate_data(cnum, CrateMetadata::new(
+            self.sess,
+            metadata,
+            crate_root,
+            raw_proc_macros,
             cnum,
-            dependencies: Lock::new(dependencies),
-            source_map_import_info: Once::new(),
-            alloc_decoding_state: AllocDecodingState::new(interpret_alloc_index),
-            dep_kind: Lock::new(dep_kind),
+            cnum_map,
+            dep_kind,
             source,
             private_dep,
-            raw_proc_macros,
-            dep_node_index: AtomicCell::new(DepNodeIndex::INVALID),
-        });
+            host_hash,
+        ));
 
         cnum
     }
 
     fn load_proc_macro<'b>(
         &self,
-        locate_ctxt: &mut locator::Context<'b>,
+        locator: &mut CrateLocator<'b>,
         path_kind: PathKind,
     ) -> Option<(LoadResult, Option<Library>)>
     where
         'a: 'b,
     {
-        // Use a new locator Context so trying to load a proc macro doesn't affect the error
+        // Use a new crate locator so trying to load a proc macro doesn't affect the error
         // message we emit
-        let mut proc_macro_locator = locate_ctxt.clone();
+        let mut proc_macro_locator = locator.clone();
 
         // Try to load a proc macro
         proc_macro_locator.is_proc_macro = Some(true);
@@ -287,10 +264,10 @@ impl<'a> CrateLoader<'a> {
                 LoadResult::Previous(cnum) => return Some((LoadResult::Previous(cnum), None)),
                 LoadResult::Loaded(library) => Some(LoadResult::Loaded(library))
             };
-            locate_ctxt.hash = locate_ctxt.host_hash;
-            // Use the locate_ctxt when looking for the host proc macro crate, as that is required
+            locator.hash = locator.host_hash;
+            // Use the locator when looking for the host proc macro crate, as that is required
             // so we want it to affect the error message
-            (locate_ctxt, result)
+            (locator, result)
         } else {
             (&mut proc_macro_locator, None)
         };
@@ -350,37 +327,30 @@ impl<'a> CrateLoader<'a> {
             (LoadResult::Previous(cnum), None)
         } else {
             info!("falling back to a load");
-            let mut locate_ctxt = locator::Context {
-                sess: self.sess,
-                span,
-                crate_name: name,
+            let mut locator = CrateLocator::new(
+                self.sess,
+                self.metadata_loader,
+                name,
                 hash,
                 host_hash,
                 extra_filename,
-                filesearch: self.sess.target_filesearch(path_kind),
-                target: &self.sess.target.target,
-                triple: self.sess.opts.target_triple.clone(),
+                false, // is_host
+                path_kind,
+                span,
                 root,
-                rejected_via_hash: vec![],
-                rejected_via_triple: vec![],
-                rejected_via_kind: vec![],
-                rejected_via_version: vec![],
-                rejected_via_filename: vec![],
-                should_match_name: true,
-                is_proc_macro: Some(false),
-                metadata_loader: self.metadata_loader,
-            };
+                Some(false), // is_proc_macro
+            );
 
-            self.load(&mut locate_ctxt).map(|r| (r, None)).or_else(|| {
+            self.load(&mut locator).map(|r| (r, None)).or_else(|| {
                 dep_kind = DepKind::UnexportedMacrosOnly;
-                self.load_proc_macro(&mut locate_ctxt, path_kind)
-            }).ok_or_else(move || LoadError::LocatorError(locate_ctxt))?
+                self.load_proc_macro(&mut locator, path_kind)
+            }).ok_or_else(move || LoadError::LocatorError(locator))?
         };
 
         match result {
             (LoadResult::Previous(cnum), None) => {
                 let data = self.cstore.get_crate_data(cnum);
-                if data.root.proc_macro_data.is_some() {
+                if data.root.is_proc_macro_crate() {
                     dep_kind = DepKind::UnexportedMacrosOnly;
                 }
                 data.dep_kind.with_lock(|data_dep_kind| {
@@ -395,8 +365,8 @@ impl<'a> CrateLoader<'a> {
         }
     }
 
-    fn load(&self, locate_ctxt: &mut locator::Context<'_>) -> Option<LoadResult> {
-        let library = locate_ctxt.maybe_load_library_crate()?;
+    fn load(&self, locator: &mut CrateLocator<'_>) -> Option<LoadResult> {
+        let library = locator.maybe_load_library_crate()?;
 
         // In the case that we're loading a crate, but not matching
         // against a hash, we could load a crate which has the same hash
@@ -407,11 +377,11 @@ impl<'a> CrateLoader<'a> {
         // don't want to match a host crate against an equivalent target one
         // already loaded.
         let root = library.metadata.get_root();
-        if locate_ctxt.triple == self.sess.opts.target_triple {
+        if locator.triple == self.sess.opts.target_triple {
             let mut result = LoadResult::Loaded(library);
             self.cstore.iter_crate_data(|cnum, data| {
                 if data.root.name == root.name && root.hash == data.root.hash {
-                    assert!(locate_ctxt.hash.is_none());
+                    assert!(locator.hash.is_none());
                     info!("load success, going to previous cnum: {}", cnum);
                     result = LoadResult::Previous(cnum);
                 }
@@ -471,16 +441,16 @@ impl<'a> CrateLoader<'a> {
                           krate: CrateNum,
                           span: Span,
                           dep_kind: DepKind)
-                          -> cstore::CrateNumMap {
+                          -> CrateNumMap {
         debug!("resolving deps of external crate");
-        if crate_root.proc_macro_data.is_some() {
-            return cstore::CrateNumMap::new();
+        if crate_root.is_proc_macro_crate() {
+            return CrateNumMap::new();
         }
 
         // The map from crate numbers in the crate we're resolving to local crate numbers.
         // We map 0 and all other holes in the map to our parent crate. The "additional"
         // self-dependencies should be harmless.
-        std::iter::once(krate).chain(crate_root.crate_deps.decode(metadata).map(|dep| {
+        std::iter::once(krate).chain(crate_root.decode_crate_deps(metadata).map(|dep| {
             info!("resolving dep crate {} hash: `{}` extra filename: `{}`", dep.name, dep.hash,
                   dep.extra_filename);
             if dep.kind == DepKind::UnexportedMacrosOnly {
@@ -824,7 +794,7 @@ impl<'a> CrateLoader<'a> {
     fn inject_dependency_if(&self,
                             krate: CrateNum,
                             what: &str,
-                            needs_dep: &dyn Fn(&cstore::CrateMetadata) -> bool) {
+                            needs_dep: &dyn Fn(&CrateMetadata) -> bool) {
         // don't perform this validation if the session has errors, as one of
         // those errors may indicate a circular dependency which could cause
         // this to stack overflow.
diff --git a/src/librustc_metadata/cstore.rs b/src/librustc_metadata/cstore.rs
index 54857ce1b82..48cf0b982f2 100644
--- a/src/librustc_metadata/cstore.rs
+++ b/src/librustc_metadata/cstore.rs
@@ -1,109 +1,23 @@
 // The crate store - a central repo for information collected about external
 // crates and libraries
 
-use crate::rmeta;
-use rustc::dep_graph::DepNodeIndex;
-use rustc::hir::def_id::{CrateNum, DefIndex};
-use rustc::hir::map::definitions::DefPathTable;
-use rustc::middle::cstore::{CrateSource, DepKind, ExternCrate};
-use rustc::mir::interpret::AllocDecodingState;
+use crate::rmeta::CrateMetadata;
+
+use rustc_data_structures::sync::Lrc;
 use rustc_index::vec::IndexVec;
-use rustc::util::nodemap::FxHashMap;
-use rustc_data_structures::sync::{Lrc, Lock, MetadataRef, Once, AtomicCell};
-use rustc_data_structures::svh::Svh;
+use rustc::hir::def_id::CrateNum;
 use syntax::ast;
 use syntax::edition::Edition;
-use syntax_expand::base::SyntaxExtension;
 use syntax::expand::allocator::AllocatorKind;
-use syntax_pos;
-use proc_macro::bridge::client::ProcMacro;
+use syntax_expand::base::SyntaxExtension;
 
 pub use crate::rmeta::{provide, provide_extern};
 
-// A map from external crate numbers (as decoded from some crate file) to
-// local crate numbers (as generated during this session). Each external
-// crate may refer to types in other external crates, and each has their
-// own crate numbers.
-crate type CrateNumMap = IndexVec<CrateNum, CrateNum>;
-
-crate struct MetadataBlob(pub MetadataRef);
-
-/// Holds information about a syntax_pos::SourceFile imported from another crate.
-/// See `imported_source_files()` for more information.
-crate struct ImportedSourceFile {
-    /// This SourceFile's byte-offset within the source_map of its original crate
-    pub original_start_pos: syntax_pos::BytePos,
-    /// The end of this SourceFile within the source_map of its original crate
-    pub original_end_pos: syntax_pos::BytePos,
-    /// The imported SourceFile's representation within the local source_map
-    pub translated_source_file: Lrc<syntax_pos::SourceFile>,
-}
-
-crate struct CrateMetadata {
-    /// The primary crate data - binary metadata blob.
-    crate blob: MetadataBlob,
-
-    // --- Some data pre-decoded from the metadata blob, usually for performance ---
-
-    /// Properties of the whole crate.
-    /// NOTE(eddyb) we pass `'static` to a `'tcx` parameter because this
-    /// lifetime is only used behind `Lazy`, and therefore acts like an
-    /// universal (`for<'tcx>`), that is paired up with whichever `TyCtxt`
-    /// is being used to decode those values.
-    crate root: rmeta::CrateRoot<'static>,
-    /// For each definition in this crate, we encode a key. When the
-    /// crate is loaded, we read all the keys and put them in this
-    /// hashmap, which gives the reverse mapping. This allows us to
-    /// quickly retrace a `DefPath`, which is needed for incremental
-    /// compilation support.
-    crate def_path_table: DefPathTable,
-    /// Trait impl data.
-    /// FIXME: Used only from queries and can use query cache,
-    /// so pre-decoding can probably be avoided.
-    crate trait_impls: FxHashMap<(u32, DefIndex), rmeta::Lazy<[DefIndex]>>,
-    /// Proc macro descriptions for this crate, if it's a proc macro crate.
-    crate raw_proc_macros: Option<&'static [ProcMacro]>,
-    /// Source maps for code from the crate.
-    crate source_map_import_info: Once<Vec<ImportedSourceFile>>,
-    /// Used for decoding interpret::AllocIds in a cached & thread-safe manner.
-    crate alloc_decoding_state: AllocDecodingState,
-    /// The `DepNodeIndex` of the `DepNode` representing this upstream crate.
-    /// It is initialized on the first access in `get_crate_dep_node_index()`.
-    /// Do not access the value directly, as it might not have been initialized yet.
-    /// The field must always be initialized to `DepNodeIndex::INVALID`.
-    crate dep_node_index: AtomicCell<DepNodeIndex>,
-
-    // --- Other significant crate properties ---
-
-    /// ID of this crate, from the current compilation session's point of view.
-    crate cnum: CrateNum,
-    /// Maps crate IDs as they are were seen from this crate's compilation sessions into
-    /// IDs as they are seen from the current compilation session.
-    crate cnum_map: CrateNumMap,
-    /// Same ID set as `cnum_map` plus maybe some injected crates like panic runtime.
-    crate dependencies: Lock<Vec<CrateNum>>,
-    /// How to link (or not link) this crate to the currently compiled crate.
-    crate dep_kind: Lock<DepKind>,
-    /// Filesystem location of this crate.
-    crate source: CrateSource,
-    /// Whether or not this crate should be consider a private dependency
-    /// for purposes of the 'exported_private_dependencies' lint
-    crate private_dep: bool,
-    /// The hash for the host proc macro. Used to support `-Z dual-proc-macro`.
-    crate host_hash: Option<Svh>,
-
-    // --- Data used only for improving diagnostics ---
-
-    /// Information about the `extern crate` item or path that caused this crate to be loaded.
-    /// If this is `None`, then the crate was injected (e.g., by the allocator).
-    crate extern_crate: Lock<Option<ExternCrate>>,
-}
-
 #[derive(Clone)]
 pub struct CStore {
     metas: IndexVec<CrateNum, Option<Lrc<CrateMetadata>>>,
-    pub(crate) injected_panic_runtime: Option<CrateNum>,
-    pub(crate) allocator_kind: Option<AllocatorKind>,
+    crate injected_panic_runtime: Option<CrateNum>,
+    crate allocator_kind: Option<AllocatorKind>,
 }
 
 pub enum LoadedMacro {
diff --git a/src/librustc_metadata/locator.rs b/src/librustc_metadata/locator.rs
index 582602138e5..64230fd9e60 100644
--- a/src/librustc_metadata/locator.rs
+++ b/src/librustc_metadata/locator.rs
@@ -212,9 +212,8 @@
 //! no means all of the necessary details. Take a look at the rest of
 //! metadata::locator or metadata::creader for all the juicy details!
 
-use crate::cstore::MetadataBlob;
 use crate::creader::Library;
-use crate::rmeta::{METADATA_HEADER, rustc_version};
+use crate::rmeta::{METADATA_HEADER, rustc_version, MetadataBlob};
 
 use rustc_data_structures::fx::FxHashSet;
 use rustc_data_structures::svh::Svh;
@@ -249,37 +248,47 @@ use log::{debug, info, warn};
 use rustc_error_codes::*;
 
 #[derive(Clone)]
-crate struct CrateMismatch {
+struct CrateMismatch {
     path: PathBuf,
     got: String,
 }
 
 #[derive(Clone)]
-crate struct Context<'a> {
-    pub sess: &'a Session,
-    pub span: Span,
-    pub crate_name: Symbol,
+crate struct CrateLocator<'a> {
+    // Immutable per-session configuration.
+    sess: &'a Session,
+    metadata_loader: &'a dyn MetadataLoader,
+
+    // Immutable per-search configuration.
+    crate_name: Symbol,
+    exact_paths: Vec<PathBuf>,
     pub hash: Option<&'a Svh>,
     pub host_hash: Option<&'a Svh>,
-    pub extra_filename: Option<&'a str>,
-    // points to either self.sess.target.target or self.sess.host, must match triple
+    extra_filename: Option<&'a str>,
     pub target: &'a Target,
     pub triple: TargetTriple,
     pub filesearch: FileSearch<'a>,
-    pub root: Option<&'a CratePaths>,
-    pub rejected_via_hash: Vec<CrateMismatch>,
-    pub rejected_via_triple: Vec<CrateMismatch>,
-    pub rejected_via_kind: Vec<CrateMismatch>,
-    pub rejected_via_version: Vec<CrateMismatch>,
-    pub rejected_via_filename: Vec<CrateMismatch>,
-    pub should_match_name: bool,
+    span: Span,
+    root: Option<&'a CratePaths>,
     pub is_proc_macro: Option<bool>,
-    pub metadata_loader: &'a dyn MetadataLoader,
+
+    // Mutable in-progress state or output.
+    rejected_via_hash: Vec<CrateMismatch>,
+    rejected_via_triple: Vec<CrateMismatch>,
+    rejected_via_kind: Vec<CrateMismatch>,
+    rejected_via_version: Vec<CrateMismatch>,
+    rejected_via_filename: Vec<CrateMismatch>,
 }
 
 crate struct CratePaths {
-    pub name: Symbol,
-    pub source: CrateSource,
+    name: Symbol,
+    source: CrateSource,
+}
+
+impl CratePaths {
+    crate fn new(name: Symbol, source: CrateSource) -> CratePaths {
+        CratePaths { name, source }
+    }
 }
 
 #[derive(Copy, Clone, PartialEq)]
@@ -299,7 +308,58 @@ impl fmt::Display for CrateFlavor {
     }
 }
 
-impl<'a> Context<'a> {
+impl<'a> CrateLocator<'a> {
+    crate fn new(
+        sess: &'a Session,
+        metadata_loader: &'a dyn MetadataLoader,
+        crate_name: Symbol,
+        hash: Option<&'a Svh>,
+        host_hash: Option<&'a Svh>,
+        extra_filename: Option<&'a str>,
+        is_host: bool,
+        path_kind: PathKind,
+        span: Span,
+        root: Option<&'a CratePaths>,
+        is_proc_macro: Option<bool>,
+    ) -> CrateLocator<'a> {
+        CrateLocator {
+            sess,
+            metadata_loader,
+            crate_name,
+            exact_paths: if hash.is_none() {
+                sess.opts.externs.get(&crate_name.as_str()).into_iter()
+                    .flat_map(|entry| entry.locations.iter())
+                    .filter_map(|location| location.clone().map(PathBuf::from)).collect()
+            } else {
+                // SVH being specified means this is a transitive dependency,
+                // so `--extern` options do not apply.
+                Vec::new()
+            },
+            hash,
+            host_hash,
+            extra_filename,
+            target: if is_host { &sess.host } else { &sess.target.target },
+            triple: if is_host {
+                TargetTriple::from_triple(config::host_triple())
+            } else {
+                sess.opts.target_triple.clone()
+            },
+            filesearch: if is_host {
+                sess.host_filesearch(path_kind)
+            } else {
+                sess.target_filesearch(path_kind)
+            },
+            span,
+            root,
+            is_proc_macro,
+            rejected_via_hash: Vec::new(),
+            rejected_via_triple: Vec::new(),
+            rejected_via_kind: Vec::new(),
+            rejected_via_version: Vec::new(),
+            rejected_via_filename: Vec::new(),
+        }
+    }
+
     crate fn reset(&mut self) {
         self.rejected_via_hash.clear();
         self.rejected_via_triple.clear();
@@ -309,6 +369,9 @@ impl<'a> Context<'a> {
     }
 
     crate fn maybe_load_library_crate(&mut self) -> Option<Library> {
+        if !self.exact_paths.is_empty() {
+            return self.find_commandline_library();
+        }
         let mut seen_paths = FxHashSet::default();
         match self.extra_filename {
             Some(s) => self.find_library_crate(s, &mut seen_paths)
@@ -434,21 +497,6 @@ impl<'a> Context<'a> {
                           extra_prefix: &str,
                           seen_paths: &mut FxHashSet<PathBuf>)
                           -> Option<Library> {
-        // If an SVH is specified, then this is a transitive dependency that
-        // must be loaded via -L plus some filtering.
-        if self.hash.is_none() {
-            self.should_match_name = false;
-            if let Some(entry) = self.sess.opts.externs.get(&self.crate_name.as_str()) {
-                // Only use `--extern crate_name=path` here, not `--extern crate_name`.
-                if entry.locations.iter().any(|l| l.is_some()) {
-                    return self.find_commandline_library(
-                        entry.locations.iter().filter_map(|l| l.as_ref()),
-                    );
-                }
-            }
-            self.should_match_name = true;
-        }
-
         let dypair = self.dylibname();
         let staticpair = self.staticlibname();
 
@@ -716,15 +764,16 @@ impl<'a> Context<'a> {
         }
 
         let root = metadata.get_root();
-        if let Some(is_proc_macro) = self.is_proc_macro {
-            if root.proc_macro_data.is_some() != is_proc_macro {
+        if let Some(expected_is_proc_macro) = self.is_proc_macro {
+            let is_proc_macro = root.is_proc_macro_crate();
+            if is_proc_macro != expected_is_proc_macro {
                 info!("Rejecting via proc macro: expected {} got {}",
-                      is_proc_macro, root.proc_macro_data.is_some());
+                      expected_is_proc_macro, is_proc_macro);
                 return None;
             }
         }
 
-        if self.should_match_name {
+        if self.exact_paths.is_empty() {
             if self.crate_name != root.name {
                 info!("Rejecting via crate name");
                 return None;
@@ -771,9 +820,7 @@ impl<'a> Context<'a> {
         (t.options.staticlib_prefix.clone(), t.options.staticlib_suffix.clone())
     }
 
-    fn find_commandline_library<'b, LOCS>(&mut self, locs: LOCS) -> Option<Library>
-        where LOCS: Iterator<Item = &'b String>
-    {
+    fn find_commandline_library(&mut self) -> Option<Library> {
         // First, filter out all libraries that look suspicious. We only accept
         // files which actually exist that have the correct naming scheme for
         // rlibs/dylibs.
@@ -783,10 +830,12 @@ impl<'a> Context<'a> {
         let mut rmetas = FxHashMap::default();
         let mut dylibs = FxHashMap::default();
         {
-            let locs = locs.map(|l| PathBuf::from(l)).filter(|loc| {
+                let crate_name = self.crate_name;
+                let rejected_via_filename = &mut self.rejected_via_filename;
+                let locs = self.exact_paths.iter().filter(|loc| {
                 if !loc.exists() {
                     sess.err(&format!("extern location for {} does not exist: {}",
-                                      self.crate_name,
+                                      crate_name,
                                       loc.display()));
                     return false;
                 }
@@ -794,7 +843,7 @@ impl<'a> Context<'a> {
                     Some(file) => file,
                     None => {
                         sess.err(&format!("extern location for {} is not a file: {}",
-                                          self.crate_name,
+                                          crate_name,
                                           loc.display()));
                         return false;
                     }
@@ -809,8 +858,8 @@ impl<'a> Context<'a> {
                     }
                 }
 
-                self.rejected_via_filename.push(CrateMismatch {
-                    path: loc.clone(),
+                rejected_via_filename.push(CrateMismatch {
+                    path: (*loc).clone(),
                     got: String::new(),
                 });
 
@@ -907,7 +956,7 @@ fn get_metadata_section_imp(target: &Target,
             rustc_erase_owner!(OwningRef::new(StableDerefMmap(mmap)).map_owner_box())
         }
     };
-    let blob = MetadataBlob(raw_bytes);
+    let blob = MetadataBlob::new(raw_bytes);
     if blob.is_compatible() {
         Ok(blob)
     } else {
@@ -927,28 +976,21 @@ pub fn find_plugin_registrar(
     let host_triple = TargetTriple::from_triple(config::host_triple());
     let is_cross = target_triple != host_triple;
     let mut target_only = false;
-    let mut locate_ctxt = Context {
+    let mut locator = CrateLocator::new(
         sess,
-        span,
-        crate_name: name,
-        hash: None,
-        host_hash: None,
-        extra_filename: None,
-        filesearch: sess.host_filesearch(PathKind::Crate),
-        target: &sess.host,
-        triple: host_triple,
-        root: None,
-        rejected_via_hash: vec![],
-        rejected_via_triple: vec![],
-        rejected_via_kind: vec![],
-        rejected_via_version: vec![],
-        rejected_via_filename: vec![],
-        should_match_name: true,
-        is_proc_macro: None,
         metadata_loader,
-    };
+        name,
+        None, // hash
+        None, // host_hash
+        None, // extra_filename
+        true, // is_host
+        PathKind::Crate,
+        span,
+        None, // root
+        None, // is_proc_macro
+    );
 
-    let library = locate_ctxt.maybe_load_library_crate().or_else(|| {
+    let library = locator.maybe_load_library_crate().or_else(|| {
         if !is_cross {
             return None
         }
@@ -956,15 +998,15 @@ pub fn find_plugin_registrar(
         // try to load a plugin registrar function,
         target_only = true;
 
-        locate_ctxt.target = &sess.target.target;
-        locate_ctxt.triple = target_triple;
-        locate_ctxt.filesearch = sess.target_filesearch(PathKind::Crate);
+        locator.target = &sess.target.target;
+        locator.triple = target_triple;
+        locator.filesearch = sess.target_filesearch(PathKind::Crate);
 
-        locate_ctxt.maybe_load_library_crate()
+        locator.maybe_load_library_crate()
     });
     let library = match library {
         Some(l) => l,
-        None => locate_ctxt.report_errs(),
+        None => locator.report_errs(),
     };
 
     if target_only {
diff --git a/src/librustc_metadata/rmeta/decoder.rs b/src/librustc_metadata/rmeta/decoder.rs
index fc0a0010240..7b0cf451ff9 100644
--- a/src/librustc_metadata/rmeta/decoder.rs
+++ b/src/librustc_metadata/rmeta/decoder.rs
@@ -1,27 +1,30 @@
 // Decoding metadata from a single crate's metadata
 
-use crate::cstore::{self, CrateMetadata, MetadataBlob};
 use crate::rmeta::*;
 use crate::rmeta::table::{FixedSizeEncoding, PerDefTable};
 
 use rustc_index::vec::IndexVec;
-use rustc_data_structures::sync::Lrc;
+use rustc_data_structures::sync::{Lrc, Lock, Once, AtomicCell};
 use rustc::hir::map::{DefKey, DefPath, DefPathData, DefPathHash};
+use rustc::hir::map::definitions::DefPathTable;
 use rustc::hir;
+use rustc::middle::cstore::{CrateSource, ExternCrate};
 use rustc::middle::cstore::{LinkagePreference, NativeLibrary, ForeignModule};
 use rustc::middle::exported_symbols::{ExportedSymbol, SymbolExportLevel};
 use rustc::hir::def::{self, Res, DefKind, CtorOf, CtorKind};
 use rustc::hir::def_id::{CrateNum, DefId, DefIndex, LocalDefId, CRATE_DEF_INDEX, LOCAL_CRATE};
 use rustc_data_structures::fingerprint::Fingerprint;
 use rustc_data_structures::fx::FxHashMap;
-use rustc::dep_graph::{DepNodeIndex, DepKind};
+use rustc_data_structures::svh::Svh;
+use rustc::dep_graph::{self, DepNodeIndex};
 use rustc::middle::lang_items;
 use rustc::mir::{self, interpret};
-use rustc::mir::interpret::AllocDecodingSession;
+use rustc::mir::interpret::{AllocDecodingSession, AllocDecodingState};
 use rustc::session::Session;
 use rustc::ty::{self, Ty, TyCtxt};
 use rustc::ty::codec::TyDecoder;
 use rustc::mir::{Body, Promoted};
+use rustc::util::common::record_time;
 use rustc::util::captures::Captures;
 
 use std::io;
@@ -44,7 +47,86 @@ pub use cstore_impl::{provide, provide_extern};
 
 mod cstore_impl;
 
-crate struct DecodeContext<'a, 'tcx> {
+crate struct MetadataBlob(MetadataRef);
+
+// A map from external crate numbers (as decoded from some crate file) to
+// local crate numbers (as generated during this session). Each external
+// crate may refer to types in other external crates, and each has their
+// own crate numbers.
+crate type CrateNumMap = IndexVec<CrateNum, CrateNum>;
+
+crate struct CrateMetadata {
+    /// The primary crate data - binary metadata blob.
+    blob: MetadataBlob,
+
+    // --- Some data pre-decoded from the metadata blob, usually for performance ---
+
+    /// Properties of the whole crate.
+    /// NOTE(eddyb) we pass `'static` to a `'tcx` parameter because this
+    /// lifetime is only used behind `Lazy`, and therefore acts like an
+    /// universal (`for<'tcx>`), that is paired up with whichever `TyCtxt`
+    /// is being used to decode those values.
+    crate root: CrateRoot<'static>,
+    /// For each definition in this crate, we encode a key. When the
+    /// crate is loaded, we read all the keys and put them in this
+    /// hashmap, which gives the reverse mapping. This allows us to
+    /// quickly retrace a `DefPath`, which is needed for incremental
+    /// compilation support.
+    def_path_table: DefPathTable,
+    /// Trait impl data.
+    /// FIXME: Used only from queries and can use query cache,
+    /// so pre-decoding can probably be avoided.
+    trait_impls: FxHashMap<(u32, DefIndex), Lazy<[DefIndex]>>,
+    /// Proc macro descriptions for this crate, if it's a proc macro crate.
+    raw_proc_macros: Option<&'static [ProcMacro]>,
+    /// Source maps for code from the crate.
+    source_map_import_info: Once<Vec<ImportedSourceFile>>,
+    /// Used for decoding interpret::AllocIds in a cached & thread-safe manner.
+    alloc_decoding_state: AllocDecodingState,
+    /// The `DepNodeIndex` of the `DepNode` representing this upstream crate.
+    /// It is initialized on the first access in `get_crate_dep_node_index()`.
+    /// Do not access the value directly, as it might not have been initialized yet.
+    /// The field must always be initialized to `DepNodeIndex::INVALID`.
+    dep_node_index: AtomicCell<DepNodeIndex>,
+
+    // --- Other significant crate properties ---
+
+    /// ID of this crate, from the current compilation session's point of view.
+    cnum: CrateNum,
+    /// Maps crate IDs as they are were seen from this crate's compilation sessions into
+    /// IDs as they are seen from the current compilation session.
+    cnum_map: CrateNumMap,
+    /// Same ID set as `cnum_map` plus maybe some injected crates like panic runtime.
+    crate dependencies: Lock<Vec<CrateNum>>,
+    /// How to link (or not link) this crate to the currently compiled crate.
+    crate dep_kind: Lock<DepKind>,
+    /// Filesystem location of this crate.
+    crate source: CrateSource,
+    /// Whether or not this crate should be consider a private dependency
+    /// for purposes of the 'exported_private_dependencies' lint
+    private_dep: bool,
+    /// The hash for the host proc macro. Used to support `-Z dual-proc-macro`.
+    host_hash: Option<Svh>,
+
+    // --- Data used only for improving diagnostics ---
+
+    /// Information about the `extern crate` item or path that caused this crate to be loaded.
+    /// If this is `None`, then the crate was injected (e.g., by the allocator).
+    crate extern_crate: Lock<Option<ExternCrate>>,
+}
+
+/// Holds information about a syntax_pos::SourceFile imported from another crate.
+/// See `imported_source_files()` for more information.
+struct ImportedSourceFile {
+    /// This SourceFile's byte-offset within the source_map of its original crate
+    original_start_pos: syntax_pos::BytePos,
+    /// The end of this SourceFile within the source_map of its original crate
+    original_end_pos: syntax_pos::BytePos,
+    /// The imported SourceFile's representation within the local source_map
+    translated_source_file: Lrc<syntax_pos::SourceFile>,
+}
+
+pub(super) struct DecodeContext<'a, 'tcx> {
     opaque: opaque::Decoder<'a>,
     cdata: Option<&'a CrateMetadata>,
     sess: Option<&'tcx Session>,
@@ -60,7 +142,7 @@ crate struct DecodeContext<'a, 'tcx> {
 }
 
 /// Abstract over the various ways one can create metadata decoders.
-crate trait Metadata<'a, 'tcx>: Copy {
+pub(super) trait Metadata<'a, 'tcx>: Copy {
     fn raw_bytes(self) -> &'a [u8];
     fn cdata(self) -> Option<&'a CrateMetadata> { None }
     fn sess(self) -> Option<&'tcx Session> { None }
@@ -136,7 +218,7 @@ impl<'a, 'tcx> Metadata<'a, 'tcx> for (&'a CrateMetadata, TyCtxt<'tcx>) {
 }
 
 impl<'a, 'tcx, T: Encodable + Decodable> Lazy<T> {
-    crate fn decode<M: Metadata<'a, 'tcx>>(self, metadata: M) -> T {
+    fn decode<M: Metadata<'a, 'tcx>>(self, metadata: M) -> T {
         let mut dcx = metadata.decoder(self.position.get());
         dcx.lazy_state = LazyState::NodeStart(self.position);
         T::decode(&mut dcx).unwrap()
@@ -144,7 +226,7 @@ impl<'a, 'tcx, T: Encodable + Decodable> Lazy<T> {
 }
 
 impl<'a: 'x, 'tcx: 'x, 'x, T: Encodable + Decodable> Lazy<[T]> {
-    crate fn decode<M: Metadata<'a, 'tcx>>(
+    fn decode<M: Metadata<'a, 'tcx>>(
         self,
         metadata: M,
     ) -> impl ExactSizeIterator<Item = T> + Captures<'a> + Captures<'tcx> + 'x {
@@ -393,7 +475,11 @@ for DecodeContext<'a, 'tcx> {
 
 implement_ty_decoder!( DecodeContext<'a, 'tcx> );
 
-impl<'tcx> MetadataBlob {
+impl MetadataBlob {
+    crate fn new(metadata_ref: MetadataRef) -> MetadataBlob {
+        MetadataBlob(metadata_ref)
+    }
+
     crate fn is_compatible(&self) -> bool {
         self.raw_bytes().starts_with(METADATA_HEADER)
     }
@@ -467,14 +553,62 @@ impl<'tcx> EntryKind<'tcx> {
     }
 }
 
+impl CrateRoot<'_> {
+    crate fn is_proc_macro_crate(&self) -> bool {
+        self.proc_macro_data.is_some()
+    }
+
+    crate fn decode_crate_deps(
+        &self,
+        metadata: &'a MetadataBlob,
+    ) -> impl ExactSizeIterator<Item = CrateDep> + Captures<'a> {
+        self.crate_deps.decode(metadata)
+    }
+}
+
 impl<'a, 'tcx> CrateMetadata {
-    fn is_proc_macro_crate(&self) -> bool {
-        self.root.proc_macro_decls_static.is_some()
+    crate fn new(
+        sess: &Session,
+        blob: MetadataBlob,
+        root: CrateRoot<'static>,
+        raw_proc_macros: Option<&'static [ProcMacro]>,
+        cnum: CrateNum,
+        cnum_map: CrateNumMap,
+        dep_kind: DepKind,
+        source: CrateSource,
+        private_dep: bool,
+        host_hash: Option<Svh>,
+    ) -> CrateMetadata {
+        let def_path_table = record_time(&sess.perf_stats.decode_def_path_tables_time, || {
+            root.def_path_table.decode((&blob, sess))
+        });
+        let trait_impls = root.impls.decode((&blob, sess))
+            .map(|trait_impls| (trait_impls.trait_id, trait_impls.impls)).collect();
+        let alloc_decoding_state =
+            AllocDecodingState::new(root.interpret_alloc_index.decode(&blob).collect());
+        let dependencies = Lock::new(cnum_map.iter().cloned().collect());
+        CrateMetadata {
+            blob,
+            root,
+            def_path_table,
+            trait_impls,
+            raw_proc_macros,
+            source_map_import_info: Once::new(),
+            alloc_decoding_state,
+            dep_node_index: AtomicCell::new(DepNodeIndex::INVALID),
+            cnum,
+            cnum_map,
+            dependencies,
+            dep_kind: Lock::new(dep_kind),
+            source,
+            private_dep,
+            host_hash,
+            extern_crate: Lock::new(None),
+        }
     }
 
     fn is_proc_macro(&self, id: DefIndex) -> bool {
-        self.is_proc_macro_crate() &&
-            self.root.proc_macro_data.unwrap().decode(self).find(|x| *x == id).is_some()
+        self.root.proc_macro_data.and_then(|data| data.decode(self).find(|x| *x == id)).is_some()
     }
 
     fn maybe_kind(&self, item_id: DefIndex) -> Option<EntryKind<'tcx>> {
@@ -757,7 +891,7 @@ impl<'a, 'tcx> CrateMetadata {
 
     /// Iterates over the language items in the given crate.
     fn get_lang_items(&self, tcx: TyCtxt<'tcx>) -> &'tcx [(DefId, usize)] {
-        if self.is_proc_macro_crate() {
+        if self.root.is_proc_macro_crate() {
             // Proc macro crates do not export any lang-items to the target.
             &[]
         } else {
@@ -773,7 +907,7 @@ impl<'a, 'tcx> CrateMetadata {
         &self,
         tcx: TyCtxt<'tcx>,
     ) -> &'tcx FxHashMap<Symbol, DefId> {
-        tcx.arena.alloc(if self.is_proc_macro_crate() {
+        tcx.arena.alloc(if self.root.is_proc_macro_crate() {
             // Proc macro crates do not export any diagnostic-items to the target.
             Default::default()
         } else {
@@ -1081,7 +1215,7 @@ impl<'a, 'tcx> CrateMetadata {
         tcx: TyCtxt<'tcx>,
         filter: Option<DefId>,
     ) -> &'tcx [DefId] {
-        if self.is_proc_macro_crate() {
+        if self.root.is_proc_macro_crate() {
             // proc-macro crates export no trait impls.
             return &[]
         }
@@ -1125,7 +1259,7 @@ impl<'a, 'tcx> CrateMetadata {
 
 
     fn get_native_libraries(&self, sess: &Session) -> Vec<NativeLibrary> {
-        if self.is_proc_macro_crate() {
+        if self.root.is_proc_macro_crate() {
             // Proc macro crates do not have any *target* native libraries.
             vec![]
         } else {
@@ -1134,7 +1268,7 @@ impl<'a, 'tcx> CrateMetadata {
     }
 
     fn get_foreign_modules(&self, tcx: TyCtxt<'tcx>) -> &'tcx [ForeignModule] {
-        if self.is_proc_macro_crate() {
+        if self.root.is_proc_macro_crate() {
             // Proc macro crates do not have any *target* foreign modules.
             &[]
         } else {
@@ -1157,7 +1291,7 @@ impl<'a, 'tcx> CrateMetadata {
     }
 
     fn get_missing_lang_items(&self, tcx: TyCtxt<'tcx>) -> &'tcx [lang_items::LangItem] {
-        if self.is_proc_macro_crate() {
+        if self.root.is_proc_macro_crate() {
             // Proc macro crates do not depend on any target weak lang-items.
             &[]
         } else {
@@ -1181,7 +1315,7 @@ impl<'a, 'tcx> CrateMetadata {
         &self,
         tcx: TyCtxt<'tcx>,
     ) -> Vec<(ExportedSymbol<'tcx>, SymbolExportLevel)> {
-        if self.is_proc_macro_crate() {
+        if self.root.is_proc_macro_crate() {
             // If this crate is a custom derive crate, then we're not even going to
             // link those in so we skip those crates.
             vec![]
@@ -1296,7 +1430,7 @@ impl<'a, 'tcx> CrateMetadata {
     fn imported_source_files(
         &'a self,
         local_source_map: &source_map::SourceMap,
-    ) -> &[cstore::ImportedSourceFile] {
+    ) -> &[ImportedSourceFile] {
         self.source_map_import_info.init_locking(|| {
             let external_source_map = self.root.source_map.decode(self);
 
@@ -1351,7 +1485,7 @@ impl<'a, 'tcx> CrateMetadata {
                        local_version.name, start_pos, end_pos,
                        local_version.start_pos, local_version.end_pos);
 
-                cstore::ImportedSourceFile {
+                ImportedSourceFile {
                     original_start_pos: start_pos,
                     original_end_pos: end_pos,
                     translated_source_file: local_version,
@@ -1374,7 +1508,7 @@ impl<'a, 'tcx> CrateMetadata {
             // would always write the same value.
 
             let def_path_hash = self.def_path_hash(CRATE_DEF_INDEX);
-            let dep_node = def_path_hash.to_dep_node(DepKind::CrateMetadata);
+            let dep_node = def_path_hash.to_dep_node(dep_graph::DepKind::CrateMetadata);
 
             dep_node_index = tcx.dep_graph.dep_node_index_of(&dep_node);
             assert!(dep_node_index != DepNodeIndex::INVALID);
diff --git a/src/librustc_metadata/rmeta/decoder/cstore_impl.rs b/src/librustc_metadata/rmeta/decoder/cstore_impl.rs
index a6cb3864ca7..abb0ceb4ff4 100644
--- a/src/librustc_metadata/rmeta/decoder/cstore_impl.rs
+++ b/src/librustc_metadata/rmeta/decoder/cstore_impl.rs
@@ -52,7 +52,7 @@ macro_rules! provide {
                 assert!(!$def_id.is_local());
 
                 let $cdata = $tcx.crate_data_as_any($def_id.krate);
-                let $cdata = $cdata.downcast_ref::<cstore::CrateMetadata>()
+                let $cdata = $cdata.downcast_ref::<rmeta::CrateMetadata>()
                     .expect("CrateStore created data is not a CrateMetadata");
 
                 if $tcx.dep_graph.is_fully_enabled() {
@@ -410,7 +410,7 @@ impl cstore::CStore {
         let _prof_timer = sess.prof.generic_activity("metadata_load_macro");
 
         let data = self.get_crate_data(id.krate);
-        if data.is_proc_macro_crate() {
+        if data.root.is_proc_macro_crate() {
             return LoadedMacro::ProcMacro(data.load_proc_macro(id.index, sess));
         }
 
diff --git a/src/librustc_metadata/rmeta/mod.rs b/src/librustc_metadata/rmeta/mod.rs
index 850ee5afbc8..23c0204ee25 100644
--- a/src/librustc_metadata/rmeta/mod.rs
+++ b/src/librustc_metadata/rmeta/mod.rs
@@ -14,6 +14,7 @@ use rustc::ty::{self, Ty, ReprOptions};
 use rustc_target::spec::{PanicStrategy, TargetTriple};
 use rustc_index::vec::IndexVec;
 use rustc_data_structures::svh::Svh;
+use rustc_data_structures::sync::MetadataRef;
 use rustc_serialize::Encodable;
 use syntax::{ast, attr};
 use syntax::edition::Edition;
@@ -24,6 +25,7 @@ use std::marker::PhantomData;
 use std::num::NonZeroUsize;
 
 pub use decoder::{provide, provide_extern};
+crate use decoder::{CrateMetadata, CrateNumMap, MetadataBlob};
 
 mod decoder;
 mod encoder;
@@ -49,7 +51,7 @@ crate const METADATA_HEADER: &[u8; 8] =
 
 /// Additional metadata for a `Lazy<T>` where `T` may not be `Sized`,
 /// e.g. for `Lazy<[T]>`, this is the length (count of `T` values).
-crate trait LazyMeta {
+trait LazyMeta {
     type Meta: Copy + 'static;
 
     /// Returns the minimum encoded size.
@@ -103,7 +105,7 @@ impl<T: Encodable> LazyMeta for [T] {
 #[must_use]
 // FIXME(#59875) the `Meta` parameter only exists to dodge
 // invariance wrt `T` (coming from the `meta: T::Meta` field).
-crate struct Lazy<T, Meta = <T as LazyMeta>::Meta>
+struct Lazy<T, Meta = <T as LazyMeta>::Meta>
     where T: ?Sized + LazyMeta<Meta = Meta>,
           Meta: 'static + Copy,
 {
@@ -186,7 +188,7 @@ crate struct CrateRoot<'tcx> {
     proc_macro_decls_static: Option<DefIndex>,
     proc_macro_stability: Option<attr::Stability>,
 
-    pub crate_deps: Lazy<[CrateDep]>,
+    crate_deps: Lazy<[CrateDep]>,
     dylib_dependency_formats: Lazy<[Option<LinkagePreference>]>,
     lib_features: Lazy<[(Symbol, Option<Symbol>)]>,
     lang_items: Lazy<[(DefIndex, usize)]>,
@@ -195,16 +197,15 @@ crate struct CrateRoot<'tcx> {
     native_libraries: Lazy<[NativeLibrary]>,
     foreign_modules: Lazy<[ForeignModule]>,
     source_map: Lazy<[syntax_pos::SourceFile]>,
-    pub def_path_table: Lazy<hir::map::definitions::DefPathTable>,
-    pub impls: Lazy<[TraitImpls]>,
+    def_path_table: Lazy<hir::map::definitions::DefPathTable>,
+    impls: Lazy<[TraitImpls]>,
     exported_symbols: Lazy!([(ExportedSymbol<'tcx>, SymbolExportLevel)]),
-    pub interpret_alloc_index: Lazy<[u32]>,
+    interpret_alloc_index: Lazy<[u32]>,
 
     per_def: LazyPerDefTables<'tcx>,
 
-    /// The DefIndex's of any proc macros delcared by
-    /// this crate
-    pub proc_macro_data: Option<Lazy<[DefIndex]>>,
+    /// The DefIndex's of any proc macros delcared by this crate.
+    proc_macro_data: Option<Lazy<[DefIndex]>>,
 
     compiler_builtins: bool,
     pub needs_allocator: bool,
@@ -227,8 +228,8 @@ crate struct CrateDep {
 
 #[derive(RustcEncodable, RustcDecodable)]
 crate struct TraitImpls {
-    pub trait_id: (u32, DefIndex),
-    pub impls: Lazy<[DefIndex]>,
+    trait_id: (u32, DefIndex),
+    impls: Lazy<[DefIndex]>,
 }
 
 #[derive(RustcEncodable, RustcDecodable)]
diff --git a/src/librustc_mir/Cargo.toml b/src/librustc_mir/Cargo.toml
index daa2617bd9e..9bc6d32b7cb 100644
--- a/src/librustc_mir/Cargo.toml
+++ b/src/librustc_mir/Cargo.toml
@@ -22,6 +22,7 @@ rustc_data_structures = { path = "../librustc_data_structures" }
 rustc_index = { path = "../librustc_index" }
 rustc_errors = { path = "../librustc_errors" }
 rustc_lexer = { path = "../librustc_lexer" }
+rustc_macros = { path = "../librustc_macros" }
 rustc_serialize = { path = "../libserialize", package = "serialize" }
 syntax = { path = "../libsyntax" }
 syntax_pos = { path = "../libsyntax_pos" }
diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs
index 92358ad247e..08640476f7a 100644
--- a/src/librustc_mir/interpret/eval_context.rs
+++ b/src/librustc_mir/interpret/eval_context.rs
@@ -18,6 +18,7 @@ use rustc::mir::interpret::{
     InterpResult, truncate, sign_extend,
 };
 use rustc_data_structures::fx::FxHashMap;
+use rustc_macros::HashStable;
 
 use super::{
     Immediate, Operand, MemPlace, MPlaceTy, Place, PlaceTy, ScalarMaybeUndef,
@@ -93,7 +94,7 @@ pub struct Frame<'mir, 'tcx, Tag=(), Extra=()> {
     pub stmt: usize,
 }
 
-#[derive(Clone, Eq, PartialEq, Debug)] // Miri debug-prints these
+#[derive(Clone, Eq, PartialEq, Debug, HashStable)] // Miri debug-prints these
 pub enum StackPopCleanup {
     /// Jump to the next block in the caller, or cause UB if None (that's a function
     /// that may never return). Also store layout of return place so
@@ -109,15 +110,16 @@ pub enum StackPopCleanup {
 }
 
 /// State of a local variable including a memoized layout
-#[derive(Clone, PartialEq, Eq)]
+#[derive(Clone, PartialEq, Eq, HashStable)]
 pub struct LocalState<'tcx, Tag=(), Id=AllocId> {
     pub value: LocalValue<Tag, Id>,
     /// Don't modify if `Some`, this is only used to prevent computing the layout twice
+    #[stable_hasher(ignore)]
     pub layout: Cell<Option<TyLayout<'tcx>>>,
 }
 
 /// Current value of a local variable
-#[derive(Clone, PartialEq, Eq, Debug)] // Miri debug-prints these
+#[derive(Clone, PartialEq, Eq, Debug, HashStable)] // Miri debug-prints these
 pub enum LocalValue<Tag=(), Id=AllocId> {
     /// This local is not currently alive, and cannot be used at all.
     Dead,
diff --git a/src/librustc_mir/interpret/operand.rs b/src/librustc_mir/interpret/operand.rs
index 4d2ccdc20da..cfa70164cdc 100644
--- a/src/librustc_mir/interpret/operand.rs
+++ b/src/librustc_mir/interpret/operand.rs
@@ -18,6 +18,7 @@ use super::{
     MemPlace, MPlaceTy, PlaceTy, Place,
 };
 pub use rustc::mir::interpret::ScalarMaybeUndef;
+use rustc_macros::HashStable;
 
 /// An `Immediate` represents a single immediate self-contained Rust value.
 ///
@@ -26,7 +27,7 @@ pub use rustc::mir::interpret::ScalarMaybeUndef;
 /// operations and fat pointers. This idea was taken from rustc's codegen.
 /// In particular, thanks to `ScalarPair`, arithmetic operations and casts can be entirely
 /// defined on `Immediate`, and do not have to work with a `Place`.
-#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+#[derive(Copy, Clone, Debug, PartialEq, Eq, HashStable)]
 pub enum Immediate<Tag=(), Id=AllocId> {
     Scalar(ScalarMaybeUndef<Tag, Id>),
     ScalarPair(ScalarMaybeUndef<Tag, Id>, ScalarMaybeUndef<Tag, Id>),
@@ -103,7 +104,7 @@ impl<'tcx, Tag> ::std::ops::Deref for ImmTy<'tcx, Tag> {
 /// An `Operand` is the result of computing a `mir::Operand`. It can be immediate,
 /// or still in memory. The latter is an optimization, to delay reading that chunk of
 /// memory and to avoid having to store arbitrary-sized data here.
-#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+#[derive(Copy, Clone, Debug, PartialEq, Eq, HashStable)]
 pub enum Operand<Tag=(), Id=AllocId> {
     Immediate(Immediate<Tag, Id>),
     Indirect(MemPlace<Tag, Id>),
diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs
index 0bd47edc046..088fbe1695e 100644
--- a/src/librustc_mir/interpret/place.rs
+++ b/src/librustc_mir/interpret/place.rs
@@ -12,6 +12,7 @@ use rustc::ty::layout::{
     self, Size, Align, LayoutOf, TyLayout, HasDataLayout, VariantIdx, PrimitiveExt
 };
 use rustc::ty::TypeFoldable;
+use rustc_macros::HashStable;
 
 use super::{
     GlobalId, AllocId, Allocation, Scalar, InterpResult, Pointer, PointerArithmetic,
@@ -19,7 +20,7 @@ use super::{
     RawConst, Immediate, ImmTy, ScalarMaybeUndef, Operand, OpTy, MemoryKind, LocalValue,
 };
 
-#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
+#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable)]
 pub struct MemPlace<Tag=(), Id=AllocId> {
     /// A place may have an integral pointer for ZSTs, and since it might
     /// be turned back into a reference before ever being dereferenced.
@@ -32,7 +33,7 @@ pub struct MemPlace<Tag=(), Id=AllocId> {
     pub meta: Option<Scalar<Tag, Id>>,
 }
 
-#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
+#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable)]
 pub enum Place<Tag=(), Id=AllocId> {
     /// A place referring to a value allocated in the `Memory` system.
     Ptr(MemPlace<Tag, Id>),
diff --git a/src/librustc_mir/interpret/snapshot.rs b/src/librustc_mir/interpret/snapshot.rs
index 7f3ea0283cd..b460badd1fd 100644
--- a/src/librustc_mir/interpret/snapshot.rs
+++ b/src/librustc_mir/interpret/snapshot.rs
@@ -19,6 +19,7 @@ use rustc::ty::layout::{Align, Size};
 use rustc_data_structures::fx::FxHashSet;
 use rustc_index::vec::IndexVec;
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
+use rustc_macros::HashStable;
 use syntax::ast::Mutability;
 use syntax::source_map::Span;
 
@@ -197,21 +198,12 @@ impl_snapshot_for!(enum ScalarMaybeUndef {
     Undef,
 });
 
-impl_stable_hash_for!(struct crate::interpret::MemPlace {
-    ptr,
-    align,
-    meta,
-});
 impl_snapshot_for!(struct MemPlace {
     ptr,
     meta,
     align -> *align, // just copy alignment verbatim
 });
 
-impl_stable_hash_for!(enum crate::interpret::Place {
-    Ptr(mem_place),
-    Local { frame, local },
-});
 impl<'a, Ctx> Snapshot<'a, Ctx> for Place
     where Ctx: SnapshotContext<'a>,
 {
@@ -229,29 +221,16 @@ impl<'a, Ctx> Snapshot<'a, Ctx> for Place
     }
 }
 
-impl_stable_hash_for!(enum crate::interpret::Immediate {
-    Scalar(x),
-    ScalarPair(x, y),
-});
 impl_snapshot_for!(enum Immediate {
     Scalar(s),
     ScalarPair(s, t),
 });
 
-impl_stable_hash_for!(enum crate::interpret::Operand {
-    Immediate(x),
-    Indirect(x),
-});
 impl_snapshot_for!(enum Operand {
     Immediate(v),
     Indirect(m),
 });
 
-impl_stable_hash_for!(enum crate::interpret::LocalValue {
-    Dead,
-    Uninitialized,
-    Live(x),
-});
 impl_snapshot_for!(enum LocalValue {
     Dead,
     Uninitialized,
@@ -314,11 +293,6 @@ impl<'a, Ctx> Snapshot<'a, Ctx> for &'a Allocation
     }
 }
 
-impl_stable_hash_for!(enum crate::interpret::eval_context::StackPopCleanup {
-    Goto { ret, unwind },
-    None { cleanup },
-});
-
 #[derive(Eq, PartialEq)]
 struct FrameSnapshot<'a, 'tcx> {
     instance: ty::Instance<'tcx>,
@@ -383,11 +357,6 @@ impl<'a, 'tcx, Ctx> Snapshot<'a, Ctx> for &'a LocalState<'tcx>
     }
 }
 
-impl_stable_hash_for!(struct LocalState<'tcx> {
-    value,
-    layout -> _,
-});
-
 impl<'b, 'mir, 'tcx> SnapshotContext<'b>
     for Memory<'mir, 'tcx, CompileTimeInterpreter<'mir, 'tcx>>
 {
@@ -399,7 +368,10 @@ impl<'b, 'mir, 'tcx> SnapshotContext<'b>
 /// The virtual machine state during const-evaluation at a given point in time.
 /// We assume the `CompileTimeInterpreter` has no interesting extra state that
 /// is worth considering here.
+#[derive(HashStable)]
 struct InterpSnapshot<'mir, 'tcx> {
+    // Not hashing memory: Avoid hashing memory all the time during execution
+    #[stable_hasher(ignore)]
     memory: Memory<'mir, 'tcx, CompileTimeInterpreter<'mir, 'tcx>>,
     stack: Vec<Frame<'mir, 'tcx>>,
 }
@@ -434,12 +406,6 @@ impl<'mir, 'tcx> Hash for InterpSnapshot<'mir, 'tcx> {
     }
 }
 
-impl_stable_hash_for!(impl<> for struct InterpSnapshot<'mir, 'tcx> {
-    // Not hashing memory: Avoid hashing memory all the time during execution
-    memory -> _,
-    stack,
-});
-
 impl<'mir, 'tcx> Eq for InterpSnapshot<'mir, 'tcx> {}
 
 impl<'mir, 'tcx> PartialEq for InterpSnapshot<'mir, 'tcx> {
diff --git a/src/librustc_passes/liveness.rs b/src/librustc_passes/liveness.rs
index fb06808619f..6847e45458a 100644
--- a/src/librustc_passes/liveness.rs
+++ b/src/librustc_passes/liveness.rs
@@ -987,8 +987,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
         opt_expr.map_or(succ, |expr| self.propagate_through_expr(expr, succ))
     }
 
-    fn propagate_through_expr(&mut self, expr: &Expr, succ: LiveNode)
-                              -> LiveNode {
+    fn propagate_through_expr(&mut self, expr: &Expr, succ: LiveNode) -> LiveNode {
         debug!("propagate_through_expr: {}", self.ir.tcx.hir().hir_to_pretty_string(expr.hir_id));
 
         match expr.kind {
@@ -1074,7 +1073,15 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
 
                 match target {
                     Some(b) => self.propagate_through_opt_expr(opt_expr.as_ref().map(|e| &**e), b),
-                    None => span_bug!(expr.span, "break to unknown label")
+                    None => {
+                        // FIXME: This should have been checked earlier. Once this is fixed,
+                        // replace with `delay_span_bug`. (#62480)
+                        self.ir.tcx.sess.struct_span_err(
+                            expr.span,
+                            "`break` to unknown label",
+                        ).emit();
+                        errors::FatalError.raise()
+                    }
                 }
             }
 
diff --git a/src/librustdoc/html/layout.rs b/src/librustdoc/html/layout.rs
index 8249e69e9a7..a6f37053687 100644
--- a/src/librustdoc/html/layout.rs
+++ b/src/librustdoc/html/layout.rs
@@ -87,10 +87,11 @@ pub fn render<T: Print, S: Print>(
     </div>\
     <script src=\"{static_root_path}theme{suffix}.js\"></script>\
     <nav class=\"sub\">\
-        <form class=\"search-form js-only\">\
+        <form class=\"search-form\">\
             <div class=\"search-container\">\
                 <div>{filter_crates}\
                     <input class=\"search-input\" name=\"search\" \
+                           disabled \
                            autocomplete=\"off\" \
                            spellcheck=\"false\" \
                            placeholder=\"Click or press ‘S’ to search, ‘?’ for more options…\" \
diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs
index 2fa56f58512..bd2a6602e16 100644
--- a/src/librustdoc/html/render.rs
+++ b/src/librustdoc/html/render.rs
@@ -882,7 +882,9 @@ themePicker.onblur = handleThemeButtonsBlur;
         v.push_str(&minify_replacer(
             &format!("{}\n{}", variables.join(""), all_indexes.join("\n")),
             options.enable_minification));
-        v.push_str("initSearch(searchIndex);addSearchOptions(searchIndex);");
+        // "addSearchOptions" has to be called first so the crate filtering can be set before the
+        // search might start (if it's set into the URL for example).
+        v.push_str("addSearchOptions(searchIndex);initSearch(searchIndex);");
         cx.shared.fs.write(&dst, &v)?;
     }
     if options.enable_index_page {
diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js
index 197efb7cac8..cc0f470b349 100644
--- a/src/librustdoc/html/static/main.js
+++ b/src/librustdoc/html/static/main.js
@@ -142,10 +142,6 @@ function getSearchElement() {
     var TY_PRIMITIVE = itemTypes.indexOf("primitive");
     var TY_KEYWORD = itemTypes.indexOf("keyword");
 
-    onEachLazy(document.getElementsByClassName("js-only"), function(e) {
-        removeClass(e, "js-only");
-    });
-
     function getQueryStringParams() {
         var params = {};
         window.location.search.substring(1).split("&").
@@ -525,21 +521,6 @@ function getSearchElement() {
         var OUTPUT_DATA = 1;
         var params = getQueryStringParams();
 
-        // Set the crate filter from saved storage, if the current page has the saved crate filter.
-        //
-        // If not, ignore the crate filter -- we want to support filtering for crates on sites like
-        // doc.rust-lang.org where the crates may differ from page to page while on the same domain.
-        var savedCrate = getCurrentValue("rustdoc-saved-filter-crate");
-        if (savedCrate !== null) {
-            onEachLazy(document.getElementById("crate-search").getElementsByTagName("option"),
-                       function(e) {
-                if (e.value === savedCrate) {
-                    document.getElementById("crate-search").value = e.value;
-                    return true;
-                }
-            });
-        }
-
         // Populate search bar with query string search term when provided,
         // but only if the input bar is empty. This avoid the obnoxious issue
         // where you start trying to do a search, and the index loads, and
@@ -2633,12 +2614,26 @@ function getSearchElement() {
             }
             return 0;
         });
+        var savedCrate = getCurrentValue("rustdoc-saved-filter-crate");
         for (var i = 0; i < crates_text.length; ++i) {
             var option = document.createElement("option");
             option.value = crates_text[i];
             option.innerText = crates_text[i];
             elem.appendChild(option);
+            // Set the crate filter from saved storage, if the current page has the saved crate
+            // filter.
+            //
+            // If not, ignore the crate filter -- we want to support filtering for crates on sites
+            // like doc.rust-lang.org where the crates may differ from page to page while on the
+            // same domain.
+            if (crates_text[i] === savedCrate) {
+                elem.value = savedCrate;
+            }
         }
+
+        if (search_input) {
+            search_input.removeAttribute('disabled');
+        };
     }
 
     window.addSearchOptions = addSearchOptions;
diff --git a/src/librustdoc/html/static/rustdoc.css b/src/librustdoc/html/static/rustdoc.css
index 6d2f6c7eda6..b2c48bf089b 100644
--- a/src/librustdoc/html/static/rustdoc.css
+++ b/src/librustdoc/html/static/rustdoc.css
@@ -203,7 +203,7 @@ nav.sub {
 
 /* Everything else */
 
-.js-only, .hidden {
+.hidden {
 	display: none !important;
 }
 
diff --git a/src/librustdoc/html/static/themes/dark.css b/src/librustdoc/html/static/themes/dark.css
index a60d543a539..f46bd6d6a10 100644
--- a/src/librustdoc/html/static/themes/dark.css
+++ b/src/librustdoc/html/static/themes/dark.css
@@ -177,6 +177,10 @@ a.test-arrow {
 	border-color: #008dfd;
 }
 
+.search-focus:disabled {
+	background-color: #c5c4c4;
+}
+
 #crate-search + .search-input:focus {
 	box-shadow: 0 0 8px 4px #078dd8;
 }
diff --git a/src/librustdoc/html/static/themes/light.css b/src/librustdoc/html/static/themes/light.css
index 351f027b942..ca67b1c1f82 100644
--- a/src/librustdoc/html/static/themes/light.css
+++ b/src/librustdoc/html/static/themes/light.css
@@ -177,6 +177,10 @@ a.test-arrow {
 	border-color: #66afe9;
 }
 
+.search-focus:disabled {
+	background-color: #e6e6e6;
+}
+
 #crate-search + .search-input:focus {
 	box-shadow: 0 0 8px #078dd8;
 }
diff --git a/src/libsyntax/feature_gate/builtin_attrs.rs b/src/libsyntax/feature_gate/builtin_attrs.rs
index 57dae23f0dc..a13a4475ef0 100644
--- a/src/libsyntax/feature_gate/builtin_attrs.rs
+++ b/src/libsyntax/feature_gate/builtin_attrs.rs
@@ -543,7 +543,10 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
     rustc_attr!(TEST, rustc_variance, Normal, template!(Word)),
     rustc_attr!(TEST, rustc_layout, Normal, template!(List: "field1, field2, ...")),
     rustc_attr!(TEST, rustc_regions, Normal, template!(Word)),
-    rustc_attr!(TEST, rustc_error, Whitelisted, template!(Word)),
+    rustc_attr!(
+        TEST, rustc_error, Whitelisted,
+        template!(Word, List: "delay_span_bug_from_inside_query")
+    ),
     rustc_attr!(TEST, rustc_dump_user_substs, Whitelisted, template!(Word)),
     rustc_attr!(TEST, rustc_if_this_changed, Whitelisted, template!(Word, List: "DepNode")),
     rustc_attr!(TEST, rustc_then_this_would_need, Whitelisted, template!(List: "DepNode")),
diff --git a/src/libsyntax_pos/symbol.rs b/src/libsyntax_pos/symbol.rs
index 86eaeeab5a4..1139bf67a36 100644
--- a/src/libsyntax_pos/symbol.rs
+++ b/src/libsyntax_pos/symbol.rs
@@ -236,6 +236,7 @@ symbols! {
         default_lib_allocator,
         default_type_parameter_fallback,
         default_type_params,
+        delay_span_bug_from_inside_query,
         deny,
         deprecated,
         deref,
diff --git a/src/test/incremental/delayed_span_bug.rs b/src/test/incremental/delayed_span_bug.rs
new file mode 100644
index 00000000000..2529e531e30
--- /dev/null
+++ b/src/test/incremental/delayed_span_bug.rs
@@ -0,0 +1,8 @@
+// revisions: cfail1 cfail2
+// should-ice
+// error-pattern: delayed span bug triggered by #[rustc_error(delay_span_bug_from_inside_query)]
+
+#![feature(rustc_attrs)]
+
+#[rustc_error(delay_span_bug_from_inside_query)]
+fn main() {}
diff --git a/src/test/run-make-fulldeps/reproducible-build-2/Makefile b/src/test/run-make-fulldeps/reproducible-build-2/Makefile
index 45c9a742723..fc912efed5e 100644
--- a/src/test/run-make-fulldeps/reproducible-build-2/Makefile
+++ b/src/test/run-make-fulldeps/reproducible-build-2/Makefile
@@ -2,6 +2,7 @@
 
 # ignore-musl
 # ignore-windows
+# ignore-macos (rust-lang/rust#66568)
 # Objects are reproducible but their path is not.
 
 all:  \
diff --git a/src/test/ui/associated-types/bound-lifetime-constrained.rs b/src/test/ui/associated-types/bound-lifetime-constrained.rs
index fb82b3fa666..4e6754c865d 100644
--- a/src/test/ui/associated-types/bound-lifetime-constrained.rs
+++ b/src/test/ui/associated-types/bound-lifetime-constrained.rs
@@ -45,4 +45,4 @@ fn clause2<T>() where T: for<'a> Fn() -> <() as Foo<'a>>::Item {
 }
 
 #[rustc_error]
-fn main() { } //[ok]~ ERROR compilation successful
+fn main() { } //[ok]~ ERROR fatal error triggered by #[rustc_error]
diff --git a/src/test/ui/associated-types/bound-lifetime-in-binding-only.ok.stderr b/src/test/ui/associated-types/bound-lifetime-in-binding-only.ok.stderr
index fcdb371a6e5..5ece425196c 100644
--- a/src/test/ui/associated-types/bound-lifetime-in-binding-only.ok.stderr
+++ b/src/test/ui/associated-types/bound-lifetime-in-binding-only.ok.stderr
@@ -1,4 +1,4 @@
-error: compilation successful
+error: fatal error triggered by #[rustc_error]
   --> $DIR/bound-lifetime-in-binding-only.rs:71:1
    |
 LL | fn main() { }
diff --git a/src/test/ui/associated-types/bound-lifetime-in-binding-only.rs b/src/test/ui/associated-types/bound-lifetime-in-binding-only.rs
index 843f5f06195..e714457ef7b 100644
--- a/src/test/ui/associated-types/bound-lifetime-in-binding-only.rs
+++ b/src/test/ui/associated-types/bound-lifetime-in-binding-only.rs
@@ -68,4 +68,4 @@ fn ok3<T>() where for<'a> Parameterized<'a>: Foo<Item=&'a i32> {
 }
 
 #[rustc_error]
-fn main() { } //[ok]~ ERROR compilation successful
+fn main() { } //[ok]~ ERROR fatal error triggered by #[rustc_error]
diff --git a/src/test/ui/associated-types/bound-lifetime-in-return-only.ok.stderr b/src/test/ui/associated-types/bound-lifetime-in-return-only.ok.stderr
index 504d68e66e2..8c098098311 100644
--- a/src/test/ui/associated-types/bound-lifetime-in-return-only.ok.stderr
+++ b/src/test/ui/associated-types/bound-lifetime-in-return-only.ok.stderr
@@ -1,4 +1,4 @@
-error: compilation successful
+error: fatal error triggered by #[rustc_error]
   --> $DIR/bound-lifetime-in-return-only.rs:49:1
    |
 LL | fn main() { }
diff --git a/src/test/ui/associated-types/bound-lifetime-in-return-only.rs b/src/test/ui/associated-types/bound-lifetime-in-return-only.rs
index 9c0dc61494d..a60ccb6c4b2 100644
--- a/src/test/ui/associated-types/bound-lifetime-in-return-only.rs
+++ b/src/test/ui/associated-types/bound-lifetime-in-return-only.rs
@@ -46,4 +46,4 @@ fn ok2(_: &dyn for<'a,'b> Fn<(&'b Parameterized<'a>,), Output=&'a i32>) {
 }
 
 #[rustc_error]
-fn main() { } //[ok]~ ERROR compilation successful
+fn main() { } //[ok]~ ERROR fatal error triggered by #[rustc_error]
diff --git a/src/test/ui/associated-types/cache/project-fn-ret-contravariant.ok.stderr b/src/test/ui/associated-types/cache/project-fn-ret-contravariant.ok.stderr
index 15bbea671c5..baa8e6f82f6 100644
--- a/src/test/ui/associated-types/cache/project-fn-ret-contravariant.ok.stderr
+++ b/src/test/ui/associated-types/cache/project-fn-ret-contravariant.ok.stderr
@@ -1,4 +1,4 @@
-error: compilation successful
+error: fatal error triggered by #[rustc_error]
   --> $DIR/project-fn-ret-contravariant.rs:50:1
    |
 LL | fn main() { }
diff --git a/src/test/ui/associated-types/cache/project-fn-ret-contravariant.oneuse.stderr b/src/test/ui/associated-types/cache/project-fn-ret-contravariant.oneuse.stderr
index 15bbea671c5..baa8e6f82f6 100644
--- a/src/test/ui/associated-types/cache/project-fn-ret-contravariant.oneuse.stderr
+++ b/src/test/ui/associated-types/cache/project-fn-ret-contravariant.oneuse.stderr
@@ -1,4 +1,4 @@
-error: compilation successful
+error: fatal error triggered by #[rustc_error]
   --> $DIR/project-fn-ret-contravariant.rs:50:1
    |
 LL | fn main() { }
diff --git a/src/test/ui/associated-types/cache/project-fn-ret-contravariant.rs b/src/test/ui/associated-types/cache/project-fn-ret-contravariant.rs
index d953325df23..ebf52918153 100644
--- a/src/test/ui/associated-types/cache/project-fn-ret-contravariant.rs
+++ b/src/test/ui/associated-types/cache/project-fn-ret-contravariant.rs
@@ -48,5 +48,5 @@ fn transmute<'a,'b>(x: &'a u32, y: &'b u32) -> (&'a u32, &'b u32) {
 
 #[rustc_error]
 fn main() { }
-//[ok]~^ ERROR compilation successful
-//[oneuse]~^^ ERROR compilation successful
+//[ok]~^ ERROR fatal error triggered by #[rustc_error]
+//[oneuse]~^^ ERROR fatal error triggered by #[rustc_error]
diff --git a/src/test/ui/associated-types/cache/project-fn-ret-invariant.ok.stderr b/src/test/ui/associated-types/cache/project-fn-ret-invariant.ok.stderr
index 8110ed40cfe..8f445acf2b9 100644
--- a/src/test/ui/associated-types/cache/project-fn-ret-invariant.ok.stderr
+++ b/src/test/ui/associated-types/cache/project-fn-ret-invariant.ok.stderr
@@ -1,4 +1,4 @@
-error: compilation successful
+error: fatal error triggered by #[rustc_error]
   --> $DIR/project-fn-ret-invariant.rs:59:1
    |
 LL | fn main() { }
diff --git a/src/test/ui/associated-types/cache/project-fn-ret-invariant.rs b/src/test/ui/associated-types/cache/project-fn-ret-invariant.rs
index 54b6e3642c2..23d873212ed 100644
--- a/src/test/ui/associated-types/cache/project-fn-ret-invariant.rs
+++ b/src/test/ui/associated-types/cache/project-fn-ret-invariant.rs
@@ -57,4 +57,4 @@ fn transmute<'a,'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) {
 
 #[rustc_error]
 fn main() { }
-//[ok]~^ ERROR compilation successful
+//[ok]~^ ERROR fatal error triggered by #[rustc_error]
diff --git a/src/test/ui/associated-types/higher-ranked-projection.good.stderr b/src/test/ui/associated-types/higher-ranked-projection.good.stderr
index 16fef0510f8..63d88543607 100644
--- a/src/test/ui/associated-types/higher-ranked-projection.good.stderr
+++ b/src/test/ui/associated-types/higher-ranked-projection.good.stderr
@@ -1,4 +1,4 @@
-error: compilation successful
+error: fatal error triggered by #[rustc_error]
   --> $DIR/higher-ranked-projection.rs:24:1
    |
 LL | / fn main() {
diff --git a/src/test/ui/associated-types/higher-ranked-projection.rs b/src/test/ui/associated-types/higher-ranked-projection.rs
index a2ea6d8f206..5315e21b0f5 100644
--- a/src/test/ui/associated-types/higher-ranked-projection.rs
+++ b/src/test/ui/associated-types/higher-ranked-projection.rs
@@ -21,7 +21,7 @@ fn foo<U, T>(_t: T)
 {}
 
 #[rustc_error]
-fn main() { //[good]~ ERROR compilation successful
+fn main() { //[good]~ ERROR fatal error triggered by #[rustc_error]
     foo(());
     //[bad]~^ ERROR type mismatch
 }
diff --git a/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_bound_a.stderr b/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_bound_a.stderr
index 9ec36f4c142..6aba6466fad 100644
--- a/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_bound_a.stderr
+++ b/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_bound_a.stderr
@@ -1,4 +1,4 @@
-error: compilation successful
+error: fatal error triggered by #[rustc_error]
   --> $DIR/hr-subtype.rs:100:1
    |
 LL | / fn main() {
diff --git a/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_bound_b.stderr b/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_bound_b.stderr
index 9ec36f4c142..6aba6466fad 100644
--- a/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_bound_b.stderr
+++ b/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_bound_b.stderr
@@ -1,4 +1,4 @@
-error: compilation successful
+error: fatal error triggered by #[rustc_error]
   --> $DIR/hr-subtype.rs:100:1
    |
 LL | / fn main() {
diff --git a/src/test/ui/hr-subtype/hr-subtype.bound_co_a_vs_bound_co_b.stderr b/src/test/ui/hr-subtype/hr-subtype.bound_co_a_vs_bound_co_b.stderr
index 9ec36f4c142..6aba6466fad 100644
--- a/src/test/ui/hr-subtype/hr-subtype.bound_co_a_vs_bound_co_b.stderr
+++ b/src/test/ui/hr-subtype/hr-subtype.bound_co_a_vs_bound_co_b.stderr
@@ -1,4 +1,4 @@
-error: compilation successful
+error: fatal error triggered by #[rustc_error]
   --> $DIR/hr-subtype.rs:100:1
    |
 LL | / fn main() {
diff --git a/src/test/ui/hr-subtype/hr-subtype.bound_inv_a_vs_bound_inv_b.stderr b/src/test/ui/hr-subtype/hr-subtype.bound_inv_a_vs_bound_inv_b.stderr
index 9ec36f4c142..6aba6466fad 100644
--- a/src/test/ui/hr-subtype/hr-subtype.bound_inv_a_vs_bound_inv_b.stderr
+++ b/src/test/ui/hr-subtype/hr-subtype.bound_inv_a_vs_bound_inv_b.stderr
@@ -1,4 +1,4 @@
-error: compilation successful
+error: fatal error triggered by #[rustc_error]
   --> $DIR/hr-subtype.rs:100:1
    |
 LL | / fn main() {
diff --git a/src/test/ui/hr-subtype/hr-subtype.free_x_vs_free_x.stderr b/src/test/ui/hr-subtype/hr-subtype.free_x_vs_free_x.stderr
index 9ec36f4c142..6aba6466fad 100644
--- a/src/test/ui/hr-subtype/hr-subtype.free_x_vs_free_x.stderr
+++ b/src/test/ui/hr-subtype/hr-subtype.free_x_vs_free_x.stderr
@@ -1,4 +1,4 @@
-error: compilation successful
+error: fatal error triggered by #[rustc_error]
   --> $DIR/hr-subtype.rs:100:1
    |
 LL | / fn main() {
diff --git a/src/test/ui/hr-subtype/hr-subtype.rs b/src/test/ui/hr-subtype/hr-subtype.rs
index 2f7c1e6fd8c..b31f198bd97 100644
--- a/src/test/ui/hr-subtype/hr-subtype.rs
+++ b/src/test/ui/hr-subtype/hr-subtype.rs
@@ -98,9 +98,9 @@ check! { bound_a_b_ret_a_vs_bound_a_ret_a: (for<'a,'b> fn(&'a u32, &'b u32) -> &
 
 #[rustc_error]
 fn main() {
-//[bound_a_vs_bound_a]~^ ERROR compilation successful
-//[bound_a_vs_bound_b]~^^ ERROR compilation successful
-//[bound_inv_a_vs_bound_inv_b]~^^^ ERROR compilation successful
-//[bound_co_a_vs_bound_co_b]~^^^^ ERROR compilation successful
-//[free_x_vs_free_x]~^^^^^ ERROR compilation successful
+//[bound_a_vs_bound_a]~^ ERROR fatal error triggered by #[rustc_error]
+//[bound_a_vs_bound_b]~^^ ERROR fatal error triggered by #[rustc_error]
+//[bound_inv_a_vs_bound_inv_b]~^^^ ERROR fatal error triggered by #[rustc_error]
+//[bound_co_a_vs_bound_co_b]~^^^^ ERROR fatal error triggered by #[rustc_error]
+//[free_x_vs_free_x]~^^^^^ ERROR fatal error triggered by #[rustc_error]
 }
diff --git a/src/test/ui/issues/issue-62480.rs b/src/test/ui/issues/issue-62480.rs
new file mode 100644
index 00000000000..bc3e6c69a60
--- /dev/null
+++ b/src/test/ui/issues/issue-62480.rs
@@ -0,0 +1,10 @@
+#![feature(label_break_value)]
+
+fn main() {
+    // This used to ICE during liveness check because `target_id` passed to
+    // `propagate_through_expr` would be the closure and not the `loop`, which wouldn't be found in
+    // `self.break_ln`. (#62480)
+    'a: {
+        || break 'a //~ ERROR `break` to unknown label
+    }
+}
diff --git a/src/test/ui/issues/issue-62480.stderr b/src/test/ui/issues/issue-62480.stderr
new file mode 100644
index 00000000000..de8451ad7df
--- /dev/null
+++ b/src/test/ui/issues/issue-62480.stderr
@@ -0,0 +1,8 @@
+error: `break` to unknown label
+  --> $DIR/issue-62480.rs:8:12
+   |
+LL |         || break 'a
+   |            ^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/proc-macro/no-macro-use-attr.rs b/src/test/ui/proc-macro/no-macro-use-attr.rs
index 15ab431fe75..a8a8fa4e19a 100644
--- a/src/test/ui/proc-macro/no-macro-use-attr.rs
+++ b/src/test/ui/proc-macro/no-macro-use-attr.rs
@@ -7,4 +7,4 @@ extern crate test_macros;
 //~^ WARN unused extern crate
 
 #[rustc_error]
-fn main() {} //~ ERROR compilation successful
+fn main() {} //~ ERROR fatal error triggered by #[rustc_error]
diff --git a/src/test/ui/proc-macro/no-macro-use-attr.stderr b/src/test/ui/proc-macro/no-macro-use-attr.stderr
index 87487bcc7d6..50552ea7dbb 100644
--- a/src/test/ui/proc-macro/no-macro-use-attr.stderr
+++ b/src/test/ui/proc-macro/no-macro-use-attr.stderr
@@ -10,7 +10,7 @@ note: lint level defined here
 LL | #![warn(unused_extern_crates)]
    |         ^^^^^^^^^^^^^^^^^^^^
 
-error: compilation successful
+error: fatal error triggered by #[rustc_error]
   --> $DIR/no-macro-use-attr.rs:10:1
    |
 LL | fn main() {}
diff --git a/src/test/ui/rfc1445/feature-gate.rs b/src/test/ui/rfc1445/feature-gate.rs
index 38d6406efa5..21addfab8f5 100644
--- a/src/test/ui/rfc1445/feature-gate.rs
+++ b/src/test/ui/rfc1445/feature-gate.rs
@@ -18,7 +18,7 @@ struct Foo {
 const FOO: Foo = Foo { x: 0 };
 
 #[rustc_error]
-fn main() { //[with_gate]~ ERROR compilation successful
+fn main() { //[with_gate]~ ERROR fatal error triggered by #[rustc_error]
     let y = Foo { x: 1 };
     match y {
         FOO => { }
diff --git a/src/test/ui/rfc1445/feature-gate.with_gate.stderr b/src/test/ui/rfc1445/feature-gate.with_gate.stderr
index ca8dc75c533..fabbfd5c70b 100644
--- a/src/test/ui/rfc1445/feature-gate.with_gate.stderr
+++ b/src/test/ui/rfc1445/feature-gate.with_gate.stderr
@@ -1,4 +1,4 @@
-error: compilation successful
+error: fatal error triggered by #[rustc_error]
   --> $DIR/feature-gate.rs:21:1
    |
 LL | / fn main() {
diff --git a/src/test/ui/rustc-error.rs b/src/test/ui/rustc-error.rs
index 0504198032c..69d57948fb5 100644
--- a/src/test/ui/rustc-error.rs
+++ b/src/test/ui/rustc-error.rs
@@ -2,5 +2,5 @@
 
 #[rustc_error]
 fn main() {
-    //~^ ERROR compilation successful
+    //~^ ERROR fatal error triggered by #[rustc_error]
 }
diff --git a/src/test/ui/rustc-error.stderr b/src/test/ui/rustc-error.stderr
index dcbc0e1feb2..7dfc4449295 100644
--- a/src/test/ui/rustc-error.stderr
+++ b/src/test/ui/rustc-error.stderr
@@ -1,4 +1,4 @@
-error: compilation successful
+error: fatal error triggered by #[rustc_error]
   --> $DIR/rustc-error.rs:4:1
    |
 LL | / fn main() {
diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs
index d750595e272..dc4811e5d24 100644
--- a/src/tools/compiletest/src/header.rs
+++ b/src/tools/compiletest/src/header.rs
@@ -375,6 +375,8 @@ pub struct TestProps {
     // If true, `rustfix` will only apply `MachineApplicable` suggestions.
     pub rustfix_only_machine_applicable: bool,
     pub assembly_output: Option<String>,
+    // If true, the test is expected to ICE
+    pub should_ice: bool,
 }
 
 impl TestProps {
@@ -413,6 +415,7 @@ impl TestProps {
             run_rustfix: false,
             rustfix_only_machine_applicable: false,
             assembly_output: None,
+            should_ice: false,
         }
     }
 
@@ -463,6 +466,10 @@ impl TestProps {
                 self.pp_exact = config.parse_pp_exact(ln, testfile);
             }
 
+            if !self.should_ice {
+                self.should_ice = config.parse_should_ice(ln);
+            }
+
             if !self.build_aux_docs {
                 self.build_aux_docs = config.parse_build_aux_docs(ln);
             }
@@ -577,6 +584,9 @@ impl TestProps {
                 _ => 1,
             };
         }
+        if self.should_ice {
+            self.failure_status = 101;
+        }
 
         for key in &["RUST_TEST_NOCAPTURE", "RUST_TEST_THREADS"] {
             if let Ok(val) = env::var(key) {
@@ -687,6 +697,9 @@ fn iter_header(testfile: &Path, cfg: Option<&str>, it: &mut dyn FnMut(&str)) {
 }
 
 impl Config {
+    fn parse_should_ice(&self, line: &str) -> bool {
+        self.parse_name_directive(line, "should-ice")
+    }
     fn parse_error_pattern(&self, line: &str) -> Option<String> {
         self.parse_name_value_directive(line, "error-pattern")
     }
diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs
index 28b6d2c1d01..15ae67fb12c 100644
--- a/src/tools/compiletest/src/runtest.rs
+++ b/src/tools/compiletest/src/runtest.rs
@@ -298,6 +298,12 @@ impl<'test> TestCx<'test> {
     /// Code executed for each revision in turn (or, if there are no
     /// revisions, exactly once, with revision == None).
     fn run_revision(&self) {
+        if self.props.should_ice {
+            if self.config.mode != CompileFail &&
+                self.config.mode != Incremental {
+                self.fatal("cannot use should-ice in a test that is not cfail");
+            }
+        }
         match self.config.mode {
             CompileFail => self.run_cfail_test(),
             RunFail => self.run_rfail_test(),
@@ -383,7 +389,7 @@ impl<'test> TestCx<'test> {
     fn run_cfail_test(&self) {
         let proc_res = self.compile_test();
         self.check_if_test_should_compile(&proc_res);
-        self.check_no_compiler_crash(&proc_res);
+        self.check_no_compiler_crash(&proc_res, self.props.should_ice);
 
         let output_to_check = self.get_output(&proc_res);
         let expected_errors = errors::load_errors(&self.testpaths.file, self.revision);
@@ -395,6 +401,12 @@ impl<'test> TestCx<'test> {
         } else {
             self.check_error_patterns(&output_to_check, &proc_res);
         }
+        if self.props.should_ice {
+            match proc_res.status.code() {
+                Some(101) => (),
+                _ => self.fatal("expected ICE"),
+            }
+        }
 
         self.check_forbid_output(&output_to_check, &proc_res);
     }
@@ -1402,9 +1414,11 @@ impl<'test> TestCx<'test> {
         }
     }
 
-    fn check_no_compiler_crash(&self, proc_res: &ProcRes) {
+    fn check_no_compiler_crash(&self, proc_res: &ProcRes, should_ice: bool) {
         match proc_res.status.code() {
-            Some(101) => self.fatal_proc_rec("compiler encountered internal error", proc_res),
+            Some(101) if !should_ice => {
+                self.fatal_proc_rec("compiler encountered internal error", proc_res)
+            }
             None => self.fatal_proc_rec("compiler terminated by signal", proc_res),
             _ => (),
         }
@@ -2518,7 +2532,7 @@ impl<'test> TestCx<'test> {
             self.fatal_proc_rec("compilation failed!", &proc_res);
         }
 
-        self.check_no_compiler_crash(&proc_res);
+        self.check_no_compiler_crash(&proc_res, self.props.should_ice);
 
         const PREFIX: &'static str = "MONO_ITEM ";
         const CGU_MARKER: &'static str = "@@";
@@ -2774,8 +2788,14 @@ impl<'test> TestCx<'test> {
         }
 
         if revision.starts_with("rpass") {
+            if revision_cx.props.should_ice {
+                revision_cx.fatal("can only use should-ice in cfail tests");
+            }
             revision_cx.run_rpass_test();
         } else if revision.starts_with("rfail") {
+            if revision_cx.props.should_ice {
+                revision_cx.fatal("can only use should-ice in cfail tests");
+            }
             revision_cx.run_rfail_test();
         } else if revision.starts_with("cfail") {
             revision_cx.run_cfail_test();