about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2020-03-24 00:53:25 +0000
committerbors <bors@rust-lang.org>2020-03-24 00:53:25 +0000
commit342c5f33d097b2dc07a2dbc0ca45a37379d2ff60 (patch)
treedec00a25ca9ef0998971e97d3cc753460528c0d6 /src
parentc55c682e9ba2be16d5de4264d1b626e70f00de9d (diff)
parent3b8872d76de4def293b0bce5a5ad737ccaab7d3d (diff)
downloadrust-342c5f33d097b2dc07a2dbc0ca45a37379d2ff60.tar.gz
rust-342c5f33d097b2dc07a2dbc0ca45a37379d2ff60.zip
Auto merge of #70343 - Centril:rollup-94egfvs, r=Centril
Rollup of 11 pull requests

Successful merges:

 - #67761 (Move the dep_graph construction to a dedicated crate.)
 - #69740 (Replace some desc logic in librustc_lint with article_and_desc)
 - #69981 (Evaluate repeat expression lengths as late as possible)
 - #70087 (Remove const eval loop detector)
 - #70242 (Improve E0308 error message wording)
 - #70264 (Fix invalid suggestion on `&mut` iterators yielding `&` references)
 - #70267 (get rid of ConstPropUnsupported; use ZST marker structs instead)
 - #70277 (Remove `ReClosureBound`)
 - #70283 (Add regression test for #70155.)
 - #70294 (Account for bad placeholder types in where clauses)
 - #70309 (Clean up E0452 explanation)

Failed merges:

r? @ghost
Diffstat (limited to 'src')
-rw-r--r--src/libcore/any.rs2
-rw-r--r--src/librustc/Cargo.toml1
-rw-r--r--src/librustc/dep_graph/dep_node.rs188
-rw-r--r--src/librustc/dep_graph/mod.rs204
-rw-r--r--src/librustc/dep_graph/safe.rs50
-rw-r--r--src/librustc/ich/impls_ty.rs3
-rw-r--r--src/librustc/mir/interpret/error.rs54
-rw-r--r--src/librustc/mir/interpret/mod.rs6
-rw-r--r--src/librustc/mir/mod.rs355
-rw-r--r--src/librustc/mir/query.rs49
-rw-r--r--src/librustc/mir/tcx.rs4
-rw-r--r--src/librustc/mir/type_foldable.rs322
-rw-r--r--src/librustc/ty/print/pretty.rs8
-rw-r--r--src/librustc/ty/query/mod.rs23
-rw-r--r--src/librustc/ty/structural_impls.rs2
-rw-r--r--src/librustc/ty/sty.rs99
-rw-r--r--src/librustc_codegen_ssa/mir/rvalue.rs3
-rw-r--r--src/librustc_error_codes/error_codes/E0308.md8
-rw-r--r--src/librustc_error_codes/error_codes/E0452.md4
-rw-r--r--src/librustc_incremental/assert_dep_graph.rs2
-rw-r--r--src/librustc_incremental/persist/dirty_clean.rs2
-rw-r--r--src/librustc_infer/infer/canonical/canonicalizer.rs4
-rw-r--r--src/librustc_infer/infer/combine.rs4
-rw-r--r--src/librustc_infer/infer/error_reporting/mod.rs5
-rw-r--r--src/librustc_infer/infer/freshen.rs4
-rw-r--r--src/librustc_infer/infer/lexical_region_resolve/mod.rs7
-rw-r--r--src/librustc_infer/infer/region_constraints/mod.rs2
-rw-r--r--src/librustc_lint/builtin.rs70
-rw-r--r--src/librustc_macros/src/query.rs14
-rw-r--r--src/librustc_metadata/rmeta/decoder.rs2
-rw-r--r--src/librustc_mir/borrow_check/diagnostics/mutability_errors.rs82
-rw-r--r--src/librustc_mir/borrow_check/diagnostics/region_name.rs3
-rw-r--r--src/librustc_mir/borrow_check/region_infer/mod.rs41
-rw-r--r--src/librustc_mir/borrow_check/type_check/mod.rs6
-rw-r--r--src/librustc_mir/const_eval/machine.rs67
-rw-r--r--src/librustc_mir/interpret/memory.rs19
-rw-r--r--src/librustc_mir/interpret/mod.rs1
-rw-r--r--src/librustc_mir/interpret/snapshot.rs420
-rw-r--r--src/librustc_mir/transform/const_prop.rs33
-rw-r--r--src/librustc_mir_build/hair/cx/expr.rs32
-rw-r--r--src/librustc_mir_build/hair/mod.rs2
-rw-r--r--src/librustc_query_system/Cargo.toml22
-rw-r--r--src/librustc_query_system/dep_graph/README.md (renamed from src/librustc/dep_graph/README.md)0
-rw-r--r--src/librustc_query_system/dep_graph/debug.rs (renamed from src/librustc/dep_graph/debug.rs)6
-rw-r--r--src/librustc_query_system/dep_graph/dep_node.rs146
-rw-r--r--src/librustc_query_system/dep_graph/graph.rs (renamed from src/librustc/dep_graph/graph.rs)280
-rw-r--r--src/librustc_query_system/dep_graph/mod.rs75
-rw-r--r--src/librustc_query_system/dep_graph/prev.rs (renamed from src/librustc/dep_graph/prev.rs)30
-rw-r--r--src/librustc_query_system/dep_graph/query.rs (renamed from src/librustc/dep_graph/query.rs)26
-rw-r--r--src/librustc_query_system/dep_graph/safe.rs51
-rw-r--r--src/librustc_query_system/dep_graph/serialized.rs (renamed from src/librustc/dep_graph/serialized.rs)23
-rw-r--r--src/librustc_query_system/lib.rs32
-rw-r--r--src/librustc_trait_selection/opaque_types.rs6
-rw-r--r--src/librustc_typeck/astconv.rs113
-rw-r--r--src/librustc_typeck/check/expr.rs22
-rw-r--r--src/librustc_typeck/check/method/confirm.rs2
-rw-r--r--src/librustc_typeck/check/mod.rs21
-rw-r--r--src/librustc_typeck/collect.rs22
-rw-r--r--src/librustc_typeck/outlives/utils.rs1
-rw-r--r--src/librustc_typeck/variance/constraints.rs1
-rw-r--r--src/librustdoc/clean/mod.rs1
-rw-r--r--src/test/compile-fail/issue-52443.rs7
-rw-r--r--src/test/rustdoc-ui/deny-missing-docs-crate.stderr2
-rw-r--r--src/test/ui/borrowck/issue-69789-iterator-mut-suggestion.rs11
-rw-r--r--src/test/ui/borrowck/issue-69789-iterator-mut-suggestion.stderr12
-rw-r--r--src/test/ui/closures/issue-52437.rs1
-rw-r--r--src/test/ui/closures/issue-52437.stderr12
-rw-r--r--src/test/ui/const-generics/issues/issue-61336-1.rs3
-rw-r--r--src/test/ui/const-generics/issues/issue-61336-1.stderr8
-rw-r--r--src/test/ui/const-generics/issues/issue-61336-2.rs7
-rw-r--r--src/test/ui/const-generics/issues/issue-61336-2.stderr22
-rw-r--r--src/test/ui/const-generics/issues/issue-61336.rs3
-rw-r--r--src/test/ui/const-generics/issues/issue-61336.stderr20
-rw-r--r--src/test/ui/const-generics/issues/issue-62456.rs3
-rw-r--r--src/test/ui/const-generics/issues/issue-62456.stderr8
-rw-r--r--src/test/ui/const-generics/issues/issue-62504.rs2
-rw-r--r--src/test/ui/const-generics/issues/issue-62504.stderr10
-rw-r--r--src/test/ui/const-generics/issues/issue-67739.rs3
-rw-r--r--src/test/ui/const-generics/issues/issue-67739.stderr8
-rw-r--r--src/test/ui/const-generics/std/const-generics-range.rs30
-rw-r--r--src/test/ui/consts/const-eval/const-eval-overflow-3.rs1
-rw-r--r--src/test/ui/consts/const-eval/const-eval-overflow-3.stderr14
-rw-r--r--src/test/ui/consts/const-eval/const-eval-overflow-3b.rs1
-rw-r--r--src/test/ui/consts/const-eval/const-eval-overflow-3b.stderr11
-rw-r--r--src/test/ui/consts/const-eval/infinite_loop.rs1
-rw-r--r--src/test/ui/consts/const-eval/infinite_loop.stderr21
-rw-r--r--src/test/ui/consts/const-eval/issue-52442.rs4
-rw-r--r--src/test/ui/consts/const-eval/issue-52442.stderr20
-rw-r--r--src/test/ui/consts/const-eval/issue-52475.rs1
-rw-r--r--src/test/ui/consts/const-eval/issue-52475.stderr19
-rw-r--r--src/test/ui/consts/const-eval/match-test-ptr-null.rs2
-rw-r--r--src/test/ui/consts/const-eval/match-test-ptr-null.stderr27
-rw-r--r--src/test/ui/consts/const_limit/const_eval_limit_not_reached.rs22
-rw-r--r--src/test/ui/consts/const_limit/const_eval_limit_reached.rs27
-rw-r--r--src/test/ui/consts/const_limit/const_eval_limit_reached.stderr25
-rw-r--r--src/test/ui/consts/issue-52432.rs1
-rw-r--r--src/test/ui/consts/issue-52432.stderr12
-rw-r--r--src/test/ui/consts/issue-69310-array-size-lit-wrong-ty.rs2
-rw-r--r--src/test/ui/consts/too_generic_eval_ice.rs1
-rw-r--r--src/test/ui/consts/too_generic_eval_ice.stderr12
-rw-r--r--src/test/ui/did_you_mean/bad-assoc-ty.rs32
-rw-r--r--src/test/ui/did_you_mean/bad-assoc-ty.stderr110
-rw-r--r--src/test/ui/issues/issue-10656.rs2
-rw-r--r--src/test/ui/issues/issue-10656.stderr2
-rw-r--r--src/test/ui/issues/issue-39559-2.rs1
-rw-r--r--src/test/ui/issues/issue-39559-2.stderr16
-rw-r--r--src/test/ui/issues/issue-52060.rs1
-rw-r--r--src/test/ui/issues/issue-52060.stderr13
-rw-r--r--src/test/ui/issues/issue-69602-type-err-during-codegen-ice.rs1
-rw-r--r--src/test/ui/issues/issue-69602-type-err-during-codegen-ice.stderr8
-rw-r--r--src/test/ui/json-bom-plus-crlf-multifile.stderr32
-rw-r--r--src/test/ui/json-bom-plus-crlf.stderr32
-rw-r--r--src/test/ui/lint/lint-missing-doc.rs6
-rw-r--r--src/test/ui/lint/lint-missing-doc.stderr6
-rw-r--r--src/test/ui/lint/lints-in-foreign-macros.rs2
-rw-r--r--src/test/ui/lint/lints-in-foreign-macros.stderr2
-rw-r--r--src/test/ui/nll/ty-outlives/projection-one-region-closure.stderr2
-rw-r--r--src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.stderr2
-rw-r--r--src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.stderr24
-rw-r--r--src/test/ui/privacy/private-in-public-non-principal.rs2
-rw-r--r--src/test/ui/privacy/private-in-public-non-principal.stderr2
-rw-r--r--src/test/ui/repeat_count.stderr12
-rw-r--r--src/test/ui/resolve/issue-65035-static-with-parent-generics.rs1
-rw-r--r--src/test/ui/resolve/issue-65035-static-with-parent-generics.stderr14
-rw-r--r--src/test/ui/typeck/typeck_type_placeholder_item.rs5
-rw-r--r--src/test/ui/typeck/typeck_type_placeholder_item.stderr66
126 files changed, 1947 insertions, 1932 deletions
diff --git a/src/libcore/any.rs b/src/libcore/any.rs
index 97ef513cbcc..39df803bbea 100644
--- a/src/libcore/any.rs
+++ b/src/libcore/any.rs
@@ -164,7 +164,7 @@ impl dyn Any {
         // Get `TypeId` of the type this function is instantiated with.
         let t = TypeId::of::<T>();
 
-        // Get `TypeId` of the type in the trait object.
+        // Get `TypeId` of the type in the trait object (`self`).
         let concrete = self.type_id();
 
         // Compare both `TypeId`s on equality.
diff --git a/src/librustc/Cargo.toml b/src/librustc/Cargo.toml
index 481d691b8e9..47b94a2f1a4 100644
--- a/src/librustc/Cargo.toml
+++ b/src/librustc/Cargo.toml
@@ -25,6 +25,7 @@ rustc_hir = { path = "../librustc_hir" }
 rustc_target = { path = "../librustc_target" }
 rustc_macros = { path = "../librustc_macros" }
 rustc_data_structures = { path = "../librustc_data_structures" }
+rustc_query_system = { path = "../librustc_query_system" }
 rustc_errors = { path = "../librustc_errors" }
 rustc_index = { path = "../librustc_index" }
 rustc_serialize = { path = "../libserialize", package = "serialize" }
diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs
index 7cde57e1f13..fdcc1a0db05 100644
--- a/src/librustc/dep_graph/dep_node.rs
+++ b/src/librustc/dep_graph/dep_node.rs
@@ -50,7 +50,7 @@
 //! fingerprint for a given set of node parameters.
 
 use crate::hir::map::DefPathHash;
-use crate::ich::{Fingerprint, StableHashingContext};
+use crate::ich::Fingerprint;
 use crate::mir;
 use crate::mir::interpret::{GlobalId, LitToConstInput};
 use crate::traits;
@@ -62,13 +62,13 @@ use crate::traits::query::{
 use crate::ty::subst::SubstsRef;
 use crate::ty::{self, ParamEnvAnd, Ty, TyCtxt};
 
-use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, CRATE_DEF_INDEX};
 use rustc_hir::HirId;
 use rustc_span::symbol::Symbol;
-use std::fmt;
 use std::hash::Hash;
 
+pub use rustc_query_system::dep_graph::{DepContext, DepNodeParams};
+
 // erase!() just makes tokens go away. It's used to specify which macro argument
 // is repeated (i.e., which sub-expression of the macro we are in) but don't need
 // to actually use any of the arguments.
@@ -128,7 +128,7 @@ macro_rules! define_dep_nodes {
 
                             // tuple args
                             $({
-                                return <$tuple_arg_ty as DepNodeParams>
+                                return <$tuple_arg_ty as DepNodeParams<TyCtxt<'_>>>
                                     ::CAN_RECONSTRUCT_QUERY_KEY;
                             })*
 
@@ -212,20 +212,39 @@ macro_rules! define_dep_nodes {
             )*
         }
 
-        #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash,
-                 RustcEncodable, RustcDecodable)]
-        pub struct DepNode {
-            pub kind: DepKind,
-            pub hash: Fingerprint,
+        pub type DepNode = rustc_query_system::dep_graph::DepNode<DepKind>;
+
+        pub trait DepNodeExt: Sized {
+            /// Construct a DepNode from the given DepKind and DefPathHash. This
+            /// method will assert that the given DepKind actually requires a
+            /// single DefId/DefPathHash parameter.
+            fn from_def_path_hash(def_path_hash: DefPathHash, kind: DepKind) -> Self;
+
+            /// Extracts the DefId corresponding to this DepNode. This will work
+            /// if two conditions are met:
+            ///
+            /// 1. The Fingerprint of the DepNode actually is a DefPathHash, and
+            /// 2. the item that the DefPath refers to exists in the current tcx.
+            ///
+            /// Condition (1) is determined by the DepKind variant of the
+            /// DepNode. Condition (2) might not be fulfilled if a DepNode
+            /// refers to something from the previous compilation session that
+            /// has been removed.
+            fn extract_def_id(&self, tcx: TyCtxt<'_>) -> Option<DefId>;
+
+            /// Used in testing
+            fn from_label_string(label: &str, def_path_hash: DefPathHash)
+                -> Result<Self, ()>;
+
+            /// Used in testing
+            fn has_label_string(label: &str) -> bool;
         }
 
-        impl DepNode {
+        impl DepNodeExt for DepNode {
             /// Construct a DepNode from the given DepKind and DefPathHash. This
             /// method will assert that the given DepKind actually requires a
             /// single DefId/DefPathHash parameter.
-            pub fn from_def_path_hash(def_path_hash: DefPathHash,
-                                      kind: DepKind)
-                                      -> DepNode {
+            fn from_def_path_hash(def_path_hash: DefPathHash, kind: DepKind) -> DepNode {
                 debug_assert!(kind.can_reconstruct_query_key() && kind.has_params());
                 DepNode {
                     kind,
@@ -233,17 +252,6 @@ macro_rules! define_dep_nodes {
                 }
             }
 
-            /// Creates a new, parameterless DepNode. This method will assert
-            /// that the DepNode corresponding to the given DepKind actually
-            /// does not require any parameters.
-            pub fn new_no_params(kind: DepKind) -> DepNode {
-                debug_assert!(!kind.has_params());
-                DepNode {
-                    kind,
-                    hash: Fingerprint::ZERO,
-                }
-            }
-
             /// Extracts the DefId corresponding to this DepNode. This will work
             /// if two conditions are met:
             ///
@@ -254,20 +262,17 @@ macro_rules! define_dep_nodes {
             /// DepNode. Condition (2) might not be fulfilled if a DepNode
             /// refers to something from the previous compilation session that
             /// has been removed.
-            pub fn extract_def_id(&self, tcx: TyCtxt<'_>) -> Option<DefId> {
+            fn extract_def_id(&self, tcx: TyCtxt<'tcx>) -> Option<DefId> {
                 if self.kind.can_reconstruct_query_key() {
                     let def_path_hash = DefPathHash(self.hash);
-                    tcx.def_path_hash_to_def_id.as_ref()?
-                        .get(&def_path_hash).cloned()
+                    tcx.def_path_hash_to_def_id.as_ref()?.get(&def_path_hash).cloned()
                 } else {
                     None
                 }
             }
 
             /// Used in testing
-            pub fn from_label_string(label: &str,
-                                     def_path_hash: DefPathHash)
-                                     -> Result<DepNode, ()> {
+            fn from_label_string(label: &str, def_path_hash: DefPathHash) -> Result<DepNode, ()> {
                 let kind = match label {
                     $(
                         stringify!($variant) => DepKind::$variant,
@@ -287,7 +292,7 @@ macro_rules! define_dep_nodes {
             }
 
             /// Used in testing
-            pub fn has_label_string(label: &str) -> bool {
+            fn has_label_string(label: &str) -> bool {
                 match label {
                     $(
                         stringify!($variant) => true,
@@ -308,35 +313,6 @@ macro_rules! define_dep_nodes {
     );
 }
 
-impl fmt::Debug for DepNode {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(f, "{:?}", self.kind)?;
-
-        if !self.kind.has_params() && !self.kind.is_anon() {
-            return Ok(());
-        }
-
-        write!(f, "(")?;
-
-        crate::ty::tls::with_opt(|opt_tcx| {
-            if let Some(tcx) = opt_tcx {
-                if let Some(def_id) = self.extract_def_id(tcx) {
-                    write!(f, "{}", tcx.def_path_debug_str(def_id))?;
-                } else if let Some(ref s) = tcx.dep_graph.dep_node_debug_str(*self) {
-                    write!(f, "{}", s)?;
-                } else {
-                    write!(f, "{}", self.hash)?;
-                }
-            } else {
-                write!(f, "{}", self.hash)?;
-            }
-            Ok(())
-        })?;
-
-        write!(f, ")")
-    }
-}
-
 rustc_dep_node_append!([define_dep_nodes!][ <'tcx>
     // We use this for most things when incr. comp. is turned off.
     [] Null,
@@ -349,58 +325,10 @@ rustc_dep_node_append!([define_dep_nodes!][ <'tcx>
     [] CompileCodegenUnit(Symbol),
 ]);
 
-pub(crate) trait DepNodeParams<'tcx>: fmt::Debug + Sized {
-    const CAN_RECONSTRUCT_QUERY_KEY: bool;
-
-    /// This method turns the parameters of a DepNodeConstructor into an opaque
-    /// Fingerprint to be used in DepNode.
-    /// Not all DepNodeParams support being turned into a Fingerprint (they
-    /// don't need to if the corresponding DepNode is anonymous).
-    fn to_fingerprint(&self, _: TyCtxt<'tcx>) -> Fingerprint {
-        panic!("Not implemented. Accidentally called on anonymous node?")
-    }
-
-    fn to_debug_str(&self, _: TyCtxt<'tcx>) -> String {
-        format!("{:?}", self)
-    }
-
-    /// This method tries to recover the query key from the given `DepNode`,
-    /// something which is needed when forcing `DepNode`s during red-green
-    /// evaluation. The query system will only call this method if
-    /// `CAN_RECONSTRUCT_QUERY_KEY` is `true`.
-    /// It is always valid to return `None` here, in which case incremental
-    /// compilation will treat the query as having changed instead of forcing it.
-    fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self>;
-}
-
-impl<'tcx, T> DepNodeParams<'tcx> for T
-where
-    T: HashStable<StableHashingContext<'tcx>> + fmt::Debug,
-{
-    default const CAN_RECONSTRUCT_QUERY_KEY: bool = false;
-
-    default fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint {
-        let mut hcx = tcx.create_stable_hashing_context();
-        let mut hasher = StableHasher::new();
-
-        self.hash_stable(&mut hcx, &mut hasher);
-
-        hasher.finish()
-    }
-
-    default fn to_debug_str(&self, _: TyCtxt<'tcx>) -> String {
-        format!("{:?}", *self)
-    }
-
-    default fn recover(_: TyCtxt<'tcx>, _: &DepNode) -> Option<Self> {
-        None
-    }
-}
-
-impl<'tcx> DepNodeParams<'tcx> for DefId {
+impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for DefId {
     const CAN_RECONSTRUCT_QUERY_KEY: bool = true;
 
-    fn to_fingerprint(&self, tcx: TyCtxt<'_>) -> Fingerprint {
+    fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint {
         tcx.def_path_hash(*self).0
     }
 
@@ -413,10 +341,10 @@ impl<'tcx> DepNodeParams<'tcx> for DefId {
     }
 }
 
-impl<'tcx> DepNodeParams<'tcx> for LocalDefId {
+impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for LocalDefId {
     const CAN_RECONSTRUCT_QUERY_KEY: bool = true;
 
-    fn to_fingerprint(&self, tcx: TyCtxt<'_>) -> Fingerprint {
+    fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint {
         self.to_def_id().to_fingerprint(tcx)
     }
 
@@ -429,10 +357,10 @@ impl<'tcx> DepNodeParams<'tcx> for LocalDefId {
     }
 }
 
-impl<'tcx> DepNodeParams<'tcx> for CrateNum {
+impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for CrateNum {
     const CAN_RECONSTRUCT_QUERY_KEY: bool = true;
 
-    fn to_fingerprint(&self, tcx: TyCtxt<'_>) -> Fingerprint {
+    fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint {
         let def_id = DefId { krate: *self, index: CRATE_DEF_INDEX };
         tcx.def_path_hash(def_id).0
     }
@@ -446,13 +374,13 @@ impl<'tcx> DepNodeParams<'tcx> for CrateNum {
     }
 }
 
-impl<'tcx> DepNodeParams<'tcx> for (DefId, DefId) {
+impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for (DefId, DefId) {
     const CAN_RECONSTRUCT_QUERY_KEY: bool = false;
 
     // We actually would not need to specialize the implementation of this
     // method but it's faster to combine the hashes than to instantiate a full
     // hashing context and stable-hashing state.
-    fn to_fingerprint(&self, tcx: TyCtxt<'_>) -> Fingerprint {
+    fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint {
         let (def_id_0, def_id_1) = *self;
 
         let def_path_hash_0 = tcx.def_path_hash(def_id_0);
@@ -468,13 +396,13 @@ impl<'tcx> DepNodeParams<'tcx> for (DefId, DefId) {
     }
 }
 
-impl<'tcx> DepNodeParams<'tcx> for HirId {
+impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for HirId {
     const CAN_RECONSTRUCT_QUERY_KEY: bool = false;
 
     // We actually would not need to specialize the implementation of this
     // method but it's faster to combine the hashes than to instantiate a full
     // hashing context and stable-hashing state.
-    fn to_fingerprint(&self, tcx: TyCtxt<'_>) -> Fingerprint {
+    fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint {
         let HirId { owner, local_id } = *self;
 
         let def_path_hash = tcx.def_path_hash(owner.to_def_id());
@@ -483,27 +411,3 @@ impl<'tcx> DepNodeParams<'tcx> for HirId {
         def_path_hash.0.combine(local_id)
     }
 }
-
-/// A "work product" corresponds to a `.o` (or other) file that we
-/// save in between runs. These IDs do not have a `DefId` but rather
-/// some independent path or string that persists between runs without
-/// 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)]
-#[derive(HashStable)]
-pub struct WorkProductId {
-    hash: Fingerprint,
-}
-
-impl WorkProductId {
-    pub fn from_cgu_name(cgu_name: &str) -> WorkProductId {
-        let mut hasher = StableHasher::new();
-        cgu_name.len().hash(&mut hasher);
-        cgu_name.hash(&mut hasher);
-        WorkProductId { hash: hasher.finish() }
-    }
-
-    pub fn from_fingerprint(fingerprint: Fingerprint) -> WorkProductId {
-        WorkProductId { hash: fingerprint }
-    }
-}
diff --git a/src/librustc/dep_graph/mod.rs b/src/librustc/dep_graph/mod.rs
index 1fbd90743f4..3c39597584d 100644
--- a/src/librustc/dep_graph/mod.rs
+++ b/src/librustc/dep_graph/mod.rs
@@ -1,17 +1,191 @@
-pub mod debug;
+use crate::ich::StableHashingContext;
+use crate::ty::query::try_load_from_on_disk_cache;
+use crate::ty::{self, TyCtxt};
+use rustc_data_structures::profiling::SelfProfilerRef;
+use rustc_data_structures::sync::Lock;
+use rustc_data_structures::thin_vec::ThinVec;
+use rustc_errors::Diagnostic;
+use rustc_hir::def_id::DefId;
+
 mod dep_node;
-mod graph;
-mod prev;
-mod query;
 mod safe;
-mod serialized;
-
-pub(crate) use self::dep_node::DepNodeParams;
-pub use self::dep_node::{label_strs, DepConstructor, DepKind, DepNode, WorkProductId};
-pub use self::graph::WorkProductFileKind;
-pub use self::graph::{hash_result, DepGraph, DepNodeColor, DepNodeIndex, TaskDeps, WorkProduct};
-pub use self::prev::PreviousDepGraph;
-pub use self::query::DepGraphQuery;
-pub use self::safe::AssertDepGraphSafe;
-pub use self::safe::DepGraphSafe;
-pub use self::serialized::{SerializedDepGraph, SerializedDepNodeIndex};
+
+pub(crate) use rustc_query_system::dep_graph::DepNodeParams;
+pub use rustc_query_system::dep_graph::{
+    debug, hash_result, DepContext, DepNodeColor, DepNodeIndex, SerializedDepNodeIndex,
+    WorkProduct, WorkProductFileKind, WorkProductId,
+};
+
+pub use dep_node::{label_strs, DepConstructor, DepKind, DepNode, DepNodeExt};
+pub use safe::AssertDepGraphSafe;
+pub use safe::DepGraphSafe;
+
+pub type DepGraph = rustc_query_system::dep_graph::DepGraph<DepKind>;
+pub type TaskDeps = rustc_query_system::dep_graph::TaskDeps<DepKind>;
+pub type DepGraphQuery = rustc_query_system::dep_graph::DepGraphQuery<DepKind>;
+pub type PreviousDepGraph = rustc_query_system::dep_graph::PreviousDepGraph<DepKind>;
+pub type SerializedDepGraph = rustc_query_system::dep_graph::SerializedDepGraph<DepKind>;
+
+impl rustc_query_system::dep_graph::DepKind for DepKind {
+    fn is_eval_always(&self) -> bool {
+        DepKind::is_eval_always(self)
+    }
+
+    fn has_params(&self) -> bool {
+        DepKind::has_params(self)
+    }
+
+    fn debug_node(node: &DepNode, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        write!(f, "{:?}", node.kind)?;
+
+        if !node.kind.has_params() && !node.kind.is_anon() {
+            return Ok(());
+        }
+
+        write!(f, "(")?;
+
+        ty::tls::with_opt(|opt_tcx| {
+            if let Some(tcx) = opt_tcx {
+                if let Some(def_id) = node.extract_def_id(tcx) {
+                    write!(f, "{}", tcx.def_path_debug_str(def_id))?;
+                } else if let Some(ref s) = tcx.dep_graph.dep_node_debug_str(*node) {
+                    write!(f, "{}", s)?;
+                } else {
+                    write!(f, "{}", node.hash)?;
+                }
+            } else {
+                write!(f, "{}", node.hash)?;
+            }
+            Ok(())
+        })?;
+
+        write!(f, ")")
+    }
+
+    fn with_deps<OP, R>(task_deps: Option<&Lock<TaskDeps>>, op: OP) -> R
+    where
+        OP: FnOnce() -> R,
+    {
+        ty::tls::with_context(|icx| {
+            let icx = ty::tls::ImplicitCtxt { task_deps, ..icx.clone() };
+
+            ty::tls::enter_context(&icx, |_| op())
+        })
+    }
+
+    fn read_deps<OP>(op: OP) -> ()
+    where
+        OP: for<'a> FnOnce(Option<&'a Lock<TaskDeps>>) -> (),
+    {
+        ty::tls::with_context_opt(|icx| {
+            let icx = if let Some(icx) = icx { icx } else { return };
+            op(icx.task_deps)
+        })
+    }
+}
+
+impl<'tcx> DepContext for TyCtxt<'tcx> {
+    type DepKind = DepKind;
+    type StableHashingContext = StableHashingContext<'tcx>;
+
+    fn create_stable_hashing_context(&self) -> Self::StableHashingContext {
+        TyCtxt::create_stable_hashing_context(*self)
+    }
+
+    fn try_force_from_dep_node(&self, dep_node: &DepNode) -> bool {
+        // FIXME: This match is just a workaround for incremental bugs and should
+        // be removed. https://github.com/rust-lang/rust/issues/62649 is one such
+        // bug that must be fixed before removing this.
+        match dep_node.kind {
+            DepKind::hir_owner | DepKind::hir_owner_nodes | DepKind::CrateMetadata => {
+                if let Some(def_id) = dep_node.extract_def_id(*self) {
+                    if def_id_corresponds_to_hir_dep_node(*self, def_id) {
+                        if dep_node.kind == DepKind::CrateMetadata {
+                            // The `DefPath` has corresponding node,
+                            // and that node should have been marked
+                            // either red or green in `data.colors`.
+                            bug!(
+                                "DepNode {:?} should have been \
+                             pre-marked as red or green but wasn't.",
+                                dep_node
+                            );
+                        }
+                    } else {
+                        // This `DefPath` does not have a
+                        // corresponding `DepNode` (e.g. a
+                        // struct field), and the ` DefPath`
+                        // collided with the `DefPath` of a
+                        // proper item that existed in the
+                        // previous compilation session.
+                        //
+                        // Since the given `DefPath` does not
+                        // denote the item that previously
+                        // existed, we just fail to mark green.
+                        return false;
+                    }
+                } else {
+                    // If the node does not exist anymore, we
+                    // just fail to mark green.
+                    return false;
+                }
+            }
+            _ => {
+                // For other kinds of nodes it's OK to be
+                // forced.
+            }
+        }
+
+        debug!("try_force_from_dep_node({:?}) --- trying to force", dep_node);
+        ty::query::force_from_dep_node(*self, dep_node)
+    }
+
+    fn has_errors_or_delayed_span_bugs(&self) -> bool {
+        self.sess.has_errors_or_delayed_span_bugs()
+    }
+
+    fn diagnostic(&self) -> &rustc_errors::Handler {
+        self.sess.diagnostic()
+    }
+
+    // Interactions with on_disk_cache
+    fn try_load_from_on_disk_cache(&self, dep_node: &DepNode) {
+        try_load_from_on_disk_cache(*self, dep_node)
+    }
+
+    fn load_diagnostics(&self, prev_dep_node_index: SerializedDepNodeIndex) -> Vec<Diagnostic> {
+        self.queries.on_disk_cache.load_diagnostics(*self, prev_dep_node_index)
+    }
+
+    fn store_diagnostics(&self, dep_node_index: DepNodeIndex, diagnostics: ThinVec<Diagnostic>) {
+        self.queries.on_disk_cache.store_diagnostics(dep_node_index, diagnostics)
+    }
+
+    fn profiler(&self) -> &SelfProfilerRef {
+        &self.prof
+    }
+}
+
+fn def_id_corresponds_to_hir_dep_node(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
+    let hir_id = tcx.hir().as_local_hir_id(def_id).unwrap();
+    def_id.index == hir_id.owner.local_def_index
+}
+
+impl rustc_query_system::HashStableContext for StableHashingContext<'_> {
+    fn debug_dep_tasks(&self) -> bool {
+        self.sess().opts.debugging_opts.dep_tasks
+    }
+}
+
+impl rustc_query_system::HashStableContextProvider<StableHashingContext<'tcx>> for TyCtxt<'tcx> {
+    fn get_stable_hashing_context(&self) -> StableHashingContext<'tcx> {
+        self.create_stable_hashing_context()
+    }
+}
+
+impl rustc_query_system::HashStableContextProvider<StableHashingContext<'a>>
+    for StableHashingContext<'a>
+{
+    fn get_stable_hashing_context(&self) -> Self {
+        self.clone()
+    }
+}
diff --git a/src/librustc/dep_graph/safe.rs b/src/librustc/dep_graph/safe.rs
index 74e32867cde..47a1c09672f 100644
--- a/src/librustc/dep_graph/safe.rs
+++ b/src/librustc/dep_graph/safe.rs
@@ -2,56 +2,8 @@
 
 use crate::ty::TyCtxt;
 
-use rustc_ast::ast::NodeId;
-use rustc_hir::def_id::DefId;
-use rustc_hir::BodyId;
-
-/// The `DepGraphSafe` trait is used to specify what kinds of values
-/// are safe to "leak" into a task. The idea is that this should be
-/// only be implemented for things like the tcx as well as various id
-/// types, which will create reads in the dep-graph whenever the trait
-/// loads anything that might depend on the input program.
-pub trait DepGraphSafe {}
-
-/// A `BodyId` on its own doesn't give access to any particular state.
-/// You must fetch the state from the various maps or generate
-/// on-demand queries, all of which create reads.
-impl DepGraphSafe for BodyId {}
-
-/// A `NodeId` on its own doesn't give access to any particular state.
-/// You must fetch the state from the various maps or generate
-/// on-demand queries, all of which create reads.
-impl DepGraphSafe for NodeId {}
-
-/// A `DefId` on its own doesn't give access to any particular state.
-/// You must fetch the state from the various maps or generate
-/// on-demand queries, all of which create reads.
-impl DepGraphSafe for DefId {}
+pub use rustc_query_system::dep_graph::{AssertDepGraphSafe, DepGraphSafe};
 
 /// The type context itself can be used to access all kinds of tracked
 /// state, but those accesses should always generate read events.
 impl<'tcx> DepGraphSafe for TyCtxt<'tcx> {}
-
-/// Tuples make it easy to build up state.
-impl<A, B> DepGraphSafe for (A, B)
-where
-    A: DepGraphSafe,
-    B: DepGraphSafe,
-{
-}
-
-/// Shared ref to dep-graph-safe stuff should still be dep-graph-safe.
-impl<'a, A> DepGraphSafe for &'a A where A: DepGraphSafe {}
-
-/// Mut ref to dep-graph-safe stuff should still be dep-graph-safe.
-impl<'a, A> DepGraphSafe for &'a mut A where A: DepGraphSafe {}
-
-/// No data here! :)
-impl DepGraphSafe for () {}
-
-/// A convenient override that lets you pass arbitrary state into a
-/// task. Every use should be accompanied by a comment explaining why
-/// it makes sense (or how it could be refactored away in the future).
-pub struct AssertDepGraphSafe<T>(pub T);
-
-impl<T> DepGraphSafe for AssertDepGraphSafe<T> {}
diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs
index 844250f51a0..433076bb834 100644
--- a/src/librustc/ich/impls_ty.rs
+++ b/src/librustc/ich/impls_ty.rs
@@ -92,9 +92,6 @@ impl<'a> HashStable<StableHashingContext<'a>> for ty::RegionKind {
             ty::ReFree(ref free_region) => {
                 free_region.hash_stable(hcx, hasher);
             }
-            ty::ReClosureBound(vid) => {
-                vid.hash_stable(hcx, hasher);
-            }
             ty::ReVar(..) | ty::RePlaceholder(..) => {
                 bug!("StableHasher: unexpected region {:?}", *self)
             }
diff --git a/src/librustc/mir/interpret/error.rs b/src/librustc/mir/interpret/error.rs
index f665881ae4c..8f06b9a69bd 100644
--- a/src/librustc/mir/interpret/error.rs
+++ b/src/librustc/mir/interpret/error.rs
@@ -14,7 +14,7 @@ use rustc_hir as hir;
 use rustc_macros::HashStable;
 use rustc_session::CtfeBacktrace;
 use rustc_span::{def_id::DefId, Pos, Span};
-use std::{any::Any, fmt};
+use std::{any::Any, fmt, mem};
 
 #[derive(Debug, Copy, Clone, PartialEq, Eq, HashStable, RustcEncodable, RustcDecodable)]
 pub enum ErrorHandled {
@@ -449,9 +449,6 @@ impl fmt::Debug for UndefinedBehaviorInfo {
 pub enum UnsupportedOpInfo {
     /// Free-form case. Only for errors that are never caught!
     Unsupported(String),
-    /// When const-prop encounters a situation it does not support, it raises this error.
-    /// This must not allocate for performance reasons (hence `str`, not `String`).
-    ConstPropUnsupported(&'static str),
     /// Accessing an unsupported foreign static.
     ReadForeignStatic(DefId),
     /// Could not find MIR for a function.
@@ -470,9 +467,6 @@ impl fmt::Debug for UnsupportedOpInfo {
         use UnsupportedOpInfo::*;
         match self {
             Unsupported(ref msg) => write!(f, "{}", msg),
-            ConstPropUnsupported(ref msg) => {
-                write!(f, "Constant propagation encountered an unsupported situation: {}", msg)
-            }
             ReadForeignStatic(did) => {
                 write!(f, "tried to read from foreign (extern) static {:?}", did)
             }
@@ -494,8 +488,10 @@ impl fmt::Debug for UnsupportedOpInfo {
 pub enum ResourceExhaustionInfo {
     /// The stack grew too big.
     StackFrameLimitReached,
-    /// The program ran into an infinite loop.
-    InfiniteLoop,
+    /// The program ran for too long.
+    ///
+    /// The exact limit is set by the `const_eval_limit` attribute.
+    StepLimitReached,
 }
 
 impl fmt::Debug for ResourceExhaustionInfo {
@@ -505,15 +501,36 @@ impl fmt::Debug for ResourceExhaustionInfo {
             StackFrameLimitReached => {
                 write!(f, "reached the configured maximum number of stack frames")
             }
-            InfiniteLoop => write!(
-                f,
-                "duplicate interpreter state observed here, const evaluation will never \
-                    terminate"
-            ),
+            StepLimitReached => {
+                write!(f, "exceeded interpreter step limit (see `#[const_eval_limit]`)")
+            }
         }
     }
 }
 
+/// A trait to work around not having trait object upcasting.
+pub trait AsAny: Any {
+    fn as_any(&self) -> &dyn Any;
+}
+
+impl<T: Any> AsAny for T {
+    #[inline(always)]
+    fn as_any(&self) -> &dyn Any {
+        self
+    }
+}
+
+/// A trait for machine-specific errors (or other "machine stop" conditions).
+pub trait MachineStopType: AsAny + fmt::Debug + Send {}
+impl MachineStopType for String {}
+
+impl dyn MachineStopType {
+    #[inline(always)]
+    pub fn downcast_ref<T: Any>(&self) -> Option<&T> {
+        self.as_any().downcast_ref()
+    }
+}
+
 pub enum InterpError<'tcx> {
     /// The program caused undefined behavior.
     UndefinedBehavior(UndefinedBehaviorInfo),
@@ -527,7 +544,7 @@ pub enum InterpError<'tcx> {
     ResourceExhaustion(ResourceExhaustionInfo),
     /// Stop execution for a machine-controlled reason. This is never raised by
     /// the core engine itself.
-    MachineStop(Box<dyn Any + Send>),
+    MachineStop(Box<dyn MachineStopType>),
 }
 
 pub type InterpResult<'tcx, T = ()> = Result<T, InterpErrorInfo<'tcx>>;
@@ -547,7 +564,7 @@ impl fmt::Debug for InterpError<'_> {
             InvalidProgram(ref msg) => write!(f, "{:?}", msg),
             UndefinedBehavior(ref msg) => write!(f, "{:?}", msg),
             ResourceExhaustion(ref msg) => write!(f, "{:?}", msg),
-            MachineStop(_) => bug!("unhandled MachineStop"),
+            MachineStop(ref msg) => write!(f, "{:?}", msg),
         }
     }
 }
@@ -558,8 +575,9 @@ impl InterpError<'_> {
     /// waste of resources.
     pub fn allocates(&self) -> bool {
         match self {
-            InterpError::MachineStop(_)
-            | InterpError::Unsupported(UnsupportedOpInfo::Unsupported(_))
+            // Zero-sized boxes do not allocate.
+            InterpError::MachineStop(b) => mem::size_of_val::<dyn MachineStopType>(&**b) > 0,
+            InterpError::Unsupported(UnsupportedOpInfo::Unsupported(_))
             | InterpError::UndefinedBehavior(UndefinedBehaviorInfo::ValidationFailure(_))
             | InterpError::UndefinedBehavior(UndefinedBehaviorInfo::Ub(_)) => true,
             _ => false,
diff --git a/src/librustc/mir/interpret/mod.rs b/src/librustc/mir/interpret/mod.rs
index a2f7a2d847e..1b5fb4c9954 100644
--- a/src/librustc/mir/interpret/mod.rs
+++ b/src/librustc/mir/interpret/mod.rs
@@ -97,8 +97,8 @@ mod value;
 
 pub use self::error::{
     struct_error, ConstEvalErr, ConstEvalRawResult, ConstEvalResult, ErrorHandled, FrameInfo,
-    InterpError, InterpErrorInfo, InterpResult, InvalidProgramInfo, ResourceExhaustionInfo,
-    UndefinedBehaviorInfo, UnsupportedOpInfo,
+    InterpError, InterpErrorInfo, InterpResult, InvalidProgramInfo, MachineStopType,
+    ResourceExhaustionInfo, UndefinedBehaviorInfo, UnsupportedOpInfo,
 };
 
 pub use self::value::{get_slice_bytes, ConstValue, RawConst, Scalar, ScalarMaybeUndef};
@@ -156,7 +156,7 @@ pub struct LitToConstInput<'tcx> {
 pub enum LitToConstError {
     /// The literal's inferred type did not match the expected `ty` in the input.
     /// This is used for graceful error handling (`delay_span_bug`) in
-    /// type checking (`AstConv::ast_const_to_const`).
+    /// type checking (`Const::from_anon_const`).
     TypeError,
     UnparseableFloat,
     Reported,
diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs
index 5b1b6bb08bf..1e47317cf1a 100644
--- a/src/librustc/mir/mod.rs
+++ b/src/librustc/mir/mod.rs
@@ -45,6 +45,7 @@ pub mod mono;
 mod query;
 pub mod tcx;
 pub mod traversal;
+mod type_foldable;
 pub mod visit;
 
 /// Types for locals
@@ -2046,7 +2047,7 @@ pub enum Rvalue<'tcx> {
     Use(Operand<'tcx>),
 
     /// [x; 32]
-    Repeat(Operand<'tcx>, u64),
+    Repeat(Operand<'tcx>, &'tcx ty::Const<'tcx>),
 
     /// &x or &mut x
     Ref(Region<'tcx>, BorrowKind, Place<'tcx>),
@@ -2174,7 +2175,11 @@ impl<'tcx> Debug for Rvalue<'tcx> {
 
         match *self {
             Use(ref place) => write!(fmt, "{:?}", place),
-            Repeat(ref a, ref b) => write!(fmt, "[{:?}; {:?}]", a, b),
+            Repeat(ref a, ref b) => {
+                write!(fmt, "[{:?}; ", a)?;
+                pretty_print_const(b, fmt, false)?;
+                write!(fmt, "]")
+            }
             Len(ref a) => write!(fmt, "Len({:?})", a),
             Cast(ref kind, ref place, ref ty) => {
                 write!(fmt, "{:?} as {:?} ({:?})", place, ty, kind)
@@ -2542,18 +2547,26 @@ impl<'tcx> Debug for Constant<'tcx> {
 
 impl<'tcx> Display for Constant<'tcx> {
     fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
-        use crate::ty::print::PrettyPrinter;
         write!(fmt, "const ")?;
-        ty::tls::with(|tcx| {
-            let literal = tcx.lift(&self.literal).unwrap();
-            let mut cx = FmtPrinter::new(tcx, fmt, Namespace::ValueNS);
-            cx.print_alloc_ids = true;
-            cx.pretty_print_const(literal, true)?;
-            Ok(())
-        })
+        pretty_print_const(self.literal, fmt, true)
     }
 }
 
+fn pretty_print_const(
+    c: &ty::Const<'tcx>,
+    fmt: &mut Formatter<'_>,
+    print_types: bool,
+) -> fmt::Result {
+    use crate::ty::print::PrettyPrinter;
+    ty::tls::with(|tcx| {
+        let literal = tcx.lift(&c).unwrap();
+        let mut cx = FmtPrinter::new(tcx, fmt, Namespace::ValueNS);
+        cx.print_alloc_ids = true;
+        cx.pretty_print_const(literal, print_types)?;
+        Ok(())
+    })
+}
+
 impl<'tcx> graph::DirectedGraph for Body<'tcx> {
     type Node = BasicBlock;
 }
@@ -2651,325 +2664,3 @@ impl Location {
         }
     }
 }
-
-/*
- * `TypeFoldable` implementations for MIR types
-*/
-
-CloneTypeFoldableAndLiftImpls! {
-    BlockTailInfo,
-    MirPhase,
-    SourceInfo,
-    FakeReadCause,
-    RetagKind,
-    SourceScope,
-    SourceScopeData,
-    SourceScopeLocalData,
-    UserTypeAnnotationIndex,
-}
-
-impl<'tcx> TypeFoldable<'tcx> for Terminator<'tcx> {
-    fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
-        use crate::mir::TerminatorKind::*;
-
-        let kind = match self.kind {
-            Goto { target } => Goto { target },
-            SwitchInt { ref discr, switch_ty, ref values, ref targets } => SwitchInt {
-                discr: discr.fold_with(folder),
-                switch_ty: switch_ty.fold_with(folder),
-                values: values.clone(),
-                targets: targets.clone(),
-            },
-            Drop { ref location, target, unwind } => {
-                Drop { location: location.fold_with(folder), target, unwind }
-            }
-            DropAndReplace { ref location, ref value, target, unwind } => DropAndReplace {
-                location: location.fold_with(folder),
-                value: value.fold_with(folder),
-                target,
-                unwind,
-            },
-            Yield { ref value, resume, ref resume_arg, drop } => Yield {
-                value: value.fold_with(folder),
-                resume,
-                resume_arg: resume_arg.fold_with(folder),
-                drop,
-            },
-            Call { ref func, ref args, ref destination, cleanup, from_hir_call } => {
-                let dest =
-                    destination.as_ref().map(|&(ref loc, dest)| (loc.fold_with(folder), dest));
-
-                Call {
-                    func: func.fold_with(folder),
-                    args: args.fold_with(folder),
-                    destination: dest,
-                    cleanup,
-                    from_hir_call,
-                }
-            }
-            Assert { ref cond, expected, ref msg, target, cleanup } => {
-                use AssertKind::*;
-                let msg = match msg {
-                    BoundsCheck { ref len, ref index } => {
-                        BoundsCheck { len: len.fold_with(folder), index: index.fold_with(folder) }
-                    }
-                    Overflow(_)
-                    | OverflowNeg
-                    | DivisionByZero
-                    | RemainderByZero
-                    | ResumedAfterReturn(_)
-                    | ResumedAfterPanic(_) => msg.clone(),
-                };
-                Assert { cond: cond.fold_with(folder), expected, msg, target, cleanup }
-            }
-            GeneratorDrop => GeneratorDrop,
-            Resume => Resume,
-            Abort => Abort,
-            Return => Return,
-            Unreachable => Unreachable,
-            FalseEdges { real_target, imaginary_target } => {
-                FalseEdges { real_target, imaginary_target }
-            }
-            FalseUnwind { real_target, unwind } => FalseUnwind { real_target, unwind },
-        };
-        Terminator { source_info: self.source_info, kind }
-    }
-
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
-        use crate::mir::TerminatorKind::*;
-
-        match self.kind {
-            SwitchInt { ref discr, switch_ty, .. } => {
-                discr.visit_with(visitor) || switch_ty.visit_with(visitor)
-            }
-            Drop { ref location, .. } => location.visit_with(visitor),
-            DropAndReplace { ref location, ref value, .. } => {
-                location.visit_with(visitor) || value.visit_with(visitor)
-            }
-            Yield { ref value, .. } => value.visit_with(visitor),
-            Call { ref func, ref args, ref destination, .. } => {
-                let dest = if let Some((ref loc, _)) = *destination {
-                    loc.visit_with(visitor)
-                } else {
-                    false
-                };
-                dest || func.visit_with(visitor) || args.visit_with(visitor)
-            }
-            Assert { ref cond, ref msg, .. } => {
-                if cond.visit_with(visitor) {
-                    use AssertKind::*;
-                    match msg {
-                        BoundsCheck { ref len, ref index } => {
-                            len.visit_with(visitor) || index.visit_with(visitor)
-                        }
-                        Overflow(_)
-                        | OverflowNeg
-                        | DivisionByZero
-                        | RemainderByZero
-                        | ResumedAfterReturn(_)
-                        | ResumedAfterPanic(_) => false,
-                    }
-                } else {
-                    false
-                }
-            }
-            Goto { .. }
-            | Resume
-            | Abort
-            | Return
-            | GeneratorDrop
-            | Unreachable
-            | FalseEdges { .. }
-            | FalseUnwind { .. } => false,
-        }
-    }
-}
-
-impl<'tcx> TypeFoldable<'tcx> for GeneratorKind {
-    fn super_fold_with<F: TypeFolder<'tcx>>(&self, _: &mut F) -> Self {
-        *self
-    }
-
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> bool {
-        false
-    }
-}
-
-impl<'tcx> TypeFoldable<'tcx> for Place<'tcx> {
-    fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
-        Place { local: self.local.fold_with(folder), projection: self.projection.fold_with(folder) }
-    }
-
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
-        self.local.visit_with(visitor) || self.projection.visit_with(visitor)
-    }
-}
-
-impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<PlaceElem<'tcx>> {
-    fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
-        let v = self.iter().map(|t| t.fold_with(folder)).collect::<Vec<_>>();
-        folder.tcx().intern_place_elems(&v)
-    }
-
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
-        self.iter().any(|t| t.visit_with(visitor))
-    }
-}
-
-impl<'tcx> TypeFoldable<'tcx> for Rvalue<'tcx> {
-    fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
-        use crate::mir::Rvalue::*;
-        match *self {
-            Use(ref op) => Use(op.fold_with(folder)),
-            Repeat(ref op, len) => Repeat(op.fold_with(folder), len),
-            Ref(region, bk, ref place) => {
-                Ref(region.fold_with(folder), bk, place.fold_with(folder))
-            }
-            AddressOf(mutability, ref place) => AddressOf(mutability, place.fold_with(folder)),
-            Len(ref place) => Len(place.fold_with(folder)),
-            Cast(kind, ref op, ty) => Cast(kind, op.fold_with(folder), ty.fold_with(folder)),
-            BinaryOp(op, ref rhs, ref lhs) => {
-                BinaryOp(op, rhs.fold_with(folder), lhs.fold_with(folder))
-            }
-            CheckedBinaryOp(op, ref rhs, ref lhs) => {
-                CheckedBinaryOp(op, rhs.fold_with(folder), lhs.fold_with(folder))
-            }
-            UnaryOp(op, ref val) => UnaryOp(op, val.fold_with(folder)),
-            Discriminant(ref place) => Discriminant(place.fold_with(folder)),
-            NullaryOp(op, ty) => NullaryOp(op, ty.fold_with(folder)),
-            Aggregate(ref kind, ref fields) => {
-                let kind = box match **kind {
-                    AggregateKind::Array(ty) => AggregateKind::Array(ty.fold_with(folder)),
-                    AggregateKind::Tuple => AggregateKind::Tuple,
-                    AggregateKind::Adt(def, v, substs, user_ty, n) => AggregateKind::Adt(
-                        def,
-                        v,
-                        substs.fold_with(folder),
-                        user_ty.fold_with(folder),
-                        n,
-                    ),
-                    AggregateKind::Closure(id, substs) => {
-                        AggregateKind::Closure(id, substs.fold_with(folder))
-                    }
-                    AggregateKind::Generator(id, substs, movablity) => {
-                        AggregateKind::Generator(id, substs.fold_with(folder), movablity)
-                    }
-                };
-                Aggregate(kind, fields.fold_with(folder))
-            }
-        }
-    }
-
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
-        use crate::mir::Rvalue::*;
-        match *self {
-            Use(ref op) => op.visit_with(visitor),
-            Repeat(ref op, _) => op.visit_with(visitor),
-            Ref(region, _, ref place) => region.visit_with(visitor) || place.visit_with(visitor),
-            AddressOf(_, ref place) => place.visit_with(visitor),
-            Len(ref place) => place.visit_with(visitor),
-            Cast(_, ref op, ty) => op.visit_with(visitor) || ty.visit_with(visitor),
-            BinaryOp(_, ref rhs, ref lhs) | CheckedBinaryOp(_, ref rhs, ref lhs) => {
-                rhs.visit_with(visitor) || lhs.visit_with(visitor)
-            }
-            UnaryOp(_, ref val) => val.visit_with(visitor),
-            Discriminant(ref place) => place.visit_with(visitor),
-            NullaryOp(_, ty) => ty.visit_with(visitor),
-            Aggregate(ref kind, ref fields) => {
-                (match **kind {
-                    AggregateKind::Array(ty) => ty.visit_with(visitor),
-                    AggregateKind::Tuple => false,
-                    AggregateKind::Adt(_, _, substs, user_ty, _) => {
-                        substs.visit_with(visitor) || user_ty.visit_with(visitor)
-                    }
-                    AggregateKind::Closure(_, substs) => substs.visit_with(visitor),
-                    AggregateKind::Generator(_, substs, _) => substs.visit_with(visitor),
-                }) || fields.visit_with(visitor)
-            }
-        }
-    }
-}
-
-impl<'tcx> TypeFoldable<'tcx> for Operand<'tcx> {
-    fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
-        match *self {
-            Operand::Copy(ref place) => Operand::Copy(place.fold_with(folder)),
-            Operand::Move(ref place) => Operand::Move(place.fold_with(folder)),
-            Operand::Constant(ref c) => Operand::Constant(c.fold_with(folder)),
-        }
-    }
-
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
-        match *self {
-            Operand::Copy(ref place) | Operand::Move(ref place) => place.visit_with(visitor),
-            Operand::Constant(ref c) => c.visit_with(visitor),
-        }
-    }
-}
-
-impl<'tcx> TypeFoldable<'tcx> for PlaceElem<'tcx> {
-    fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
-        use crate::mir::ProjectionElem::*;
-
-        match *self {
-            Deref => Deref,
-            Field(f, ty) => Field(f, ty.fold_with(folder)),
-            Index(v) => Index(v.fold_with(folder)),
-            Downcast(symbol, variantidx) => Downcast(symbol, variantidx),
-            ConstantIndex { offset, min_length, from_end } => {
-                ConstantIndex { offset, min_length, from_end }
-            }
-            Subslice { from, to, from_end } => Subslice { from, to, from_end },
-        }
-    }
-
-    fn super_visit_with<Vs: TypeVisitor<'tcx>>(&self, visitor: &mut Vs) -> bool {
-        use crate::mir::ProjectionElem::*;
-
-        match self {
-            Field(_, ty) => ty.visit_with(visitor),
-            Index(v) => v.visit_with(visitor),
-            _ => false,
-        }
-    }
-}
-
-impl<'tcx> TypeFoldable<'tcx> for Field {
-    fn super_fold_with<F: TypeFolder<'tcx>>(&self, _: &mut F) -> Self {
-        *self
-    }
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> bool {
-        false
-    }
-}
-
-impl<'tcx> TypeFoldable<'tcx> for GeneratorSavedLocal {
-    fn super_fold_with<F: TypeFolder<'tcx>>(&self, _: &mut F) -> Self {
-        *self
-    }
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> bool {
-        false
-    }
-}
-
-impl<'tcx, R: Idx, C: Idx> TypeFoldable<'tcx> for BitMatrix<R, C> {
-    fn super_fold_with<F: TypeFolder<'tcx>>(&self, _: &mut F) -> Self {
-        self.clone()
-    }
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> bool {
-        false
-    }
-}
-
-impl<'tcx> TypeFoldable<'tcx> for Constant<'tcx> {
-    fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
-        Constant {
-            span: self.span,
-            user_ty: self.user_ty.fold_with(folder),
-            literal: self.literal.fold_with(folder),
-        }
-    }
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
-        self.literal.visit_with(visitor)
-    }
-}
diff --git a/src/librustc/mir/query.rs b/src/librustc/mir/query.rs
index 824cdfe55bf..8c81f5227d2 100644
--- a/src/librustc/mir/query.rs
+++ b/src/librustc/mir/query.rs
@@ -88,34 +88,35 @@ pub struct ConstQualifs {
 /// requirements are then verified and proved by the closure's
 /// creating function. This struct encodes those requirements.
 ///
-/// The requirements are listed as being between various
-/// `RegionVid`. The 0th region refers to `'static`; subsequent region
-/// vids refer to the free regions that appear in the closure (or
-/// generator's) type, in order of appearance. (This numbering is
-/// actually defined by the `UniversalRegions` struct in the NLL
-/// region checker. See for example
-/// `UniversalRegions::closure_mapping`.) Note that we treat the free
-/// regions in the closure's type "as if" they were erased, so their
-/// precise identity is not important, only their position.
+/// The requirements are listed as being between various `RegionVid`. The 0th
+/// region refers to `'static`; subsequent region vids refer to the free
+/// regions that appear in the closure (or generator's) type, in order of
+/// appearance. (This numbering is actually defined by the `UniversalRegions`
+/// struct in the NLL region checker. See for example
+/// `UniversalRegions::closure_mapping`.) Note the free regions in the
+/// closure's signature and captures are erased.
 ///
 /// Example: If type check produces a closure with the closure substs:
 ///
 /// ```text
 /// ClosureSubsts = [
-///     i8,                                  // the "closure kind"
-///     for<'x> fn(&'a &'x u32) -> &'x u32,  // the "closure signature"
-///     &'a String,                          // some upvar
+///     'a,                                         // From the parent.
+///     'b,
+///     i8,                                         // the "closure kind"
+///     for<'x> fn(&'<erased> &'x u32) -> &'x u32,  // the "closure signature"
+///     &'<erased> String,                          // some upvar
 /// ]
 /// ```
 ///
-/// here, there is one unique free region (`'a`) but it appears
-/// twice. We would "renumber" each occurrence to a unique vid, as follows:
+/// We would "renumber" each free region to a unique vid, as follows:
 ///
 /// ```text
 /// ClosureSubsts = [
-///     i8,                                  // the "closure kind"
-///     for<'x> fn(&'1 &'x u32) -> &'x u32,  // the "closure signature"
-///     &'2 String,                          // some upvar
+///     '1,                                         // From the parent.
+///     '2,
+///     i8,                                         // the "closure kind"
+///     for<'x> fn(&'3 &'x u32) -> &'x u32,         // the "closure signature"
+///     &'4 String,                                 // some upvar
 /// ]
 /// ```
 ///
@@ -124,14 +125,12 @@ pub struct ConstQualifs {
 /// can be extracted from its type and constrained to have the given
 /// outlives relationship.
 ///
-/// In some cases, we have to record outlives requirements between
-/// types and regions as well. In that case, if those types include
-/// any regions, those regions are recorded as `ReClosureBound`
-/// instances assigned one of these same indices. Those regions will
-/// be substituted away by the creator. We use `ReClosureBound` in
-/// that case because the regions must be allocated in the global
-/// `TyCtxt`, and hence we cannot use `ReVar` (which is what we use
-/// internally within the rest of the NLL code).
+/// In some cases, we have to record outlives requirements between types and
+/// regions as well. In that case, if those types include any regions, those
+/// regions are recorded using their external names (`ReStatic`,
+/// `ReEarlyBound`, `ReFree`). We use these because in a query response we
+/// cannot use `ReVar` (which is what we use internally within the rest of the
+/// NLL code).
 #[derive(Clone, Debug, RustcEncodable, RustcDecodable, HashStable)]
 pub struct ClosureRegionRequirements<'tcx> {
     /// The number of external regions defined on the closure. In our
diff --git a/src/librustc/mir/tcx.rs b/src/librustc/mir/tcx.rs
index 13996a74acb..feb66319267 100644
--- a/src/librustc/mir/tcx.rs
+++ b/src/librustc/mir/tcx.rs
@@ -149,7 +149,9 @@ impl<'tcx> Rvalue<'tcx> {
     {
         match *self {
             Rvalue::Use(ref operand) => operand.ty(local_decls, tcx),
-            Rvalue::Repeat(ref operand, count) => tcx.mk_array(operand.ty(local_decls, tcx), count),
+            Rvalue::Repeat(ref operand, count) => {
+                tcx.mk_ty(ty::Array(operand.ty(local_decls, tcx), count))
+            }
             Rvalue::Ref(reg, bk, ref place) => {
                 let place_ty = place.ty(local_decls, tcx).ty;
                 tcx.mk_ref(reg, ty::TypeAndMut { ty: place_ty, mutbl: bk.to_mutbl_lossy() })
diff --git a/src/librustc/mir/type_foldable.rs b/src/librustc/mir/type_foldable.rs
new file mode 100644
index 00000000000..9520f081b6b
--- /dev/null
+++ b/src/librustc/mir/type_foldable.rs
@@ -0,0 +1,322 @@
+//! `TypeFoldable` implementations for MIR types
+
+use super::*;
+use crate::ty;
+
+CloneTypeFoldableAndLiftImpls! {
+    BlockTailInfo,
+    MirPhase,
+    SourceInfo,
+    FakeReadCause,
+    RetagKind,
+    SourceScope,
+    SourceScopeData,
+    SourceScopeLocalData,
+    UserTypeAnnotationIndex,
+}
+
+impl<'tcx> TypeFoldable<'tcx> for Terminator<'tcx> {
+    fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
+        use crate::mir::TerminatorKind::*;
+
+        let kind = match self.kind {
+            Goto { target } => Goto { target },
+            SwitchInt { ref discr, switch_ty, ref values, ref targets } => SwitchInt {
+                discr: discr.fold_with(folder),
+                switch_ty: switch_ty.fold_with(folder),
+                values: values.clone(),
+                targets: targets.clone(),
+            },
+            Drop { ref location, target, unwind } => {
+                Drop { location: location.fold_with(folder), target, unwind }
+            }
+            DropAndReplace { ref location, ref value, target, unwind } => DropAndReplace {
+                location: location.fold_with(folder),
+                value: value.fold_with(folder),
+                target,
+                unwind,
+            },
+            Yield { ref value, resume, ref resume_arg, drop } => Yield {
+                value: value.fold_with(folder),
+                resume,
+                resume_arg: resume_arg.fold_with(folder),
+                drop,
+            },
+            Call { ref func, ref args, ref destination, cleanup, from_hir_call } => {
+                let dest =
+                    destination.as_ref().map(|&(ref loc, dest)| (loc.fold_with(folder), dest));
+
+                Call {
+                    func: func.fold_with(folder),
+                    args: args.fold_with(folder),
+                    destination: dest,
+                    cleanup,
+                    from_hir_call,
+                }
+            }
+            Assert { ref cond, expected, ref msg, target, cleanup } => {
+                use AssertKind::*;
+                let msg = match msg {
+                    BoundsCheck { ref len, ref index } => {
+                        BoundsCheck { len: len.fold_with(folder), index: index.fold_with(folder) }
+                    }
+                    Overflow(_)
+                    | OverflowNeg
+                    | DivisionByZero
+                    | RemainderByZero
+                    | ResumedAfterReturn(_)
+                    | ResumedAfterPanic(_) => msg.clone(),
+                };
+                Assert { cond: cond.fold_with(folder), expected, msg, target, cleanup }
+            }
+            GeneratorDrop => GeneratorDrop,
+            Resume => Resume,
+            Abort => Abort,
+            Return => Return,
+            Unreachable => Unreachable,
+            FalseEdges { real_target, imaginary_target } => {
+                FalseEdges { real_target, imaginary_target }
+            }
+            FalseUnwind { real_target, unwind } => FalseUnwind { real_target, unwind },
+        };
+        Terminator { source_info: self.source_info, kind }
+    }
+
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
+        use crate::mir::TerminatorKind::*;
+
+        match self.kind {
+            SwitchInt { ref discr, switch_ty, .. } => {
+                discr.visit_with(visitor) || switch_ty.visit_with(visitor)
+            }
+            Drop { ref location, .. } => location.visit_with(visitor),
+            DropAndReplace { ref location, ref value, .. } => {
+                location.visit_with(visitor) || value.visit_with(visitor)
+            }
+            Yield { ref value, .. } => value.visit_with(visitor),
+            Call { ref func, ref args, ref destination, .. } => {
+                let dest = if let Some((ref loc, _)) = *destination {
+                    loc.visit_with(visitor)
+                } else {
+                    false
+                };
+                dest || func.visit_with(visitor) || args.visit_with(visitor)
+            }
+            Assert { ref cond, ref msg, .. } => {
+                if cond.visit_with(visitor) {
+                    use AssertKind::*;
+                    match msg {
+                        BoundsCheck { ref len, ref index } => {
+                            len.visit_with(visitor) || index.visit_with(visitor)
+                        }
+                        Overflow(_)
+                        | OverflowNeg
+                        | DivisionByZero
+                        | RemainderByZero
+                        | ResumedAfterReturn(_)
+                        | ResumedAfterPanic(_) => false,
+                    }
+                } else {
+                    false
+                }
+            }
+            Goto { .. }
+            | Resume
+            | Abort
+            | Return
+            | GeneratorDrop
+            | Unreachable
+            | FalseEdges { .. }
+            | FalseUnwind { .. } => false,
+        }
+    }
+}
+
+impl<'tcx> TypeFoldable<'tcx> for GeneratorKind {
+    fn super_fold_with<F: TypeFolder<'tcx>>(&self, _: &mut F) -> Self {
+        *self
+    }
+
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> bool {
+        false
+    }
+}
+
+impl<'tcx> TypeFoldable<'tcx> for Place<'tcx> {
+    fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
+        Place { local: self.local.fold_with(folder), projection: self.projection.fold_with(folder) }
+    }
+
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
+        self.local.visit_with(visitor) || self.projection.visit_with(visitor)
+    }
+}
+
+impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<PlaceElem<'tcx>> {
+    fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
+        let v = self.iter().map(|t| t.fold_with(folder)).collect::<Vec<_>>();
+        folder.tcx().intern_place_elems(&v)
+    }
+
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
+        self.iter().any(|t| t.visit_with(visitor))
+    }
+}
+
+impl<'tcx> TypeFoldable<'tcx> for Rvalue<'tcx> {
+    fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
+        use crate::mir::Rvalue::*;
+        match *self {
+            Use(ref op) => Use(op.fold_with(folder)),
+            Repeat(ref op, len) => Repeat(op.fold_with(folder), len),
+            Ref(region, bk, ref place) => {
+                Ref(region.fold_with(folder), bk, place.fold_with(folder))
+            }
+            AddressOf(mutability, ref place) => AddressOf(mutability, place.fold_with(folder)),
+            Len(ref place) => Len(place.fold_with(folder)),
+            Cast(kind, ref op, ty) => Cast(kind, op.fold_with(folder), ty.fold_with(folder)),
+            BinaryOp(op, ref rhs, ref lhs) => {
+                BinaryOp(op, rhs.fold_with(folder), lhs.fold_with(folder))
+            }
+            CheckedBinaryOp(op, ref rhs, ref lhs) => {
+                CheckedBinaryOp(op, rhs.fold_with(folder), lhs.fold_with(folder))
+            }
+            UnaryOp(op, ref val) => UnaryOp(op, val.fold_with(folder)),
+            Discriminant(ref place) => Discriminant(place.fold_with(folder)),
+            NullaryOp(op, ty) => NullaryOp(op, ty.fold_with(folder)),
+            Aggregate(ref kind, ref fields) => {
+                let kind = box match **kind {
+                    AggregateKind::Array(ty) => AggregateKind::Array(ty.fold_with(folder)),
+                    AggregateKind::Tuple => AggregateKind::Tuple,
+                    AggregateKind::Adt(def, v, substs, user_ty, n) => AggregateKind::Adt(
+                        def,
+                        v,
+                        substs.fold_with(folder),
+                        user_ty.fold_with(folder),
+                        n,
+                    ),
+                    AggregateKind::Closure(id, substs) => {
+                        AggregateKind::Closure(id, substs.fold_with(folder))
+                    }
+                    AggregateKind::Generator(id, substs, movablity) => {
+                        AggregateKind::Generator(id, substs.fold_with(folder), movablity)
+                    }
+                };
+                Aggregate(kind, fields.fold_with(folder))
+            }
+        }
+    }
+
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
+        use crate::mir::Rvalue::*;
+        match *self {
+            Use(ref op) => op.visit_with(visitor),
+            Repeat(ref op, _) => op.visit_with(visitor),
+            Ref(region, _, ref place) => region.visit_with(visitor) || place.visit_with(visitor),
+            AddressOf(_, ref place) => place.visit_with(visitor),
+            Len(ref place) => place.visit_with(visitor),
+            Cast(_, ref op, ty) => op.visit_with(visitor) || ty.visit_with(visitor),
+            BinaryOp(_, ref rhs, ref lhs) | CheckedBinaryOp(_, ref rhs, ref lhs) => {
+                rhs.visit_with(visitor) || lhs.visit_with(visitor)
+            }
+            UnaryOp(_, ref val) => val.visit_with(visitor),
+            Discriminant(ref place) => place.visit_with(visitor),
+            NullaryOp(_, ty) => ty.visit_with(visitor),
+            Aggregate(ref kind, ref fields) => {
+                (match **kind {
+                    AggregateKind::Array(ty) => ty.visit_with(visitor),
+                    AggregateKind::Tuple => false,
+                    AggregateKind::Adt(_, _, substs, user_ty, _) => {
+                        substs.visit_with(visitor) || user_ty.visit_with(visitor)
+                    }
+                    AggregateKind::Closure(_, substs) => substs.visit_with(visitor),
+                    AggregateKind::Generator(_, substs, _) => substs.visit_with(visitor),
+                }) || fields.visit_with(visitor)
+            }
+        }
+    }
+}
+
+impl<'tcx> TypeFoldable<'tcx> for Operand<'tcx> {
+    fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
+        match *self {
+            Operand::Copy(ref place) => Operand::Copy(place.fold_with(folder)),
+            Operand::Move(ref place) => Operand::Move(place.fold_with(folder)),
+            Operand::Constant(ref c) => Operand::Constant(c.fold_with(folder)),
+        }
+    }
+
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
+        match *self {
+            Operand::Copy(ref place) | Operand::Move(ref place) => place.visit_with(visitor),
+            Operand::Constant(ref c) => c.visit_with(visitor),
+        }
+    }
+}
+
+impl<'tcx> TypeFoldable<'tcx> for PlaceElem<'tcx> {
+    fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
+        use crate::mir::ProjectionElem::*;
+
+        match *self {
+            Deref => Deref,
+            Field(f, ty) => Field(f, ty.fold_with(folder)),
+            Index(v) => Index(v.fold_with(folder)),
+            Downcast(symbol, variantidx) => Downcast(symbol, variantidx),
+            ConstantIndex { offset, min_length, from_end } => {
+                ConstantIndex { offset, min_length, from_end }
+            }
+            Subslice { from, to, from_end } => Subslice { from, to, from_end },
+        }
+    }
+
+    fn super_visit_with<Vs: TypeVisitor<'tcx>>(&self, visitor: &mut Vs) -> bool {
+        use crate::mir::ProjectionElem::*;
+
+        match self {
+            Field(_, ty) => ty.visit_with(visitor),
+            Index(v) => v.visit_with(visitor),
+            _ => false,
+        }
+    }
+}
+
+impl<'tcx> TypeFoldable<'tcx> for Field {
+    fn super_fold_with<F: TypeFolder<'tcx>>(&self, _: &mut F) -> Self {
+        *self
+    }
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> bool {
+        false
+    }
+}
+
+impl<'tcx> TypeFoldable<'tcx> for GeneratorSavedLocal {
+    fn super_fold_with<F: TypeFolder<'tcx>>(&self, _: &mut F) -> Self {
+        *self
+    }
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> bool {
+        false
+    }
+}
+
+impl<'tcx, R: Idx, C: Idx> TypeFoldable<'tcx> for BitMatrix<R, C> {
+    fn super_fold_with<F: TypeFolder<'tcx>>(&self, _: &mut F) -> Self {
+        self.clone()
+    }
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> bool {
+        false
+    }
+}
+
+impl<'tcx> TypeFoldable<'tcx> for Constant<'tcx> {
+    fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
+        Constant {
+            span: self.span,
+            user_ty: self.user_ty.fold_with(folder),
+            literal: self.literal.fold_with(folder),
+        }
+    }
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
+        self.literal.visit_with(visitor)
+    }
+}
diff --git a/src/librustc/ty/print/pretty.rs b/src/librustc/ty/print/pretty.rs
index 3a95c573ca3..58bff2f13eb 100644
--- a/src/librustc/ty/print/pretty.rs
+++ b/src/librustc/ty/print/pretty.rs
@@ -1574,7 +1574,7 @@ impl<F: fmt::Write> PrettyPrinter<'tcx> for FmtPrinter<'_, 'tcx, F> {
 
             ty::ReVar(_) | ty::ReScope(_) | ty::ReErased => false,
 
-            ty::ReStatic | ty::ReEmpty(_) | ty::ReClosureBound(_) => true,
+            ty::ReStatic | ty::ReEmpty(_) => true,
         }
     }
 
@@ -1686,12 +1686,6 @@ impl<F: fmt::Write> FmtPrinter<'_, '_, F> {
                 p!(write("'<empty:{:?}>", ui));
                 return Ok(self);
             }
-
-            // The user should never encounter these in unsubstituted form.
-            ty::ReClosureBound(vid) => {
-                p!(write("{:?}", vid));
-                return Ok(self);
-            }
         }
 
         p!(write("'_"));
diff --git a/src/librustc/ty/query/mod.rs b/src/librustc/ty/query/mod.rs
index 32ba13b1dbe..b45b3b3f539 100644
--- a/src/librustc/ty/query/mod.rs
+++ b/src/librustc/ty/query/mod.rs
@@ -150,8 +150,6 @@ rustc_query_append! { [define_queries!][<'tcx>] }
 /// add it to the "We don't have enough information to reconstruct..." group in
 /// the match below.
 pub fn force_from_dep_node<'tcx>(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> bool {
-    use crate::dep_graph::DepKind;
-
     // We must avoid ever having to call `force_from_dep_node()` for a
     // `DepNode::codegen_unit`:
     // Since we cannot reconstruct the query key of a `DepNode::codegen_unit`, we
@@ -166,7 +164,7 @@ pub fn force_from_dep_node<'tcx>(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> bool
     // hit the cache instead of having to go through `force_from_dep_node`.
     // This assertion makes sure, we actually keep applying the solution above.
     debug_assert!(
-        dep_node.kind != DepKind::codegen_unit,
+        dep_node.kind != crate::dep_graph::DepKind::codegen_unit,
         "calling force_from_dep_node() on DepKind::codegen_unit"
     );
 
@@ -177,14 +175,14 @@ pub fn force_from_dep_node<'tcx>(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> bool
     rustc_dep_node_force!([dep_node, tcx]
         // These are inputs that are expected to be pre-allocated and that
         // should therefore always be red or green already.
-        DepKind::CrateMetadata |
+        crate::dep_graph::DepKind::CrateMetadata |
 
         // These are anonymous nodes.
-        DepKind::TraitSelect |
+        crate::dep_graph::DepKind::TraitSelect |
 
         // We don't have enough information to reconstruct the query key of
         // these.
-        DepKind::CompileCodegenUnit => {
+        crate::dep_graph::DepKind::CompileCodegenUnit => {
             bug!("force_from_dep_node: encountered {:?}", dep_node)
         }
     );
@@ -192,15 +190,6 @@ pub fn force_from_dep_node<'tcx>(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> bool
     false
 }
 
-impl DepNode {
-    /// Check whether the query invocation corresponding to the given
-    /// DepNode is eligible for on-disk-caching. If so, this is method
-    /// will execute the query corresponding to the given DepNode.
-    /// Also, as a sanity check, it expects that the corresponding query
-    /// invocation has been marked as green already.
-    pub fn try_load_from_on_disk_cache<'tcx>(&self, tcx: TyCtxt<'tcx>) {
-        use crate::dep_graph::DepKind;
-
-        rustc_dep_node_try_load_from_on_disk_cache!(self, tcx)
-    }
+pub(crate) fn try_load_from_on_disk_cache<'tcx>(tcx: TyCtxt<'tcx>, dep_node: &DepNode) {
+    rustc_dep_node_try_load_from_on_disk_cache!(dep_node, tcx)
 }
diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs
index e2fa0313911..81be5b11143 100644
--- a/src/librustc/ty/structural_impls.rs
+++ b/src/librustc/ty/structural_impls.rs
@@ -81,8 +81,6 @@ impl fmt::Debug for ty::RegionKind {
         match *self {
             ty::ReEarlyBound(ref data) => write!(f, "ReEarlyBound({}, {})", data.index, data.name),
 
-            ty::ReClosureBound(ref vid) => write!(f, "ReClosureBound({:?})", vid),
-
             ty::ReLateBound(binder_id, ref bound_region) => {
                 write!(f, "ReLateBound({:?}, {:?})", binder_id, bound_region)
             }
diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs
index 0c14580717f..d440e84e15c 100644
--- a/src/librustc/ty/sty.rs
+++ b/src/librustc/ty/sty.rs
@@ -8,7 +8,7 @@ use self::TyKind::*;
 use crate::infer::canonical::Canonical;
 use crate::middle::region;
 use crate::mir::interpret::ConstValue;
-use crate::mir::interpret::Scalar;
+use crate::mir::interpret::{LitToConstInput, Scalar};
 use crate::mir::Promoted;
 use crate::ty::layout::VariantIdx;
 use crate::ty::subst::{GenericArg, InternalSubsts, Subst, SubstsRef};
@@ -20,7 +20,7 @@ use polonius_engine::Atom;
 use rustc_ast::ast::{self, Ident};
 use rustc_data_structures::captures::Captures;
 use rustc_hir as hir;
-use rustc_hir::def_id::DefId;
+use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_index::vec::Idx;
 use rustc_macros::HashStable;
 use rustc_span::symbol::{kw, Symbol};
@@ -1352,12 +1352,6 @@ pub enum RegionKind {
 
     /// Erased region, used by trait selection, in MIR and during codegen.
     ReErased,
-
-    /// These are regions bound in the "defining type" for a
-    /// closure. They are used ONLY as part of the
-    /// `ClosureRegionRequirements` that are produced by MIR borrowck.
-    /// See `ClosureRegionRequirements` for more details.
-    ReClosureBound(RegionVid),
 }
 
 impl<'tcx> rustc_serialize::UseSpecializedDecodable for Region<'tcx> {}
@@ -1567,7 +1561,6 @@ impl RegionKind {
             RegionKind::RePlaceholder(placeholder) => placeholder.name.is_named(),
             RegionKind::ReEmpty(_) => false,
             RegionKind::ReErased => false,
-            RegionKind::ReClosureBound(..) => false,
         }
     }
 
@@ -1648,9 +1641,6 @@ impl RegionKind {
             ty::ReEmpty(_) | ty::ReStatic => {
                 flags = flags | TypeFlags::HAS_FREE_REGIONS;
             }
-            ty::ReClosureBound(..) => {
-                flags = flags | TypeFlags::HAS_FREE_REGIONS;
-            }
             ty::ReLateBound(..) => {
                 flags = flags | TypeFlags::HAS_RE_LATE_BOUND;
             }
@@ -2275,17 +2265,92 @@ pub struct Const<'tcx> {
 static_assert_size!(Const<'_>, 48);
 
 impl<'tcx> Const<'tcx> {
+    /// Literals and const generic parameters are eagerly converted to a constant, everything else
+    /// becomes `Unevaluated`.
+    pub fn from_anon_const(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &'tcx Self {
+        debug!("Const::from_anon_const(id={:?})", def_id);
+
+        let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
+
+        let body_id = match tcx.hir().get(hir_id) {
+            hir::Node::AnonConst(ac) => ac.body,
+            _ => span_bug!(
+                tcx.def_span(def_id.to_def_id()),
+                "from_anon_const can only process anonymous constants"
+            ),
+        };
+
+        let expr = &tcx.hir().body(body_id).value;
+
+        let ty = tcx.type_of(def_id.to_def_id());
+
+        let lit_input = match expr.kind {
+            hir::ExprKind::Lit(ref lit) => Some(LitToConstInput { lit: &lit.node, ty, neg: false }),
+            hir::ExprKind::Unary(hir::UnOp::UnNeg, ref expr) => match expr.kind {
+                hir::ExprKind::Lit(ref lit) => {
+                    Some(LitToConstInput { lit: &lit.node, ty, neg: true })
+                }
+                _ => None,
+            },
+            _ => None,
+        };
+
+        if let Some(lit_input) = lit_input {
+            // If an error occurred, ignore that it's a literal and leave reporting the error up to
+            // mir.
+            if let Ok(c) = tcx.at(expr.span).lit_to_const(lit_input) {
+                return c;
+            } else {
+                tcx.sess.delay_span_bug(expr.span, "Const::from_anon_const: couldn't lit_to_const");
+            }
+        }
+
+        // Unwrap a block, so that e.g. `{ P }` is recognised as a parameter. Const arguments
+        // currently have to be wrapped in curly brackets, so it's necessary to special-case.
+        let expr = match &expr.kind {
+            hir::ExprKind::Block(block, _) if block.stmts.is_empty() && block.expr.is_some() => {
+                block.expr.as_ref().unwrap()
+            }
+            _ => expr,
+        };
+
+        use hir::{def::DefKind::ConstParam, def::Res, ExprKind, Path, QPath};
+        let val = match expr.kind {
+            ExprKind::Path(QPath::Resolved(_, &Path { res: Res::Def(ConstParam, def_id), .. })) => {
+                // Find the name and index of the const parameter by indexing the generics of
+                // the parent item and construct a `ParamConst`.
+                let hir_id = tcx.hir().as_local_hir_id(def_id).unwrap();
+                let item_id = tcx.hir().get_parent_node(hir_id);
+                let item_def_id = tcx.hir().local_def_id(item_id);
+                let generics = tcx.generics_of(item_def_id);
+                let index = generics.param_def_id_to_index[&tcx.hir().local_def_id(hir_id)];
+                let name = tcx.hir().name(hir_id);
+                ty::ConstKind::Param(ty::ParamConst::new(index, name))
+            }
+            _ => ty::ConstKind::Unevaluated(
+                def_id.to_def_id(),
+                InternalSubsts::identity_for_item(tcx, def_id.to_def_id()),
+                None,
+            ),
+        };
+
+        tcx.mk_const(ty::Const { val, ty })
+    }
+
     #[inline]
+    /// Interns the given value as a constant.
     pub fn from_value(tcx: TyCtxt<'tcx>, val: ConstValue<'tcx>, ty: Ty<'tcx>) -> &'tcx Self {
         tcx.mk_const(Self { val: ConstKind::Value(val), ty })
     }
 
     #[inline]
+    /// Interns the given scalar as a constant.
     pub fn from_scalar(tcx: TyCtxt<'tcx>, val: Scalar, ty: Ty<'tcx>) -> &'tcx Self {
         Self::from_value(tcx, ConstValue::Scalar(val), ty)
     }
 
     #[inline]
+    /// Creates a constant with the given integer value and interns it.
     pub fn from_bits(tcx: TyCtxt<'tcx>, bits: u128, ty: ParamEnvAnd<'tcx, Ty<'tcx>>) -> &'tcx Self {
         let size = tcx
             .layout_of(ty)
@@ -2295,21 +2360,27 @@ impl<'tcx> Const<'tcx> {
     }
 
     #[inline]
+    /// Creates an interned zst constant.
     pub fn zero_sized(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> &'tcx Self {
         Self::from_scalar(tcx, Scalar::zst(), ty)
     }
 
     #[inline]
+    /// Creates an interned bool constant.
     pub fn from_bool(tcx: TyCtxt<'tcx>, v: bool) -> &'tcx Self {
         Self::from_bits(tcx, v as u128, ParamEnv::empty().and(tcx.types.bool))
     }
 
     #[inline]
+    /// Creates an interned usize constant.
     pub fn from_usize(tcx: TyCtxt<'tcx>, n: u64) -> &'tcx Self {
         Self::from_bits(tcx, n as u128, ParamEnv::empty().and(tcx.types.usize))
     }
 
     #[inline]
+    /// Attempts to evaluate the given constant to bits. Can fail to evaluate in the presence of
+    /// generics (or erroneous code) or if the value can't be represented as bits (e.g. because it
+    /// contains const generic parameters or pointers).
     pub fn try_eval_bits(
         &self,
         tcx: TyCtxt<'tcx>,
@@ -2323,6 +2394,8 @@ impl<'tcx> Const<'tcx> {
     }
 
     #[inline]
+    /// Tries to evaluate the constant if it is `Unevaluated`. If that doesn't succeed, return the
+    /// unevaluated constant.
     pub fn eval(&self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> &Const<'tcx> {
         let try_const_eval = |did, param_env: ParamEnv<'tcx>, substs, promoted| {
             let param_env_and_substs = param_env.with_reveal_all().and(substs);
@@ -2379,12 +2452,14 @@ impl<'tcx> Const<'tcx> {
     }
 
     #[inline]
+    /// Panics if the value cannot be evaluated or doesn't contain a valid integer of the given type.
     pub fn eval_bits(&self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>, ty: Ty<'tcx>) -> u128 {
         self.try_eval_bits(tcx, param_env, ty)
             .unwrap_or_else(|| bug!("expected bits of {:#?}, got {:#?}", ty, self))
     }
 
     #[inline]
+    /// Panics if the value cannot be evaluated or doesn't contain a valid `usize`.
     pub fn eval_usize(&self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> u64 {
         self.eval_bits(tcx, param_env, tcx.types.usize) as u64
     }
diff --git a/src/librustc_codegen_ssa/mir/rvalue.rs b/src/librustc_codegen_ssa/mir/rvalue.rs
index 245df0846b5..880bce7fde4 100644
--- a/src/librustc_codegen_ssa/mir/rvalue.rs
+++ b/src/librustc_codegen_ssa/mir/rvalue.rs
@@ -106,6 +106,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                     }
                 }
 
+                let count =
+                    self.monomorphize(&count).eval_usize(bx.cx().tcx(), ty::ParamEnv::reveal_all());
+
                 bx.write_operand_repeatedly(cg_elem, count, dest)
             }
 
diff --git a/src/librustc_error_codes/error_codes/E0308.md b/src/librustc_error_codes/error_codes/E0308.md
index 7d87d54194e..b2c84370490 100644
--- a/src/librustc_error_codes/error_codes/E0308.md
+++ b/src/librustc_error_codes/error_codes/E0308.md
@@ -13,7 +13,7 @@ let x: i32 = "I am not a number!";
 ```
 
 This error occurs when the compiler was unable to infer the concrete type of a
-variable. It can occur for several cases, the most common of which is a
-mismatch in the expected type that the compiler inferred for a variable's
-initializing expression, and the actual type explicitly assigned to the
-variable.
+variable. It can happen in several cases, the most common being a mismatch
+between the type that the compiler inferred for a variable based on its
+initializing expression, on the one hand, and the type the author explicitly
+assigned to the variable, on the other hand.
diff --git a/src/librustc_error_codes/error_codes/E0452.md b/src/librustc_error_codes/error_codes/E0452.md
index be3d573e10d..429813a7cdd 100644
--- a/src/librustc_error_codes/error_codes/E0452.md
+++ b/src/librustc_error_codes/error_codes/E0452.md
@@ -1,4 +1,6 @@
-An invalid lint attribute has been given. Erroneous code example:
+An invalid lint attribute has been given.
+
+Erroneous code example:
 
 ```compile_fail,E0452
 #![allow(foo = "")] // error: malformed lint attribute
diff --git a/src/librustc_incremental/assert_dep_graph.rs b/src/librustc_incremental/assert_dep_graph.rs
index a7dccaf974b..305e0fcc383 100644
--- a/src/librustc_incremental/assert_dep_graph.rs
+++ b/src/librustc_incremental/assert_dep_graph.rs
@@ -35,7 +35,7 @@
 
 use graphviz as dot;
 use rustc::dep_graph::debug::{DepNodeFilter, EdgeFilter};
-use rustc::dep_graph::{DepGraphQuery, DepKind, DepNode};
+use rustc::dep_graph::{DepGraphQuery, DepKind, DepNode, DepNodeExt};
 use rustc::hir::map::Map;
 use rustc::ty::TyCtxt;
 use rustc_ast::ast;
diff --git a/src/librustc_incremental/persist/dirty_clean.rs b/src/librustc_incremental/persist/dirty_clean.rs
index a7a272654f7..9ddd238afff 100644
--- a/src/librustc_incremental/persist/dirty_clean.rs
+++ b/src/librustc_incremental/persist/dirty_clean.rs
@@ -13,7 +13,7 @@
 //! Errors are reported if we are in the suitable configuration but
 //! the required condition is not met.
 
-use rustc::dep_graph::{label_strs, DepNode};
+use rustc::dep_graph::{label_strs, DepNode, DepNodeExt};
 use rustc::hir::map::Map;
 use rustc::ty::TyCtxt;
 use rustc_ast::ast::{self, Attribute, NestedMetaItem};
diff --git a/src/librustc_infer/infer/canonical/canonicalizer.rs b/src/librustc_infer/infer/canonical/canonicalizer.rs
index 7b01f39d810..4d9a81d4406 100644
--- a/src/librustc_infer/infer/canonical/canonicalizer.rs
+++ b/src/librustc_infer/infer/canonical/canonicalizer.rs
@@ -336,10 +336,6 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Canonicalizer<'cx, 'tcx> {
             | ty::ReEmpty(_)
             | ty::RePlaceholder(..)
             | ty::ReErased => self.canonicalize_region_mode.canonicalize_free_region(self, r),
-
-            ty::ReClosureBound(..) => {
-                bug!("closure bound region encountered during canonicalization");
-            }
         }
     }
 
diff --git a/src/librustc_infer/infer/combine.rs b/src/librustc_infer/infer/combine.rs
index 9d06e26d9bb..0f5d4d30a23 100644
--- a/src/librustc_infer/infer/combine.rs
+++ b/src/librustc_infer/infer/combine.rs
@@ -581,10 +581,6 @@ impl TypeRelation<'tcx> for Generalizer<'_, 'tcx> {
                 return Ok(r);
             }
 
-            ty::ReClosureBound(..) => {
-                span_bug!(self.span, "encountered unexpected ReClosureBound: {:?}", r,);
-            }
-
             ty::RePlaceholder(..)
             | ty::ReVar(..)
             | ty::ReEmpty(_)
diff --git a/src/librustc_infer/infer/error_reporting/mod.rs b/src/librustc_infer/infer/error_reporting/mod.rs
index 78f97c40cbd..a2ae4f53fb8 100644
--- a/src/librustc_infer/infer/error_reporting/mod.rs
+++ b/src/librustc_infer/infer/error_reporting/mod.rs
@@ -152,11 +152,6 @@ pub(super) fn note_and_explain_region(
         ty::ReVar(_) | ty::ReLateBound(..) | ty::ReErased => {
             (format!("lifetime {:?}", region), None)
         }
-
-        // We shouldn't encounter an error message with ReClosureBound.
-        ty::ReClosureBound(..) => {
-            bug!("encountered unexpected ReClosureBound: {:?}", region,);
-        }
     };
 
     emit_msg_span(err, prefix, description, span, suffix);
diff --git a/src/librustc_infer/infer/freshen.rs b/src/librustc_infer/infer/freshen.rs
index a454feea36b..fa28cf5b454 100644
--- a/src/librustc_infer/infer/freshen.rs
+++ b/src/librustc_infer/infer/freshen.rs
@@ -135,10 +135,6 @@ impl<'a, 'tcx> TypeFolder<'tcx> for TypeFreshener<'a, 'tcx> {
                 // replace all free regions with 'erased
                 self.tcx().lifetimes.re_erased
             }
-
-            ty::ReClosureBound(..) => {
-                bug!("encountered unexpected region: {:?}", r,);
-            }
         }
     }
 
diff --git a/src/librustc_infer/infer/lexical_region_resolve/mod.rs b/src/librustc_infer/infer/lexical_region_resolve/mod.rs
index 821b9f72c0b..d81c7454a0f 100644
--- a/src/librustc_infer/infer/lexical_region_resolve/mod.rs
+++ b/src/librustc_infer/infer/lexical_region_resolve/mod.rs
@@ -493,12 +493,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
     /// term "concrete regions").
     fn lub_concrete_regions(&self, a: Region<'tcx>, b: Region<'tcx>) -> Region<'tcx> {
         let r = match (a, b) {
-            (&ty::ReClosureBound(..), _)
-            | (_, &ty::ReClosureBound(..))
-            | (&ReLateBound(..), _)
-            | (_, &ReLateBound(..))
-            | (&ReErased, _)
-            | (_, &ReErased) => {
+            (&ReLateBound(..), _) | (_, &ReLateBound(..)) | (&ReErased, _) | (_, &ReErased) => {
                 bug!("cannot relate region: LUB({:?}, {:?})", a, b);
             }
 
diff --git a/src/librustc_infer/infer/region_constraints/mod.rs b/src/librustc_infer/infer/region_constraints/mod.rs
index 38475b02e5d..72637f4544a 100644
--- a/src/librustc_infer/infer/region_constraints/mod.rs
+++ b/src/librustc_infer/infer/region_constraints/mod.rs
@@ -798,7 +798,7 @@ impl<'tcx> RegionConstraintCollector<'tcx> {
             | ty::ReEarlyBound(..) => ty::UniverseIndex::ROOT,
             ty::ReEmpty(ui) => ui,
             ty::RePlaceholder(placeholder) => placeholder.universe,
-            ty::ReClosureBound(vid) | ty::ReVar(vid) => self.var_universe(vid),
+            ty::ReVar(vid) => self.var_universe(vid),
             ty::ReLateBound(..) => bug!("universe(): encountered bound region {:?}", region),
         }
     }
diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs
index 88f2284cd61..66d9fe7e149 100644
--- a/src/librustc_lint/builtin.rs
+++ b/src/librustc_lint/builtin.rs
@@ -349,6 +349,7 @@ impl MissingDoc {
         id: Option<hir::HirId>,
         attrs: &[ast::Attribute],
         sp: Span,
+        article: &'static str,
         desc: &'static str,
     ) {
         // If we're building a test harness, then warning about
@@ -374,7 +375,7 @@ impl MissingDoc {
         let has_doc = attrs.iter().any(|a| has_doc(a));
         if !has_doc {
             cx.struct_span_lint(MISSING_DOCS, cx.tcx.sess.source_map().def_span(sp), |lint| {
-                lint.build(&format!("missing documentation for {}", desc)).emit()
+                lint.build(&format!("missing documentation for {} {}", article, desc)).emit()
             });
         }
     }
@@ -398,7 +399,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingDoc {
     }
 
     fn check_crate(&mut self, cx: &LateContext<'_, '_>, krate: &hir::Crate<'_>) {
-        self.check_missing_docs_attrs(cx, None, &krate.item.attrs, krate.item.span, "crate");
+        self.check_missing_docs_attrs(cx, None, &krate.item.attrs, krate.item.span, "the", "crate");
 
         for macro_def in krate.exported_macros {
             let has_doc = macro_def.attrs.iter().any(|a| has_doc(a));
@@ -413,12 +414,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingDoc {
     }
 
     fn check_item(&mut self, cx: &LateContext<'_, '_>, it: &hir::Item<'_>) {
-        let desc = match it.kind {
-            hir::ItemKind::Fn(..) => "a function",
-            hir::ItemKind::Mod(..) => "a module",
-            hir::ItemKind::Enum(..) => "an enum",
-            hir::ItemKind::Struct(..) => "a struct",
-            hir::ItemKind::Union(..) => "a union",
+        match it.kind {
             hir::ItemKind::Trait(.., trait_item_refs) => {
                 // Issue #11592: traits are always considered exported, even when private.
                 if let hir::VisibilityKind::Inherited = it.vis.node {
@@ -428,33 +424,39 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingDoc {
                     }
                     return;
                 }
-                "a trait"
             }
-            hir::ItemKind::TyAlias(..) => "a type alias",
             hir::ItemKind::Impl { of_trait: Some(ref trait_ref), items, .. } => {
                 // If the trait is private, add the impl items to `private_traits` so they don't get
                 // reported for missing docs.
                 let real_trait = trait_ref.path.res.def_id();
                 if let Some(hir_id) = cx.tcx.hir().as_local_hir_id(real_trait) {
-                    match cx.tcx.hir().find(hir_id) {
-                        Some(Node::Item(item)) => {
-                            if let hir::VisibilityKind::Inherited = item.vis.node {
-                                for impl_item_ref in items {
-                                    self.private_traits.insert(impl_item_ref.id.hir_id);
-                                }
+                    if let Some(Node::Item(item)) = cx.tcx.hir().find(hir_id) {
+                        if let hir::VisibilityKind::Inherited = item.vis.node {
+                            for impl_item_ref in items {
+                                self.private_traits.insert(impl_item_ref.id.hir_id);
                             }
                         }
-                        _ => {}
                     }
                 }
                 return;
             }
-            hir::ItemKind::Const(..) => "a constant",
-            hir::ItemKind::Static(..) => "a static",
+
+            hir::ItemKind::TyAlias(..)
+            | hir::ItemKind::Fn(..)
+            | hir::ItemKind::Mod(..)
+            | hir::ItemKind::Enum(..)
+            | hir::ItemKind::Struct(..)
+            | hir::ItemKind::Union(..)
+            | hir::ItemKind::Const(..)
+            | hir::ItemKind::Static(..) => {}
+
             _ => return,
         };
 
-        self.check_missing_docs_attrs(cx, Some(it.hir_id), &it.attrs, it.span, desc);
+        let def_id = cx.tcx.hir().local_def_id(it.hir_id);
+        let (article, desc) = cx.tcx.article_and_description(def_id);
+
+        self.check_missing_docs_attrs(cx, Some(it.hir_id), &it.attrs, it.span, article, desc);
     }
 
     fn check_trait_item(&mut self, cx: &LateContext<'_, '_>, trait_item: &hir::TraitItem<'_>) {
@@ -462,17 +464,15 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingDoc {
             return;
         }
 
-        let desc = match trait_item.kind {
-            hir::TraitItemKind::Const(..) => "an associated constant",
-            hir::TraitItemKind::Fn(..) => "a trait method",
-            hir::TraitItemKind::Type(..) => "an associated type",
-        };
+        let def_id = cx.tcx.hir().local_def_id(trait_item.hir_id);
+        let (article, desc) = cx.tcx.article_and_description(def_id);
 
         self.check_missing_docs_attrs(
             cx,
             Some(trait_item.hir_id),
             &trait_item.attrs,
             trait_item.span,
+            article,
             desc,
         );
     }
@@ -483,29 +483,33 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingDoc {
             return;
         }
 
-        let desc = match impl_item.kind {
-            hir::ImplItemKind::Const(..) => "an associated constant",
-            hir::ImplItemKind::Fn(..) => "a method",
-            hir::ImplItemKind::TyAlias(_) => "an associated type",
-            hir::ImplItemKind::OpaqueTy(_) => "an associated `impl Trait` type",
-        };
+        let def_id = cx.tcx.hir().local_def_id(impl_item.hir_id);
+        let (article, desc) = cx.tcx.article_and_description(def_id);
         self.check_missing_docs_attrs(
             cx,
             Some(impl_item.hir_id),
             &impl_item.attrs,
             impl_item.span,
+            article,
             desc,
         );
     }
 
     fn check_struct_field(&mut self, cx: &LateContext<'_, '_>, sf: &hir::StructField<'_>) {
         if !sf.is_positional() {
-            self.check_missing_docs_attrs(cx, Some(sf.hir_id), &sf.attrs, sf.span, "a struct field")
+            self.check_missing_docs_attrs(
+                cx,
+                Some(sf.hir_id),
+                &sf.attrs,
+                sf.span,
+                "a",
+                "struct field",
+            )
         }
     }
 
     fn check_variant(&mut self, cx: &LateContext<'_, '_>, v: &hir::Variant<'_>) {
-        self.check_missing_docs_attrs(cx, Some(v.id), &v.attrs, v.span, "a variant");
+        self.check_missing_docs_attrs(cx, Some(v.id), &v.attrs, v.span, "a", "variant");
     }
 }
 
diff --git a/src/librustc_macros/src/query.rs b/src/librustc_macros/src/query.rs
index 56b7be2f7e2..e7005f2f5ba 100644
--- a/src/librustc_macros/src/query.rs
+++ b/src/librustc_macros/src/query.rs
@@ -429,14 +429,14 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream {
                 });
 
                 try_load_from_on_disk_cache_stream.extend(quote! {
-                    DepKind::#name => {
-                        if <#arg as DepNodeParams>::CAN_RECONSTRUCT_QUERY_KEY {
+                    ::rustc::dep_graph::DepKind::#name => {
+                        if <#arg as DepNodeParams<TyCtxt<'_>>>::CAN_RECONSTRUCT_QUERY_KEY {
                             debug_assert!($tcx.dep_graph
                                             .node_color($dep_node)
                                             .map(|c| c.is_green())
                                             .unwrap_or(false));
 
-                            let key = <#arg as DepNodeParams>::recover($tcx, $dep_node).unwrap();
+                            let key = <#arg as DepNodeParams<TyCtxt<'_>>>::recover($tcx, $dep_node).unwrap();
                             if queries::#name::cache_on_disk($tcx, key, None) {
                                 let _ = $tcx.#name(key);
                             }
@@ -486,9 +486,9 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream {
 
             // Add a match arm to force the query given the dep node
             dep_node_force_stream.extend(quote! {
-                DepKind::#name => {
-                    if <#arg as DepNodeParams>::CAN_RECONSTRUCT_QUERY_KEY {
-                        if let Some(key) = <#arg as DepNodeParams>::recover($tcx, $dep_node) {
+                ::rustc::dep_graph::DepKind::#name => {
+                    if <#arg as DepNodeParams<TyCtxt<'_>>>::CAN_RECONSTRUCT_QUERY_KEY {
+                        if let Some(key) = <#arg as DepNodeParams<TyCtxt<'_>>>::recover($tcx, $dep_node) {
                             $tcx.force_query::<crate::ty::query::queries::#name<'_>>(
                                 key,
                                 DUMMY_SP,
@@ -509,7 +509,7 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream {
     }
 
     dep_node_force_stream.extend(quote! {
-        DepKind::Null => {
+        ::rustc::dep_graph::DepKind::Null => {
             bug!("Cannot force dep node: {:?}", $dep_node)
         }
     });
diff --git a/src/librustc_metadata/rmeta/decoder.rs b/src/librustc_metadata/rmeta/decoder.rs
index e7e05097a54..4e086bcbb2d 100644
--- a/src/librustc_metadata/rmeta/decoder.rs
+++ b/src/librustc_metadata/rmeta/decoder.rs
@@ -4,7 +4,7 @@ use crate::creader::CrateMetadataRef;
 use crate::rmeta::table::{FixedSizeEncoding, Table};
 use crate::rmeta::*;
 
-use rustc::dep_graph::{self, DepNode, DepNodeIndex};
+use rustc::dep_graph::{self, DepNode, DepNodeExt, DepNodeIndex};
 use rustc::hir::exports::Export;
 use rustc::middle::cstore::{CrateSource, ExternCrate};
 use rustc::middle::cstore::{ForeignModule, LinkagePreference, NativeLibrary};
diff --git a/src/librustc_mir/borrow_check/diagnostics/mutability_errors.rs b/src/librustc_mir/borrow_check/diagnostics/mutability_errors.rs
index c462f934148..ee654431d88 100644
--- a/src/librustc_mir/borrow_check/diagnostics/mutability_errors.rs
+++ b/src/librustc_mir/borrow_check/diagnostics/mutability_errors.rs
@@ -1,9 +1,10 @@
-use rustc::mir::{self, ClearCrossCrate, Local, LocalInfo, Location, ReadOnlyBodyAndCache};
+use rustc::mir::{self, ClearCrossCrate, Local, LocalInfo, Location};
 use rustc::mir::{Mutability, Place, PlaceRef, ProjectionElem};
 use rustc::ty::{self, Ty, TyCtxt};
 use rustc_hir as hir;
 use rustc_hir::Node;
 use rustc_index::vec::Idx;
+use rustc_span::source_map::DesugaringKind;
 use rustc_span::symbol::kw;
 use rustc_span::Span;
 
@@ -338,10 +339,14 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
 
                 match self.local_names[local] {
                     Some(name) if !local_decl.from_compiler_desugaring() => {
-                        let suggestion = match local_decl.local_info {
+                        let label = match local_decl.local_info {
                             LocalInfo::User(ClearCrossCrate::Set(
                                 mir::BindingForm::ImplicitSelf(_),
-                            )) => Some(suggest_ampmut_self(self.infcx.tcx, local_decl)),
+                            )) => {
+                                let (span, suggestion) =
+                                    suggest_ampmut_self(self.infcx.tcx, local_decl);
+                                Some((true, span, suggestion))
+                            }
 
                             LocalInfo::User(ClearCrossCrate::Set(mir::BindingForm::Var(
                                 mir::VarBindingForm {
@@ -349,13 +354,38 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
                                     opt_ty_info,
                                     ..
                                 },
-                            ))) => Some(suggest_ampmut(
-                                self.infcx.tcx,
-                                self.body,
-                                local,
-                                local_decl,
-                                opt_ty_info,
-                            )),
+                            ))) => {
+                                // check if the RHS is from desugaring
+                                let locations = self.body.find_assignments(local);
+                                let opt_assignment_rhs_span = locations
+                                    .first()
+                                    .map(|&location| self.body.source_info(location).span);
+                                let opt_desugaring_kind =
+                                    opt_assignment_rhs_span.and_then(|span| span.desugaring_kind());
+                                match opt_desugaring_kind {
+                                    // on for loops, RHS points to the iterator part
+                                    Some(DesugaringKind::ForLoop) => Some((
+                                        false,
+                                        opt_assignment_rhs_span.unwrap(),
+                                        format!(
+                                            "this iterator yields `{SIGIL}` {DESC}s",
+                                            SIGIL = pointer_sigil,
+                                            DESC = pointer_desc
+                                        ),
+                                    )),
+                                    // don't create labels for compiler-generated spans
+                                    Some(_) => None,
+                                    None => {
+                                        let (span, suggestion) = suggest_ampmut(
+                                            self.infcx.tcx,
+                                            local_decl,
+                                            opt_assignment_rhs_span,
+                                            opt_ty_info,
+                                        );
+                                        Some((true, span, suggestion))
+                                    }
+                                }
+                            }
 
                             LocalInfo::User(ClearCrossCrate::Set(mir::BindingForm::Var(
                                 mir::VarBindingForm {
@@ -365,7 +395,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
                             ))) => {
                                 let pattern_span = local_decl.source_info.span;
                                 suggest_ref_mut(self.infcx.tcx, pattern_span)
-                                    .map(|replacement| (pattern_span, replacement))
+                                    .map(|replacement| (true, pattern_span, replacement))
                             }
 
                             LocalInfo::User(ClearCrossCrate::Clear) => {
@@ -375,13 +405,22 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
                             _ => unreachable!(),
                         };
 
-                        if let Some((err_help_span, suggested_code)) = suggestion {
-                            err.span_suggestion(
-                                err_help_span,
-                                &format!("consider changing this to be a mutable {}", pointer_desc),
-                                suggested_code,
-                                Applicability::MachineApplicable,
-                            );
+                        match label {
+                            Some((true, err_help_span, suggested_code)) => {
+                                err.span_suggestion(
+                                    err_help_span,
+                                    &format!(
+                                        "consider changing this to be a mutable {}",
+                                        pointer_desc
+                                    ),
+                                    suggested_code,
+                                    Applicability::MachineApplicable,
+                                );
+                            }
+                            Some((false, err_label_span, message)) => {
+                                err.span_label(err_label_span, &message);
+                            }
+                            None => {}
                         }
                         err.span_label(
                             span,
@@ -581,14 +620,11 @@ fn suggest_ampmut_self<'tcx>(
 // by trying (3.), then (2.) and finally falling back on (1.).
 fn suggest_ampmut<'tcx>(
     tcx: TyCtxt<'tcx>,
-    body: ReadOnlyBodyAndCache<'_, 'tcx>,
-    local: Local,
     local_decl: &mir::LocalDecl<'tcx>,
+    opt_assignment_rhs_span: Option<Span>,
     opt_ty_info: Option<Span>,
 ) -> (Span, String) {
-    let locations = body.find_assignments(local);
-    if !locations.is_empty() {
-        let assignment_rhs_span = body.source_info(locations[0]).span;
+    if let Some(assignment_rhs_span) = opt_assignment_rhs_span {
         if let Ok(src) = tcx.sess.source_map().span_to_snippet(assignment_rhs_span) {
             if let (true, Some(ws_pos)) =
                 (src.starts_with("&'"), src.find(|c: char| -> bool { c.is_whitespace() }))
diff --git a/src/librustc_mir/borrow_check/diagnostics/region_name.rs b/src/librustc_mir/borrow_check/diagnostics/region_name.rs
index 164125a145b..6756f476f61 100644
--- a/src/librustc_mir/borrow_check/diagnostics/region_name.rs
+++ b/src/librustc_mir/borrow_check/diagnostics/region_name.rs
@@ -292,8 +292,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
             | ty::ReVar(..)
             | ty::RePlaceholder(..)
             | ty::ReEmpty(_)
-            | ty::ReErased
-            | ty::ReClosureBound(..) => None,
+            | ty::ReErased => None,
         }
     }
 
diff --git a/src/librustc_mir/borrow_check/region_infer/mod.rs b/src/librustc_mir/borrow_check/region_infer/mod.rs
index fe96b3e34a2..c8b0e59ebb1 100644
--- a/src/librustc_mir/borrow_check/region_infer/mod.rs
+++ b/src/librustc_mir/borrow_check/region_infer/mod.rs
@@ -940,8 +940,9 @@ impl<'tcx> RegionInferenceContext<'tcx> {
     /// inference variables with some region from the closure
     /// signature -- this is not always possible, so this is a
     /// fallible process. Presuming we do find a suitable region, we
-    /// will represent it with a `ReClosureBound`, which is a
-    /// `RegionKind` variant that can be allocated in the gcx.
+    /// will use it's *external name*, which will be a `RegionKind`
+    /// variant that can be used in query responses such as
+    /// `ReEarlyBound`.
     fn try_promote_type_test_subject(
         &self,
         infcx: &InferCtxt<'_, 'tcx>,
@@ -991,14 +992,14 @@ impl<'tcx> RegionInferenceContext<'tcx> {
             // find an equivalent.
             let upper_bound = self.non_local_universal_upper_bound(region_vid);
             if self.region_contains(region_vid, upper_bound) {
-                tcx.mk_region(ty::ReClosureBound(upper_bound))
+                self.definitions[upper_bound].external_name.unwrap_or(r)
             } else {
-                // In the case of a failure, use a `ReVar`
-                // result. This will cause the `lift` later on to
-                // fail.
+                // In the case of a failure, use a `ReVar` result. This will
+                // cause the `has_local_value` later on to return `None`.
                 r
             }
         });
+
         debug!("try_promote_type_test_subject: folded ty = {:?}", ty);
 
         // `has_local_value` will only be true if we failed to promote some region.
@@ -2029,15 +2030,6 @@ pub trait ClosureRegionRequirementsExt<'tcx> {
         closure_def_id: DefId,
         closure_substs: SubstsRef<'tcx>,
     ) -> Vec<QueryOutlivesConstraint<'tcx>>;
-
-    fn subst_closure_mapping<T>(
-        &self,
-        tcx: TyCtxt<'tcx>,
-        closure_mapping: &IndexVec<RegionVid, ty::Region<'tcx>>,
-        value: &T,
-    ) -> T
-    where
-        T: TypeFoldable<'tcx>;
 }
 
 impl<'tcx> ClosureRegionRequirementsExt<'tcx> for ClosureRegionRequirements<'tcx> {
@@ -2094,7 +2086,6 @@ impl<'tcx> ClosureRegionRequirementsExt<'tcx> for ClosureRegionRequirements<'tcx
                     }
 
                     ClosureOutlivesSubject::Ty(ty) => {
-                        let ty = self.subst_closure_mapping(tcx, closure_mapping, &ty);
                         debug!(
                             "apply_requirements: ty={:?} \
                              outlived_region={:?} \
@@ -2107,22 +2098,4 @@ impl<'tcx> ClosureRegionRequirementsExt<'tcx> for ClosureRegionRequirements<'tcx
             })
             .collect()
     }
-
-    fn subst_closure_mapping<T>(
-        &self,
-        tcx: TyCtxt<'tcx>,
-        closure_mapping: &IndexVec<RegionVid, ty::Region<'tcx>>,
-        value: &T,
-    ) -> T
-    where
-        T: TypeFoldable<'tcx>,
-    {
-        tcx.fold_regions(value, &mut false, |r, _depth| {
-            if let ty::ReClosureBound(vid) = r {
-                closure_mapping[*vid]
-            } else {
-                bug!("subst_closure_mapping: encountered non-closure bound free region {:?}", r)
-            }
-        })
-    }
 }
diff --git a/src/librustc_mir/borrow_check/type_check/mod.rs b/src/librustc_mir/borrow_check/type_check/mod.rs
index 52fc48806fb..f94160cc08a 100644
--- a/src/librustc_mir/borrow_check/type_check/mod.rs
+++ b/src/librustc_mir/borrow_check/type_check/mod.rs
@@ -1986,7 +1986,11 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
             }
 
             Rvalue::Repeat(operand, len) => {
-                if *len > 1 {
+                // If the length cannot be evaluated we must assume that the length can be larger
+                // than 1.
+                // If the length is larger than 1, the repeat expression will need to copy the
+                // element, so we require the `Copy` trait.
+                if len.try_eval_usize(tcx, self.param_env).map_or(true, |len| len > 1) {
                     if let Operand::Move(_) = operand {
                         // While this is located in `nll::typeck` this error is not an NLL error, it's
                         // a required check to make sure that repeated elements implement `Copy`.
diff --git a/src/librustc_mir/const_eval/machine.rs b/src/librustc_mir/const_eval/machine.rs
index 87d0424ece9..ab88a92ea7b 100644
--- a/src/librustc_mir/const_eval/machine.rs
+++ b/src/librustc_mir/const_eval/machine.rs
@@ -3,7 +3,6 @@ use rustc::ty::layout::HasTyCtxt;
 use rustc::ty::{self, Ty};
 use std::borrow::{Borrow, Cow};
 use std::collections::hash_map::Entry;
-use std::convert::TryFrom;
 use std::hash::Hash;
 
 use rustc_data_structures::fx::FxHashMap;
@@ -13,13 +12,13 @@ use rustc_span::source_map::Span;
 use rustc_span::symbol::Symbol;
 
 use crate::interpret::{
-    self, snapshot, AllocId, Allocation, GlobalId, ImmTy, InterpCx, InterpResult, Memory,
-    MemoryKind, OpTy, PlaceTy, Pointer, Scalar,
+    self, AllocId, Allocation, GlobalId, ImmTy, InterpCx, InterpResult, Memory, MemoryKind, OpTy,
+    PlaceTy, Pointer, Scalar,
 };
 
 use super::error::*;
 
-impl<'mir, 'tcx> InterpCx<'mir, 'tcx, CompileTimeInterpreter<'mir, 'tcx>> {
+impl<'mir, 'tcx> InterpCx<'mir, 'tcx, CompileTimeInterpreter> {
     /// Evaluate a const function where all arguments (if any) are zero-sized types.
     /// The evaluation is memoized thanks to the query system.
     ///
@@ -86,22 +85,13 @@ impl<'mir, 'tcx> InterpCx<'mir, 'tcx, CompileTimeInterpreter<'mir, 'tcx>> {
     }
 }
 
-/// The number of steps between loop detector snapshots.
-/// Should be a power of two for performance reasons.
-const DETECTOR_SNAPSHOT_PERIOD: isize = 256;
-
-// Extra machine state for CTFE, and the Machine instance
-pub struct CompileTimeInterpreter<'mir, 'tcx> {
-    /// When this value is negative, it indicates the number of interpreter
-    /// steps *until* the loop detector is enabled. When it is positive, it is
-    /// the number of steps after the detector has been enabled modulo the loop
-    /// detector period.
-    pub(super) steps_since_detector_enabled: isize,
-
-    pub(super) is_detector_enabled: bool,
-
-    /// Extra state to detect loops.
-    pub(super) loop_detector: snapshot::InfiniteLoopDetector<'mir, 'tcx>,
+/// Extra machine state for CTFE, and the Machine instance
+pub struct CompileTimeInterpreter {
+    /// For now, the number of terminators that can be evaluated before we throw a resource
+    /// exhuastion error.
+    ///
+    /// Setting this to `0` disables the limit and allows the interpreter to run forever.
+    pub steps_remaining: usize,
 }
 
 #[derive(Copy, Clone, Debug)]
@@ -110,16 +100,9 @@ pub struct MemoryExtra {
     pub(super) can_access_statics: bool,
 }
 
-impl<'mir, 'tcx> CompileTimeInterpreter<'mir, 'tcx> {
+impl CompileTimeInterpreter {
     pub(super) fn new(const_eval_limit: usize) -> Self {
-        let steps_until_detector_enabled =
-            isize::try_from(const_eval_limit).unwrap_or(std::isize::MAX);
-
-        CompileTimeInterpreter {
-            loop_detector: Default::default(),
-            steps_since_detector_enabled: -steps_until_detector_enabled,
-            is_detector_enabled: const_eval_limit != 0,
-        }
+        CompileTimeInterpreter { steps_remaining: const_eval_limit }
     }
 }
 
@@ -173,8 +156,7 @@ impl<K: Hash + Eq, V> interpret::AllocMap<K, V> for FxHashMap<K, V> {
     }
 }
 
-crate type CompileTimeEvalContext<'mir, 'tcx> =
-    InterpCx<'mir, 'tcx, CompileTimeInterpreter<'mir, 'tcx>>;
+crate type CompileTimeEvalContext<'mir, 'tcx> = InterpCx<'mir, 'tcx, CompileTimeInterpreter>;
 
 impl interpret::MayLeak for ! {
     #[inline(always)]
@@ -184,7 +166,7 @@ impl interpret::MayLeak for ! {
     }
 }
 
-impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, 'tcx> {
+impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter {
     type MemoryKinds = !;
     type PointerTag = ();
     type ExtraFnVal = !;
@@ -345,26 +327,17 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
     }
 
     fn before_terminator(ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx> {
-        if !ecx.machine.is_detector_enabled {
+        // The step limit has already been hit in a previous call to `before_terminator`.
+        if ecx.machine.steps_remaining == 0 {
             return Ok(());
         }
 
-        {
-            let steps = &mut ecx.machine.steps_since_detector_enabled;
-
-            *steps += 1;
-            if *steps < 0 {
-                return Ok(());
-            }
-
-            *steps %= DETECTOR_SNAPSHOT_PERIOD;
-            if *steps != 0 {
-                return Ok(());
-            }
+        ecx.machine.steps_remaining -= 1;
+        if ecx.machine.steps_remaining == 0 {
+            throw_exhaust!(StepLimitReached)
         }
 
-        let span = ecx.frame().span;
-        ecx.machine.loop_detector.observe_and_analyze(*ecx.tcx, span, &ecx.memory, &ecx.stack[..])
+        Ok(())
     }
 
     #[inline(always)]
diff --git a/src/librustc_mir/interpret/memory.rs b/src/librustc_mir/interpret/memory.rs
index 5b2cd89a122..277a77af3fd 100644
--- a/src/librustc_mir/interpret/memory.rs
+++ b/src/librustc_mir/interpret/memory.rs
@@ -112,25 +112,6 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> HasDataLayout for Memory<'mir, 'tcx, M>
     }
 }
 
-// FIXME: Really we shouldn't clone memory, ever. Snapshot machinery should instead
-// carefully copy only the reachable parts.
-impl<'mir, 'tcx, M> Clone for Memory<'mir, 'tcx, M>
-where
-    M: Machine<'mir, 'tcx, PointerTag = (), AllocExtra = ()>,
-    M::MemoryExtra: Copy,
-    M::MemoryMap: AllocMap<AllocId, (MemoryKind<M::MemoryKinds>, Allocation)>,
-{
-    fn clone(&self) -> Self {
-        Memory {
-            alloc_map: self.alloc_map.clone(),
-            extra_fn_ptr_map: self.extra_fn_ptr_map.clone(),
-            dead_alloc_map: self.dead_alloc_map.clone(),
-            extra: self.extra,
-            tcx: self.tcx,
-        }
-    }
-}
-
 impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
     pub fn new(tcx: TyCtxtAt<'tcx>, extra: M::MemoryExtra) -> Self {
         Memory {
diff --git a/src/librustc_mir/interpret/mod.rs b/src/librustc_mir/interpret/mod.rs
index c3fd9682765..3063a99886b 100644
--- a/src/librustc_mir/interpret/mod.rs
+++ b/src/librustc_mir/interpret/mod.rs
@@ -9,7 +9,6 @@ mod memory;
 mod operand;
 mod operator;
 mod place;
-pub(crate) mod snapshot; // for const_eval
 mod step;
 mod terminator;
 mod traits;
diff --git a/src/librustc_mir/interpret/snapshot.rs b/src/librustc_mir/interpret/snapshot.rs
deleted file mode 100644
index ee45179fd8b..00000000000
--- a/src/librustc_mir/interpret/snapshot.rs
+++ /dev/null
@@ -1,420 +0,0 @@
-//! This module contains the machinery necessary to detect infinite loops
-//! during const-evaluation by taking snapshots of the state of the interpreter
-//! at regular intervals.
-
-// This lives in `interpret` because it needs access to all sots of private state.  However,
-// it is not used by the general miri engine, just by CTFE.
-
-use std::hash::{Hash, Hasher};
-
-use rustc::ich::StableHashingContextProvider;
-use rustc::mir;
-use rustc::mir::interpret::{
-    AllocId, Allocation, InterpResult, Pointer, Relocations, Scalar, UndefMask,
-};
-
-use rustc::ty::layout::{Align, Size};
-use rustc::ty::{self, TyCtxt};
-use rustc_ast::ast::Mutability;
-use rustc_data_structures::fx::FxHashSet;
-use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
-use rustc_index::vec::IndexVec;
-use rustc_macros::HashStable;
-use rustc_span::source_map::Span;
-
-use super::eval_context::{LocalState, StackPopCleanup};
-use super::{
-    Frame, Immediate, LocalValue, MemPlace, MemPlaceMeta, Memory, Operand, Place, ScalarMaybeUndef,
-};
-use crate::const_eval::CompileTimeInterpreter;
-
-#[derive(Default)]
-pub(crate) struct InfiniteLoopDetector<'mir, 'tcx> {
-    /// The set of all `InterpSnapshot` *hashes* observed by this detector.
-    ///
-    /// When a collision occurs in this table, we store the full snapshot in
-    /// `snapshots`.
-    hashes: FxHashSet<u64>,
-
-    /// The set of all `InterpSnapshot`s observed by this detector.
-    ///
-    /// An `InterpSnapshot` will only be fully cloned once it has caused a
-    /// collision in `hashes`. As a result, the detector must observe at least
-    /// *two* full cycles of an infinite loop before it triggers.
-    snapshots: FxHashSet<InterpSnapshot<'mir, 'tcx>>,
-}
-
-impl<'mir, 'tcx> InfiniteLoopDetector<'mir, 'tcx> {
-    pub fn observe_and_analyze(
-        &mut self,
-        tcx: TyCtxt<'tcx>,
-        span: Span,
-        memory: &Memory<'mir, 'tcx, CompileTimeInterpreter<'mir, 'tcx>>,
-        stack: &[Frame<'mir, 'tcx>],
-    ) -> InterpResult<'tcx, ()> {
-        // Compute stack's hash before copying anything
-        let mut hcx = tcx.get_stable_hashing_context();
-        let mut hasher = StableHasher::new();
-        stack.hash_stable(&mut hcx, &mut hasher);
-        let hash = hasher.finish::<u64>();
-
-        // Check if we know that hash already
-        if self.hashes.is_empty() {
-            // FIXME(#49980): make this warning a lint
-            tcx.sess.span_warn(
-                span,
-                "Constant evaluating a complex constant, this might take some time",
-            );
-        }
-        if self.hashes.insert(hash) {
-            // No collision
-            return Ok(());
-        }
-
-        // We need to make a full copy. NOW things that to get really expensive.
-        info!("snapshotting the state of the interpreter");
-
-        if self.snapshots.insert(InterpSnapshot::new(memory, stack)) {
-            // Spurious collision or first cycle
-            return Ok(());
-        }
-
-        // Second cycle
-        throw_exhaust!(InfiniteLoop)
-    }
-}
-
-trait SnapshotContext<'a> {
-    fn resolve(&'a self, id: &AllocId) -> Option<&'a Allocation>;
-}
-
-/// Taking a snapshot of the evaluation context produces a view of
-/// the state of the interpreter that is invariant to `AllocId`s.
-trait Snapshot<'a, Ctx: SnapshotContext<'a>> {
-    type Item;
-    fn snapshot(&self, ctx: &'a Ctx) -> Self::Item;
-}
-
-macro_rules! __impl_snapshot_field {
-    ($field:ident, $ctx:expr) => {
-        $field.snapshot($ctx)
-    };
-    ($field:ident, $ctx:expr, $delegate:expr) => {
-        $delegate
-    };
-}
-
-// This assumes the type has two type parameters, first for the tag (set to `()`),
-// then for the id
-macro_rules! impl_snapshot_for {
-    (enum $enum_name:ident {
-        $( $variant:ident $( ( $($field:ident $(-> $delegate:expr)?),* ) )? ),* $(,)?
-    }) => {
-
-        impl<'a, Ctx> self::Snapshot<'a, Ctx> for $enum_name
-            where Ctx: self::SnapshotContext<'a>,
-        {
-            type Item = $enum_name<(), AllocIdSnapshot<'a>>;
-
-            #[inline]
-            fn snapshot(&self, __ctx: &'a Ctx) -> Self::Item {
-                match *self {
-                    $(
-                        $enum_name::$variant $( ( $(ref $field),* ) )? => {
-                            $enum_name::$variant $(
-                                ( $( __impl_snapshot_field!($field, __ctx $(, $delegate)?) ),* )
-                            )?
-                        }
-                    )*
-                }
-            }
-        }
-    };
-
-    (struct $struct_name:ident { $($field:ident $(-> $delegate:expr)?),*  $(,)? }) => {
-        impl<'a, Ctx> self::Snapshot<'a, Ctx> for $struct_name
-            where Ctx: self::SnapshotContext<'a>,
-        {
-            type Item = $struct_name<(), AllocIdSnapshot<'a>>;
-
-            #[inline]
-            fn snapshot(&self, __ctx: &'a Ctx) -> Self::Item {
-                let $struct_name {
-                    $(ref $field),*
-                } = *self;
-
-                $struct_name {
-                    $( $field: __impl_snapshot_field!($field, __ctx $(, $delegate)?) ),*
-                }
-            }
-        }
-    };
-}
-
-impl<'a, Ctx, T> Snapshot<'a, Ctx> for Option<T>
-where
-    Ctx: SnapshotContext<'a>,
-    T: Snapshot<'a, Ctx>,
-{
-    type Item = Option<<T as Snapshot<'a, Ctx>>::Item>;
-
-    fn snapshot(&self, ctx: &'a Ctx) -> Self::Item {
-        match self {
-            Some(x) => Some(x.snapshot(ctx)),
-            None => None,
-        }
-    }
-}
-
-#[derive(Eq, PartialEq)]
-struct AllocIdSnapshot<'a>(Option<AllocationSnapshot<'a>>);
-
-impl<'a, Ctx> Snapshot<'a, Ctx> for AllocId
-where
-    Ctx: SnapshotContext<'a>,
-{
-    type Item = AllocIdSnapshot<'a>;
-
-    fn snapshot(&self, ctx: &'a Ctx) -> Self::Item {
-        AllocIdSnapshot(ctx.resolve(self).map(|alloc| alloc.snapshot(ctx)))
-    }
-}
-
-impl_snapshot_for!(struct Pointer {
-    alloc_id,
-    offset -> *offset, // just copy offset verbatim
-    tag -> *tag, // just copy tag
-});
-
-impl<'a, Ctx> Snapshot<'a, Ctx> for Scalar
-where
-    Ctx: SnapshotContext<'a>,
-{
-    type Item = Scalar<(), AllocIdSnapshot<'a>>;
-
-    fn snapshot(&self, ctx: &'a Ctx) -> Self::Item {
-        match self {
-            Scalar::Ptr(p) => Scalar::Ptr(p.snapshot(ctx)),
-            Scalar::Raw { size, data } => Scalar::Raw { data: *data, size: *size },
-        }
-    }
-}
-
-impl_snapshot_for!(
-    enum ScalarMaybeUndef {
-        Scalar(s),
-        Undef,
-    }
-);
-
-impl_snapshot_for!(
-    enum MemPlaceMeta {
-        Meta(s),
-        None,
-        Poison,
-    }
-);
-
-impl_snapshot_for!(struct MemPlace {
-    ptr,
-    meta,
-    align -> *align, // just copy alignment verbatim
-});
-
-impl<'a, Ctx> Snapshot<'a, Ctx> for Place
-where
-    Ctx: SnapshotContext<'a>,
-{
-    type Item = Place<(), AllocIdSnapshot<'a>>;
-
-    fn snapshot(&self, ctx: &'a Ctx) -> Self::Item {
-        match self {
-            Place::Ptr(p) => Place::Ptr(p.snapshot(ctx)),
-
-            Place::Local { frame, local } => Place::Local { frame: *frame, local: *local },
-        }
-    }
-}
-
-impl_snapshot_for!(
-    enum Immediate {
-        Scalar(s),
-        ScalarPair(s, t),
-    }
-);
-
-impl_snapshot_for!(
-    enum Operand {
-        Immediate(v),
-        Indirect(m),
-    }
-);
-
-impl_snapshot_for!(
-    enum LocalValue {
-        Dead,
-        Uninitialized,
-        Live(v),
-    }
-);
-
-impl<'a, Ctx> Snapshot<'a, Ctx> for Relocations
-where
-    Ctx: SnapshotContext<'a>,
-{
-    type Item = Relocations<(), AllocIdSnapshot<'a>>;
-
-    fn snapshot(&self, ctx: &'a Ctx) -> Self::Item {
-        Relocations::from_presorted(
-            self.iter().map(|(size, ((), id))| (*size, ((), id.snapshot(ctx)))).collect(),
-        )
-    }
-}
-
-#[derive(Eq, PartialEq)]
-struct AllocationSnapshot<'a> {
-    bytes: &'a [u8],
-    relocations: Relocations<(), AllocIdSnapshot<'a>>,
-    undef_mask: &'a UndefMask,
-    align: &'a Align,
-    size: &'a Size,
-    mutability: &'a Mutability,
-}
-
-impl<'a, Ctx> Snapshot<'a, Ctx> for &'a Allocation
-where
-    Ctx: SnapshotContext<'a>,
-{
-    type Item = AllocationSnapshot<'a>;
-
-    fn snapshot(&self, ctx: &'a Ctx) -> Self::Item {
-        let Allocation { size, align, mutability, extra: (), .. } = self;
-
-        let all_bytes = 0..self.len();
-        // This 'inspect' is okay since following access respects undef and relocations. This does
-        // influence interpreter exeuction, but only to detect the error of cycles in evaluation
-        // dependencies.
-        let bytes = self.inspect_with_undef_and_ptr_outside_interpreter(all_bytes);
-
-        let undef_mask = self.undef_mask();
-        let relocations = self.relocations();
-
-        AllocationSnapshot {
-            bytes,
-            undef_mask,
-            align,
-            size,
-            mutability,
-            relocations: relocations.snapshot(ctx),
-        }
-    }
-}
-
-#[derive(Eq, PartialEq)]
-struct FrameSnapshot<'a, 'tcx> {
-    instance: ty::Instance<'tcx>,
-    span: Span,
-    return_to_block: &'a StackPopCleanup,
-    return_place: Option<Place<(), AllocIdSnapshot<'a>>>,
-    locals: IndexVec<mir::Local, LocalValue<(), AllocIdSnapshot<'a>>>,
-    block: Option<mir::BasicBlock>,
-    stmt: usize,
-}
-
-impl<'a, 'mir, 'tcx, Ctx> Snapshot<'a, Ctx> for &'a Frame<'mir, 'tcx>
-where
-    Ctx: SnapshotContext<'a>,
-{
-    type Item = FrameSnapshot<'a, 'tcx>;
-
-    fn snapshot(&self, ctx: &'a Ctx) -> Self::Item {
-        let Frame {
-            body: _,
-            instance,
-            span,
-            return_to_block,
-            return_place,
-            locals,
-            block,
-            stmt,
-            extra: _,
-        } = self;
-
-        FrameSnapshot {
-            instance: *instance,
-            span: *span,
-            return_to_block,
-            block: *block,
-            stmt: *stmt,
-            return_place: return_place.map(|r| r.snapshot(ctx)),
-            locals: locals.iter().map(|local| local.snapshot(ctx)).collect(),
-        }
-    }
-}
-
-impl<'a, 'tcx, Ctx> Snapshot<'a, Ctx> for &'a LocalState<'tcx>
-where
-    Ctx: SnapshotContext<'a>,
-{
-    type Item = LocalValue<(), AllocIdSnapshot<'a>>;
-
-    fn snapshot(&self, ctx: &'a Ctx) -> Self::Item {
-        let LocalState { value, layout: _ } = self;
-        value.snapshot(ctx)
-    }
-}
-
-impl<'b, 'mir, 'tcx> SnapshotContext<'b>
-    for Memory<'mir, 'tcx, CompileTimeInterpreter<'mir, 'tcx>>
-{
-    fn resolve(&'b self, id: &AllocId) -> Option<&'b Allocation> {
-        self.get_raw(*id).ok()
-    }
-}
-
-/// 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>>,
-}
-
-impl InterpSnapshot<'mir, 'tcx> {
-    fn new(
-        memory: &Memory<'mir, 'tcx, CompileTimeInterpreter<'mir, 'tcx>>,
-        stack: &[Frame<'mir, 'tcx>],
-    ) -> Self {
-        InterpSnapshot { memory: memory.clone(), stack: stack.into() }
-    }
-
-    // Used to compare two snapshots
-    fn snapshot(&'b self) -> Vec<FrameSnapshot<'b, 'tcx>> {
-        // Start with the stack, iterate and recursively snapshot
-        self.stack.iter().map(|frame| frame.snapshot(&self.memory)).collect()
-    }
-}
-
-impl<'mir, 'tcx> Hash for InterpSnapshot<'mir, 'tcx> {
-    fn hash<H: Hasher>(&self, state: &mut H) {
-        // Implement in terms of hash stable, so that k1 == k2 -> hash(k1) == hash(k2)
-        let mut hcx = self.memory.tcx.get_stable_hashing_context();
-        let mut hasher = StableHasher::new();
-        self.hash_stable(&mut hcx, &mut hasher);
-        hasher.finish::<u64>().hash(state)
-    }
-}
-
-impl<'mir, 'tcx> Eq for InterpSnapshot<'mir, 'tcx> {}
-
-impl<'mir, 'tcx> PartialEq for InterpSnapshot<'mir, 'tcx> {
-    fn eq(&self, other: &Self) -> bool {
-        // FIXME: This looks to be a *ridiculously expensive* comparison operation.
-        // Doesn't this make tons of copies?  Either `snapshot` is very badly named,
-        // or it does!
-        self.snapshot() == other.snapshot()
-    }
-}
diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs
index a19901f3778..8899f12b153 100644
--- a/src/librustc_mir/transform/const_prop.rs
+++ b/src/librustc_mir/transform/const_prop.rs
@@ -39,6 +39,24 @@ use crate::transform::{MirPass, MirSource};
 /// The maximum number of bytes that we'll allocate space for a return value.
 const MAX_ALLOC_LIMIT: u64 = 1024;
 
+/// Macro for machine-specific `InterpError` without allocation.
+/// (These will never be shown to the user, but they help diagnose ICEs.)
+macro_rules! throw_machine_stop_str {
+    ($($tt:tt)*) => {{
+        // We make a new local type for it. The type itself does not carry any information,
+        // but its vtable (for the `MachineStopType` trait) does.
+        struct Zst;
+        // Debug-printing this type shows the desired string.
+        impl std::fmt::Debug for Zst {
+            fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+                write!(f, $($tt)*)
+            }
+        }
+        impl rustc::mir::interpret::MachineStopType for Zst {}
+        throw_machine_stop!(Zst)
+    }};
+}
+
 pub struct ConstProp;
 
 impl<'tcx> MirPass<'tcx> for ConstProp {
@@ -192,7 +210,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine {
         _ret: Option<(PlaceTy<'tcx>, BasicBlock)>,
         _unwind: Option<BasicBlock>,
     ) -> InterpResult<'tcx> {
-        throw_unsup!(ConstPropUnsupported("calling intrinsics isn't supported in ConstProp"))
+        throw_machine_stop_str!("calling intrinsics isn't supported in ConstProp")
     }
 
     fn assert_panic(
@@ -204,7 +222,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine {
     }
 
     fn ptr_to_int(_mem: &Memory<'mir, 'tcx, Self>, _ptr: Pointer) -> InterpResult<'tcx, u64> {
-        throw_unsup!(ConstPropUnsupported("ptr-to-int casts aren't supported in ConstProp"))
+        throw_unsup!(ReadPointerAsBytes)
     }
 
     fn binary_ptr_op(
@@ -214,10 +232,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine {
         _right: ImmTy<'tcx>,
     ) -> InterpResult<'tcx, (Scalar, bool, Ty<'tcx>)> {
         // We can't do this because aliasing of memory can differ between const eval and llvm
-        throw_unsup!(ConstPropUnsupported(
-            "pointer arithmetic or comparisons aren't supported \
-            in ConstProp"
-        ))
+        throw_machine_stop_str!("pointer arithmetic or comparisons aren't supported in ConstProp")
     }
 
     #[inline(always)]
@@ -238,7 +253,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine {
         _ecx: &mut InterpCx<'mir, 'tcx, Self>,
         _dest: PlaceTy<'tcx>,
     ) -> InterpResult<'tcx> {
-        throw_unsup!(ConstPropUnsupported("can't const prop `box` keyword"))
+        throw_machine_stop_str!("can't const prop heap allocations")
     }
 
     fn access_local(
@@ -249,7 +264,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine {
         let l = &frame.locals[local];
 
         if l.value == LocalValue::Uninitialized {
-            throw_unsup!(ConstPropUnsupported("tried to access an uninitialized local"));
+            throw_machine_stop_str!("tried to access an uninitialized local")
         }
 
         l.access()
@@ -262,7 +277,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine {
         // if the static allocation is mutable or if it has relocations (it may be legal to mutate
         // the memory behind that in the future), then we can't const prop it
         if allocation.mutability == Mutability::Mut || allocation.relocations().len() > 0 {
-            throw_unsup!(ConstPropUnsupported("can't eval mutable statics in ConstProp"));
+            throw_machine_stop_str!("can't eval mutable statics in ConstProp")
         }
 
         Ok(())
diff --git a/src/librustc_mir_build/hair/cx/expr.rs b/src/librustc_mir_build/hair/cx/expr.rs
index 148836e35c7..9f93b817e38 100644
--- a/src/librustc_mir_build/hair/cx/expr.rs
+++ b/src/librustc_mir_build/hair/cx/expr.rs
@@ -3,7 +3,7 @@ use crate::hair::cx::to_ref::ToRef;
 use crate::hair::cx::Cx;
 use crate::hair::util::UserAnnotatedTyHelpers;
 use crate::hair::*;
-use rustc::mir::interpret::{ErrorHandled, Scalar};
+use rustc::mir::interpret::Scalar;
 use rustc::mir::BorrowKind;
 use rustc::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability, PointerCast};
 use rustc::ty::subst::{InternalSubsts, SubstsRef};
@@ -406,34 +406,8 @@ fn make_mirror_unadjusted<'a, 'tcx>(
 
         // Now comes the rote stuff:
         hir::ExprKind::Repeat(ref v, ref count) => {
-            let def_id = cx.tcx.hir().local_def_id(count.hir_id);
-            let substs = InternalSubsts::identity_for_item(cx.tcx, def_id);
-            let span = cx.tcx.def_span(def_id);
-            let count = match cx.tcx.const_eval_resolve(
-                ty::ParamEnv::reveal_all(),
-                def_id,
-                substs,
-                None,
-                Some(span),
-            ) {
-                Ok(cv) => {
-                    if let Some(count) = cv.try_to_bits_for_ty(
-                        cx.tcx,
-                        ty::ParamEnv::reveal_all(),
-                        cx.tcx.types.usize,
-                    ) {
-                        count as u64
-                    } else {
-                        bug!("repeat count constant value can't be converted to usize");
-                    }
-                }
-                Err(ErrorHandled::Reported) => 0,
-                Err(ErrorHandled::TooGeneric) => {
-                    let span = cx.tcx.def_span(def_id);
-                    cx.tcx.sess.span_err(span, "array lengths can't depend on generic parameters");
-                    0
-                }
-            };
+            let count_def_id = cx.tcx.hir().local_def_id(count.hir_id).expect_local();
+            let count = ty::Const::from_anon_const(cx.tcx, count_def_id);
 
             ExprKind::Repeat { value: v.to_ref(), count }
         }
diff --git a/src/librustc_mir_build/hair/mod.rs b/src/librustc_mir_build/hair/mod.rs
index cb93ba7c925..77042240acf 100644
--- a/src/librustc_mir_build/hair/mod.rs
+++ b/src/librustc_mir_build/hair/mod.rs
@@ -229,7 +229,7 @@ crate enum ExprKind<'tcx> {
     },
     Repeat {
         value: ExprRef<'tcx>,
-        count: u64,
+        count: &'tcx Const<'tcx>,
     },
     Array {
         fields: Vec<ExprRef<'tcx>>,
diff --git a/src/librustc_query_system/Cargo.toml b/src/librustc_query_system/Cargo.toml
new file mode 100644
index 00000000000..a01bb5e5ea3
--- /dev/null
+++ b/src/librustc_query_system/Cargo.toml
@@ -0,0 +1,22 @@
+[package]
+authors = ["The Rust Project Developers"]
+name = "rustc_query_system"
+version = "0.0.0"
+edition = "2018"
+
+[lib]
+name = "rustc_query_system"
+path = "lib.rs"
+doctest = false
+
+[dependencies]
+log = { version = "0.4", features = ["release_max_level_info", "std"] }
+rustc_ast = { path = "../librustc_ast" }
+rustc_data_structures = { path = "../librustc_data_structures" }
+rustc_errors = { path = "../librustc_errors" }
+rustc_hir = { path = "../librustc_hir" }
+rustc_index = { path = "../librustc_index" }
+rustc_macros = { path = "../librustc_macros" }
+rustc_serialize = { path = "../libserialize", package = "serialize" }
+parking_lot = "0.9"
+smallvec = { version = "1.0", features = ["union", "may_dangle"] }
diff --git a/src/librustc/dep_graph/README.md b/src/librustc_query_system/dep_graph/README.md
index b9d91cd35a8..b9d91cd35a8 100644
--- a/src/librustc/dep_graph/README.md
+++ b/src/librustc_query_system/dep_graph/README.md
diff --git a/src/librustc/dep_graph/debug.rs b/src/librustc_query_system/dep_graph/debug.rs
index d44c54593a6..718a2f1039a 100644
--- a/src/librustc/dep_graph/debug.rs
+++ b/src/librustc_query_system/dep_graph/debug.rs
@@ -1,6 +1,6 @@
 //! Code for debugging the dep-graph.
 
-use super::dep_node::DepNode;
+use super::{DepKind, DepNode};
 use std::error::Error;
 
 /// A dep-node filter goes from a user-defined string to a query over
@@ -26,7 +26,7 @@ impl DepNodeFilter {
     }
 
     /// Tests whether `node` meets the filter, returning true if so.
-    pub fn test(&self, node: &DepNode) -> bool {
+    pub fn test<K: DepKind>(&self, node: &DepNode<K>) -> bool {
         let debug_str = format!("{:?}", node);
         self.text.split('&').map(|s| s.trim()).all(|f| debug_str.contains(f))
     }
@@ -52,7 +52,7 @@ impl EdgeFilter {
         }
     }
 
-    pub fn test(&self, source: &DepNode, target: &DepNode) -> bool {
+    pub fn test<K: DepKind>(&self, source: &DepNode<K>, target: &DepNode<K>) -> bool {
         self.source.test(source) && self.target.test(target)
     }
 }
diff --git a/src/librustc_query_system/dep_graph/dep_node.rs b/src/librustc_query_system/dep_graph/dep_node.rs
new file mode 100644
index 00000000000..c6fff2f0164
--- /dev/null
+++ b/src/librustc_query_system/dep_graph/dep_node.rs
@@ -0,0 +1,146 @@
+//! This module defines the `DepNode` type which the compiler uses to represent
+//! nodes in the dependency graph. A `DepNode` consists of a `DepKind` (which
+//! specifies the kind of thing it represents, like a piece of HIR, MIR, etc)
+//! and a `Fingerprint`, a 128 bit hash value the exact meaning of which
+//! depends on the node's `DepKind`. Together, the kind and the fingerprint
+//! fully identify a dependency node, even across multiple compilation sessions.
+//! In other words, the value of the fingerprint does not depend on anything
+//! that is specific to a given compilation session, like an unpredictable
+//! interning key (e.g., NodeId, DefId, Symbol) or the numeric value of a
+//! pointer. The concept behind this could be compared to how git commit hashes
+//! uniquely identify a given commit and has a few advantages:
+//!
+//! * A `DepNode` can simply be serialized to disk and loaded in another session
+//!   without the need to do any "rebasing (like we have to do for Spans and
+//!   NodeIds) or "retracing" like we had to do for `DefId` in earlier
+//!   implementations of the dependency graph.
+//! * A `Fingerprint` is just a bunch of bits, which allows `DepNode` to
+//!   implement `Copy`, `Sync`, `Send`, `Freeze`, etc.
+//! * Since we just have a bit pattern, `DepNode` can be mapped from disk into
+//!   memory without any post-processing (e.g., "abomination-style" pointer
+//!   reconstruction).
+//! * Because a `DepNode` is self-contained, we can instantiate `DepNodes` that
+//!   refer to things that do not exist anymore. In previous implementations
+//!   `DepNode` contained a `DefId`. A `DepNode` referring to something that
+//!   had been removed between the previous and the current compilation session
+//!   could not be instantiated because the current compilation session
+//!   contained no `DefId` for thing that had been removed.
+//!
+//! `DepNode` definition happens in `librustc` with the `define_dep_nodes!()` macro.
+//! This macro defines the `DepKind` enum and a corresponding `DepConstructor` enum. The
+//! `DepConstructor` enum links a `DepKind` to the parameters that are needed at runtime in order
+//! to construct a valid `DepNode` fingerprint.
+//!
+//! Because the macro sees what parameters a given `DepKind` requires, it can
+//! "infer" some properties for each kind of `DepNode`:
+//!
+//! * Whether a `DepNode` of a given kind has any parameters at all. Some
+//!   `DepNode`s could represent global concepts with only one value.
+//! * Whether it is possible, in principle, to reconstruct a query key from a
+//!   given `DepNode`. Many `DepKind`s only require a single `DefId` parameter,
+//!   in which case it is possible to map the node's fingerprint back to the
+//!   `DefId` it was computed from. In other cases, too much information gets
+//!   lost during fingerprint computation.
+
+use super::{DepContext, DepKind};
+
+use rustc_data_structures::fingerprint::Fingerprint;
+use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
+use rustc_macros::HashStable_Generic;
+
+use std::fmt;
+use std::hash::Hash;
+
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)]
+pub struct DepNode<K> {
+    pub kind: K,
+    pub hash: Fingerprint,
+}
+
+impl<K: DepKind> DepNode<K> {
+    /// Creates a new, parameterless DepNode. This method will assert
+    /// that the DepNode corresponding to the given DepKind actually
+    /// does not require any parameters.
+    pub fn new_no_params(kind: K) -> DepNode<K> {
+        debug_assert!(!kind.has_params());
+        DepNode { kind, hash: Fingerprint::ZERO }
+    }
+}
+
+impl<K: DepKind> fmt::Debug for DepNode<K> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        K::debug_node(self, f)
+    }
+}
+
+pub trait DepNodeParams<Ctxt: DepContext>: fmt::Debug + Sized {
+    const CAN_RECONSTRUCT_QUERY_KEY: bool;
+
+    /// This method turns the parameters of a DepNodeConstructor into an opaque
+    /// Fingerprint to be used in DepNode.
+    /// Not all DepNodeParams support being turned into a Fingerprint (they
+    /// don't need to if the corresponding DepNode is anonymous).
+    fn to_fingerprint(&self, _: Ctxt) -> Fingerprint {
+        panic!("Not implemented. Accidentally called on anonymous node?")
+    }
+
+    fn to_debug_str(&self, _: Ctxt) -> String {
+        format!("{:?}", self)
+    }
+
+    /// This method tries to recover the query key from the given `DepNode`,
+    /// something which is needed when forcing `DepNode`s during red-green
+    /// evaluation. The query system will only call this method if
+    /// `CAN_RECONSTRUCT_QUERY_KEY` is `true`.
+    /// It is always valid to return `None` here, in which case incremental
+    /// compilation will treat the query as having changed instead of forcing it.
+    fn recover(tcx: Ctxt, dep_node: &DepNode<Ctxt::DepKind>) -> Option<Self>;
+}
+
+impl<Ctxt: DepContext, T> DepNodeParams<Ctxt> for T
+where
+    T: HashStable<Ctxt::StableHashingContext> + fmt::Debug,
+{
+    default const CAN_RECONSTRUCT_QUERY_KEY: bool = false;
+
+    default fn to_fingerprint(&self, tcx: Ctxt) -> Fingerprint {
+        let mut hcx = tcx.create_stable_hashing_context();
+        let mut hasher = StableHasher::new();
+
+        self.hash_stable(&mut hcx, &mut hasher);
+
+        hasher.finish()
+    }
+
+    default fn to_debug_str(&self, _: Ctxt) -> String {
+        format!("{:?}", *self)
+    }
+
+    default fn recover(_: Ctxt, _: &DepNode<Ctxt::DepKind>) -> Option<Self> {
+        None
+    }
+}
+
+/// A "work product" corresponds to a `.o` (or other) file that we
+/// save in between runs. These IDs do not have a `DefId` but rather
+/// some independent path or string that persists between runs without
+/// 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)]
+#[derive(HashStable_Generic)]
+pub struct WorkProductId {
+    hash: Fingerprint,
+}
+
+impl WorkProductId {
+    pub fn from_cgu_name(cgu_name: &str) -> WorkProductId {
+        let mut hasher = StableHasher::new();
+        cgu_name.len().hash(&mut hasher);
+        cgu_name.hash(&mut hasher);
+        WorkProductId { hash: hasher.finish() }
+    }
+
+    pub fn from_fingerprint(fingerprint: Fingerprint) -> WorkProductId {
+        WorkProductId { hash: fingerprint }
+    }
+}
diff --git a/src/librustc/dep_graph/graph.rs b/src/librustc_query_system/dep_graph/graph.rs
index 36edf0f0fc2..7352551559c 100644
--- a/src/librustc/dep_graph/graph.rs
+++ b/src/librustc_query_system/dep_graph/graph.rs
@@ -1,32 +1,33 @@
-use crate::ty::{self, TyCtxt};
-use parking_lot::{Condvar, Mutex};
+use rustc_data_structures::fingerprint::Fingerprint;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_data_structures::profiling::QueryInvocationId;
 use rustc_data_structures::sharded::{self, Sharded};
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_data_structures::sync::{AtomicU32, AtomicU64, Lock, Lrc, Ordering};
+use rustc_data_structures::unlikely;
 use rustc_errors::Diagnostic;
-use rustc_hir::def_id::DefId;
 use rustc_index::vec::{Idx, IndexVec};
-use smallvec::SmallVec;
+
+use parking_lot::{Condvar, Mutex};
+use smallvec::{smallvec, SmallVec};
 use std::collections::hash_map::Entry;
 use std::env;
 use std::hash::Hash;
+use std::marker::PhantomData;
 use std::mem;
 use std::sync::atomic::Ordering::Relaxed;
 
-use crate::ich::{Fingerprint, StableHashingContext, StableHashingContextProvider};
-
 use super::debug::EdgeFilter;
-use super::dep_node::{DepKind, DepNode, WorkProductId};
 use super::prev::PreviousDepGraph;
 use super::query::DepGraphQuery;
 use super::safe::DepGraphSafe;
 use super::serialized::{SerializedDepGraph, SerializedDepNodeIndex};
+use super::{DepContext, DepKind, DepNode, WorkProductId};
+use crate::{HashStableContext, HashStableContextProvider};
 
 #[derive(Clone)]
-pub struct DepGraph {
-    data: Option<Lrc<DepGraphData>>,
+pub struct DepGraph<K: DepKind> {
+    data: Option<Lrc<DepGraphData<K>>>,
 
     /// This field is used for assigning DepNodeIndices when running in
     /// non-incremental mode. Even in non-incremental mode we make sure that
@@ -65,16 +66,16 @@ impl DepNodeColor {
     }
 }
 
-struct DepGraphData {
+struct DepGraphData<K: DepKind> {
     /// The new encoding of the dependency graph, optimized for red/green
     /// tracking. The `current` field is the dependency graph of only the
     /// current compilation session: We don't merge the previous dep-graph into
     /// current one anymore.
-    current: CurrentDepGraph,
+    current: CurrentDepGraph<K>,
 
     /// The dep-graph from the previous compilation session. It contains all
     /// nodes and edges as well as all fingerprints of nodes that have them.
-    previous: PreviousDepGraph,
+    previous: PreviousDepGraph<K>,
 
     colors: DepNodeColorMap,
 
@@ -90,12 +91,12 @@ struct DepGraphData {
     /// this map. We can later look for and extract that data.
     previous_work_products: FxHashMap<WorkProductId, WorkProduct>,
 
-    dep_node_debug: Lock<FxHashMap<DepNode, String>>,
+    dep_node_debug: Lock<FxHashMap<DepNode<K>, String>>,
 }
 
-pub fn hash_result<R>(hcx: &mut StableHashingContext<'_>, result: &R) -> Option<Fingerprint>
+pub fn hash_result<HashCtxt, R>(hcx: &mut HashCtxt, result: &R) -> Option<Fingerprint>
 where
-    R: for<'a> HashStable<StableHashingContext<'a>>,
+    R: HashStable<HashCtxt>,
 {
     let mut stable_hasher = StableHasher::new();
     result.hash_stable(hcx, &mut stable_hasher);
@@ -103,11 +104,11 @@ where
     Some(stable_hasher.finish())
 }
 
-impl DepGraph {
+impl<K: DepKind> DepGraph<K> {
     pub fn new(
-        prev_graph: PreviousDepGraph,
+        prev_graph: PreviousDepGraph<K>,
         prev_work_products: FxHashMap<WorkProductId, WorkProduct>,
-    ) -> DepGraph {
+    ) -> DepGraph<K> {
         let prev_graph_node_count = prev_graph.node_count();
 
         DepGraph {
@@ -124,7 +125,7 @@ impl DepGraph {
         }
     }
 
-    pub fn new_disabled() -> DepGraph {
+    pub fn new_disabled() -> DepGraph<K> {
         DepGraph { data: None, virtual_dep_node_index: Lrc::new(AtomicU32::new(0)) }
     }
 
@@ -134,7 +135,7 @@ impl DepGraph {
         self.data.is_some()
     }
 
-    pub fn query(&self) -> DepGraphQuery {
+    pub fn query(&self) -> DepGraphQuery<K> {
         let data = self.data.as_ref().unwrap().current.data.lock();
         let nodes: Vec<_> = data.iter().map(|n| n.node).collect();
         let mut edges = Vec::new();
@@ -150,9 +151,8 @@ impl DepGraph {
 
     pub fn assert_ignored(&self) {
         if let Some(..) = self.data {
-            ty::tls::with_context_opt(|icx| {
-                let icx = if let Some(icx) = icx { icx } else { return };
-                assert!(icx.task_deps.is_none(), "expected no task dependency tracking");
+            K::read_deps(|task_deps| {
+                assert!(task_deps.is_none(), "expected no task dependency tracking");
             })
         }
     }
@@ -161,11 +161,7 @@ impl DepGraph {
     where
         OP: FnOnce() -> R,
     {
-        ty::tls::with_context(|icx| {
-            let icx = ty::tls::ImplicitCtxt { task_deps: None, ..icx.clone() };
-
-            ty::tls::enter_context(&icx, |_| op())
-        })
+        K::with_deps(None, op)
     }
 
     /// Starts a new dep-graph task. Dep-graph tasks are specified
@@ -195,16 +191,17 @@ impl DepGraph {
     ///   `arg` parameter.
     ///
     /// [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/incremental-compilation.html
-    pub fn with_task<'a, C, A, R>(
+    pub fn with_task<H, C, A, R>(
         &self,
-        key: DepNode,
+        key: DepNode<K>,
         cx: C,
         arg: A,
         task: fn(C, A) -> R,
-        hash_result: impl FnOnce(&mut StableHashingContext<'_>, &R) -> Option<Fingerprint>,
+        hash_result: impl FnOnce(&mut H, &R) -> Option<Fingerprint>,
     ) -> (R, DepNodeIndex)
     where
-        C: DepGraphSafe + StableHashingContextProvider<'a>,
+        C: DepGraphSafe + HashStableContextProvider<H>,
+        H: HashStableContext,
     {
         self.with_task_impl(
             key,
@@ -218,6 +215,7 @@ impl DepGraph {
                     node: Some(_key),
                     reads: SmallVec::new(),
                     read_set: Default::default(),
+                    phantom_data: PhantomData,
                 })
             },
             |data, key, fingerprint, task| data.complete_task(key, task.unwrap(), fingerprint),
@@ -225,24 +223,25 @@ impl DepGraph {
         )
     }
 
-    fn with_task_impl<'a, C, A, R>(
+    fn with_task_impl<H, C, A, R>(
         &self,
-        key: DepNode,
+        key: DepNode<K>,
         cx: C,
         arg: A,
         no_tcx: bool,
         task: fn(C, A) -> R,
-        create_task: fn(DepNode) -> Option<TaskDeps>,
+        create_task: fn(DepNode<K>) -> Option<TaskDeps<K>>,
         finish_task_and_alloc_depnode: fn(
-            &CurrentDepGraph,
-            DepNode,
+            &CurrentDepGraph<K>,
+            DepNode<K>,
             Fingerprint,
-            Option<TaskDeps>,
+            Option<TaskDeps<K>>,
         ) -> DepNodeIndex,
-        hash_result: impl FnOnce(&mut StableHashingContext<'_>, &R) -> Option<Fingerprint>,
+        hash_result: impl FnOnce(&mut H, &R) -> Option<Fingerprint>,
     ) -> (R, DepNodeIndex)
     where
-        C: DepGraphSafe + StableHashingContextProvider<'a>,
+        C: DepGraphSafe + HashStableContextProvider<H>,
+        H: HashStableContext,
     {
         if let Some(ref data) = self.data {
             let task_deps = create_task(key).map(Lock::new);
@@ -257,12 +256,7 @@ impl DepGraph {
             let result = if no_tcx {
                 task(cx, arg)
             } else {
-                ty::tls::with_context(|icx| {
-                    let icx =
-                        ty::tls::ImplicitCtxt { task_deps: task_deps.as_ref(), ..icx.clone() };
-
-                    ty::tls::enter_context(&icx, |_| task(cx, arg))
-                })
+                K::with_deps(task_deps.as_ref(), || task(cx, arg))
             };
 
             let current_fingerprint = hash_result(&mut hcx, &result);
@@ -274,7 +268,7 @@ impl DepGraph {
                 task_deps.map(|lock| lock.into_inner()),
             );
 
-            let print_status = cfg!(debug_assertions) && hcx.sess().opts.debugging_opts.dep_tasks;
+            let print_status = cfg!(debug_assertions) && hcx.debug_dep_tasks();
 
             // Determine the color of the new DepNode.
             if let Some(prev_index) = data.previous.node_to_index_opt(&key) {
@@ -322,22 +316,16 @@ impl DepGraph {
 
     /// Executes something within an "anonymous" task, that is, a task the
     /// `DepNode` of which is determined by the list of inputs it read from.
-    pub fn with_anon_task<OP, R>(&self, dep_kind: DepKind, op: OP) -> (R, DepNodeIndex)
+    pub fn with_anon_task<OP, R>(&self, dep_kind: K, op: OP) -> (R, DepNodeIndex)
     where
         OP: FnOnce() -> R,
     {
         if let Some(ref data) = self.data {
-            let (result, task_deps) = ty::tls::with_context(|icx| {
-                let task_deps = Lock::new(TaskDeps::default());
-
-                let r = {
-                    let icx = ty::tls::ImplicitCtxt { task_deps: Some(&task_deps), ..icx.clone() };
+            let task_deps = Lock::new(TaskDeps::default());
 
-                    ty::tls::enter_context(&icx, |_| op())
-                };
+            let result = K::with_deps(Some(&task_deps), op);
+            let task_deps = task_deps.into_inner();
 
-                (r, task_deps.into_inner())
-            });
             let dep_node_index = data.current.complete_anon_task(dep_kind, task_deps);
             (result, dep_node_index)
         } else {
@@ -347,16 +335,17 @@ impl DepGraph {
 
     /// Executes something within an "eval-always" task which is a task
     /// that runs whenever anything changes.
-    pub fn with_eval_always_task<'a, C, A, R>(
+    pub fn with_eval_always_task<H, C, A, R>(
         &self,
-        key: DepNode,
+        key: DepNode<K>,
         cx: C,
         arg: A,
         task: fn(C, A) -> R,
-        hash_result: impl FnOnce(&mut StableHashingContext<'_>, &R) -> Option<Fingerprint>,
+        hash_result: impl FnOnce(&mut H, &R) -> Option<Fingerprint>,
     ) -> (R, DepNodeIndex)
     where
-        C: DepGraphSafe + StableHashingContextProvider<'a>,
+        C: DepGraphSafe + HashStableContextProvider<H>,
+        H: HashStableContext,
     {
         self.with_task_impl(
             key,
@@ -371,14 +360,14 @@ impl DepGraph {
     }
 
     #[inline]
-    pub fn read(&self, v: DepNode) {
+    pub fn read(&self, v: DepNode<K>) {
         if let Some(ref data) = self.data {
             let map = data.current.node_to_node_index.get_shard_by_value(&v).lock();
             if let Some(dep_node_index) = map.get(&v).copied() {
                 std::mem::drop(map);
                 data.read_index(dep_node_index);
             } else {
-                bug!("DepKind {:?} should be pre-allocated but isn't.", v.kind)
+                panic!("DepKind {:?} should be pre-allocated but isn't.", v.kind)
             }
         }
     }
@@ -391,7 +380,7 @@ impl DepGraph {
     }
 
     #[inline]
-    pub fn dep_node_index_of(&self, dep_node: &DepNode) -> DepNodeIndex {
+    pub fn dep_node_index_of(&self, dep_node: &DepNode<K>) -> DepNodeIndex {
         self.data
             .as_ref()
             .unwrap()
@@ -405,7 +394,7 @@ impl DepGraph {
     }
 
     #[inline]
-    pub fn dep_node_exists(&self, dep_node: &DepNode) -> bool {
+    pub fn dep_node_exists(&self, dep_node: &DepNode<K>) -> bool {
         if let Some(ref data) = self.data {
             data.current
                 .node_to_node_index
@@ -423,12 +412,12 @@ impl DepGraph {
         data[dep_node_index].fingerprint
     }
 
-    pub fn prev_fingerprint_of(&self, dep_node: &DepNode) -> Option<Fingerprint> {
+    pub fn prev_fingerprint_of(&self, dep_node: &DepNode<K>) -> Option<Fingerprint> {
         self.data.as_ref().unwrap().previous.fingerprint_of(dep_node)
     }
 
     #[inline]
-    pub fn prev_dep_node_index_of(&self, dep_node: &DepNode) -> SerializedDepNodeIndex {
+    pub fn prev_dep_node_index_of(&self, dep_node: &DepNode<K>) -> SerializedDepNodeIndex {
         self.data.as_ref().unwrap().previous.node_to_index(dep_node)
     }
 
@@ -445,7 +434,7 @@ impl DepGraph {
     }
 
     #[inline(always)]
-    pub fn register_dep_node_debug_str<F>(&self, dep_node: DepNode, debug_str_gen: F)
+    pub fn register_dep_node_debug_str<F>(&self, dep_node: DepNode<K>, debug_str_gen: F)
     where
         F: FnOnce() -> String,
     {
@@ -458,7 +447,7 @@ impl DepGraph {
         dep_node_debug.borrow_mut().insert(dep_node, debug_str);
     }
 
-    pub(super) fn dep_node_debug_str(&self, dep_node: DepNode) -> Option<String> {
+    pub fn dep_node_debug_str(&self, dep_node: DepNode<K>) -> Option<String> {
         self.data.as_ref()?.dep_node_debug.borrow().get(&dep_node).cloned()
     }
 
@@ -475,7 +464,7 @@ impl DepGraph {
         }
     }
 
-    pub fn serialize(&self) -> SerializedDepGraph {
+    pub fn serialize(&self) -> SerializedDepGraph<K> {
         let data = self.data.as_ref().unwrap().current.data.lock();
 
         let fingerprints: IndexVec<SerializedDepNodeIndex, _> =
@@ -503,7 +492,7 @@ impl DepGraph {
         SerializedDepGraph { nodes, fingerprints, edge_list_indices, edge_list_data }
     }
 
-    pub fn node_color(&self, dep_node: &DepNode) -> Option<DepNodeColor> {
+    pub fn node_color(&self, dep_node: &DepNode<K>) -> Option<DepNodeColor> {
         if let Some(ref data) = self.data {
             if let Some(prev_index) = data.previous.node_to_index_opt(dep_node) {
                 return data.colors.get(prev_index);
@@ -521,10 +510,10 @@ impl DepGraph {
     /// A node will have an index, when it's already been marked green, or when we can mark it
     /// green. This function will mark the current task as a reader of the specified node, when
     /// a node index can be found for that node.
-    pub fn try_mark_green_and_read(
+    pub fn try_mark_green_and_read<Ctxt: DepContext<DepKind = K>>(
         &self,
-        tcx: TyCtxt<'_>,
-        dep_node: &DepNode,
+        tcx: Ctxt,
+        dep_node: &DepNode<K>,
     ) -> Option<(SerializedDepNodeIndex, DepNodeIndex)> {
         self.try_mark_green(tcx, dep_node).map(|(prev_index, dep_node_index)| {
             debug_assert!(self.is_green(&dep_node));
@@ -533,10 +522,10 @@ impl DepGraph {
         })
     }
 
-    pub fn try_mark_green(
+    pub fn try_mark_green<Ctxt: DepContext<DepKind = K>>(
         &self,
-        tcx: TyCtxt<'_>,
-        dep_node: &DepNode,
+        tcx: Ctxt,
+        dep_node: &DepNode<K>,
     ) -> Option<(SerializedDepNodeIndex, DepNodeIndex)> {
         debug_assert!(!dep_node.kind.is_eval_always());
 
@@ -561,12 +550,12 @@ impl DepGraph {
     }
 
     /// Try to mark a dep-node which existed in the previous compilation session as green.
-    fn try_mark_previous_green<'tcx>(
+    fn try_mark_previous_green<Ctxt: DepContext<DepKind = K>>(
         &self,
-        tcx: TyCtxt<'tcx>,
-        data: &DepGraphData,
+        tcx: Ctxt,
+        data: &DepGraphData<K>,
         prev_dep_node_index: SerializedDepNodeIndex,
-        dep_node: &DepNode,
+        dep_node: &DepNode<K>,
     ) -> Option<DepNodeIndex> {
         debug!("try_mark_previous_green({:?}) - BEGIN", dep_node);
 
@@ -648,50 +637,6 @@ impl DepGraph {
                             current_deps.push(node_index);
                             continue;
                         }
-                    } else {
-                        // FIXME: This match is just a workaround for incremental bugs and should
-                        // be removed. https://github.com/rust-lang/rust/issues/62649 is one such
-                        // bug that must be fixed before removing this.
-                        match dep_dep_node.kind {
-                            DepKind::hir_owner
-                            | DepKind::hir_owner_nodes
-                            | DepKind::CrateMetadata => {
-                                if let Some(def_id) = dep_dep_node.extract_def_id(tcx) {
-                                    if def_id_corresponds_to_hir_dep_node(tcx, def_id) {
-                                        if dep_dep_node.kind == DepKind::CrateMetadata {
-                                            // The `DefPath` has corresponding node,
-                                            // and that node should have been marked
-                                            // either red or green in `data.colors`.
-                                            bug!(
-                                                "DepNode {:?} should have been \
-                                             pre-marked as red or green but wasn't.",
-                                                dep_dep_node
-                                            );
-                                        }
-                                    } else {
-                                        // This `DefPath` does not have a
-                                        // corresponding `DepNode` (e.g. a
-                                        // struct field), and the ` DefPath`
-                                        // collided with the `DefPath` of a
-                                        // proper item that existed in the
-                                        // previous compilation session.
-                                        //
-                                        // Since the given `DefPath` does not
-                                        // denote the item that previously
-                                        // existed, we just fail to mark green.
-                                        return None;
-                                    }
-                                } else {
-                                    // If the node does not exist anymore, we
-                                    // just fail to mark green.
-                                    return None;
-                                }
-                            }
-                            _ => {
-                                // For other kinds of nodes it's OK to be
-                                // forced.
-                            }
-                        }
                     }
 
                     // We failed to mark it green, so we try to force the query.
@@ -700,7 +645,7 @@ impl DepGraph {
                             dependency {:?}",
                         dep_node, dep_dep_node
                     );
-                    if crate::ty::query::force_from_dep_node(tcx, dep_dep_node) {
+                    if tcx.try_force_from_dep_node(dep_dep_node) {
                         let dep_dep_node_color = data.colors.get(dep_dep_node_index);
 
                         match dep_dep_node_color {
@@ -721,8 +666,8 @@ impl DepGraph {
                                 return None;
                             }
                             None => {
-                                if !tcx.sess.has_errors_or_delayed_span_bugs() {
-                                    bug!(
+                                if !tcx.has_errors_or_delayed_span_bugs() {
+                                    panic!(
                                         "try_mark_previous_green() - Forcing the DepNode \
                                           should have set its color"
                                     )
@@ -779,7 +724,7 @@ impl DepGraph {
 
         // FIXME: Store the fact that a node has diagnostics in a bit in the dep graph somewhere
         // Maybe store a list on disk and encode this fact in the DepNodeState
-        let diagnostics = tcx.queries.on_disk_cache.load_diagnostics(tcx, prev_dep_node_index);
+        let diagnostics = tcx.load_diagnostics(prev_dep_node_index);
 
         #[cfg(not(parallel_compiler))]
         debug_assert!(
@@ -805,10 +750,10 @@ impl DepGraph {
     /// This may be called concurrently on multiple threads for the same dep node.
     #[cold]
     #[inline(never)]
-    fn emit_diagnostics<'tcx>(
+    fn emit_diagnostics<Ctxt: DepContext<DepKind = K>>(
         &self,
-        tcx: TyCtxt<'tcx>,
-        data: &DepGraphData,
+        tcx: Ctxt,
+        data: &DepGraphData<K>,
         dep_node_index: DepNodeIndex,
         prev_dep_node_index: SerializedDepNodeIndex,
         diagnostics: Vec<Diagnostic>,
@@ -827,9 +772,9 @@ impl DepGraph {
             mem::drop(emitting);
 
             // Promote the previous diagnostics to the current session.
-            tcx.queries.on_disk_cache.store_diagnostics(dep_node_index, diagnostics.clone().into());
+            tcx.store_diagnostics(dep_node_index, diagnostics.clone().into());
 
-            let handle = tcx.sess.diagnostic();
+            let handle = tcx.diagnostic();
 
             for diagnostic in diagnostics {
                 handle.emit_diagnostic(&diagnostic);
@@ -858,7 +803,7 @@ impl DepGraph {
 
     // Returns true if the given node has been marked as green during the
     // current compilation session. Used in various assertions
-    pub fn is_green(&self, dep_node: &DepNode) -> bool {
+    pub fn is_green(&self, dep_node: &DepNode<K>) -> bool {
         self.node_color(dep_node).map(|c| c.is_green()).unwrap_or(false)
     }
 
@@ -870,15 +815,15 @@ impl DepGraph {
     //
     // This method will only load queries that will end up in the disk cache.
     // Other queries will not be executed.
-    pub fn exec_cache_promotions(&self, tcx: TyCtxt<'_>) {
-        let _prof_timer = tcx.prof.generic_activity("incr_comp_query_cache_promotion");
+    pub fn exec_cache_promotions<Ctxt: DepContext<DepKind = K>>(&self, tcx: Ctxt) {
+        let _prof_timer = tcx.profiler().generic_activity("incr_comp_query_cache_promotion");
 
         let data = self.data.as_ref().unwrap();
         for prev_index in data.colors.values.indices() {
             match data.colors.get(prev_index) {
                 Some(DepNodeColor::Green(_)) => {
                     let dep_node = data.previous.index_to_node(prev_index);
-                    dep_node.try_load_from_on_disk_cache(tcx);
+                    tcx.try_load_from_on_disk_cache(&dep_node);
                 }
                 None | Some(DepNodeColor::Red) => {
                     // We can skip red nodes because a node can only be marked
@@ -895,11 +840,6 @@ impl DepGraph {
     }
 }
 
-fn def_id_corresponds_to_hir_dep_node(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
-    let hir_id = tcx.hir().as_local_hir_id(def_id).unwrap();
-    def_id.index == hir_id.owner.local_def_index
-}
-
 /// A "work product" is an intermediate result that we save into the
 /// incremental directory for later re-use. The primary example are
 /// the object files that we save for each partition at code
@@ -946,8 +886,8 @@ pub enum WorkProductFileKind {
 }
 
 #[derive(Clone)]
-struct DepNodeData {
-    node: DepNode,
+struct DepNodeData<K> {
+    node: DepNode<K>,
     edges: EdgesVec,
     fingerprint: Fingerprint,
 }
@@ -967,9 +907,9 @@ struct DepNodeData {
 /// The only operation that must manipulate both locks is adding new nodes, in which case
 /// we first acquire the `node_to_node_index` lock and then, once a new node is to be inserted,
 /// acquire the lock on `data.`
-pub(super) struct CurrentDepGraph {
-    data: Lock<IndexVec<DepNodeIndex, DepNodeData>>,
-    node_to_node_index: Sharded<FxHashMap<DepNode, DepNodeIndex>>,
+pub(super) struct CurrentDepGraph<K> {
+    data: Lock<IndexVec<DepNodeIndex, DepNodeData<K>>>,
+    node_to_node_index: Sharded<FxHashMap<DepNode<K>, DepNodeIndex>>,
 
     /// Used to trap when a specific edge is added to the graph.
     /// This is used for debug purposes and is only active with `debug_assertions`.
@@ -995,8 +935,8 @@ pub(super) struct CurrentDepGraph {
     total_duplicate_read_count: AtomicU64,
 }
 
-impl CurrentDepGraph {
-    fn new(prev_graph_node_count: usize) -> CurrentDepGraph {
+impl<K: DepKind> CurrentDepGraph<K> {
+    fn new(prev_graph_node_count: usize) -> CurrentDepGraph<K> {
         use std::time::{SystemTime, UNIX_EPOCH};
 
         let duration = SystemTime::now().duration_since(UNIX_EPOCH).unwrap();
@@ -1008,7 +948,7 @@ impl CurrentDepGraph {
             match env::var("RUST_FORBID_DEP_GRAPH_EDGE") {
                 Ok(s) => match EdgeFilter::new(&s) {
                     Ok(f) => Some(f),
-                    Err(err) => bug!("RUST_FORBID_DEP_GRAPH_EDGE invalid: {}", err),
+                    Err(err) => panic!("RUST_FORBID_DEP_GRAPH_EDGE invalid: {}", err),
                 },
                 Err(_) => None,
             }
@@ -1039,14 +979,14 @@ impl CurrentDepGraph {
 
     fn complete_task(
         &self,
-        node: DepNode,
-        task_deps: TaskDeps,
+        node: DepNode<K>,
+        task_deps: TaskDeps<K>,
         fingerprint: Fingerprint,
     ) -> DepNodeIndex {
         self.alloc_node(node, task_deps.reads, fingerprint)
     }
 
-    fn complete_anon_task(&self, kind: DepKind, task_deps: TaskDeps) -> DepNodeIndex {
+    fn complete_anon_task(&self, kind: K, task_deps: TaskDeps<K>) -> DepNodeIndex {
         debug_assert!(!kind.is_eval_always());
 
         let mut hasher = StableHasher::new();
@@ -1072,7 +1012,7 @@ impl CurrentDepGraph {
 
     fn alloc_node(
         &self,
-        dep_node: DepNode,
+        dep_node: DepNode<K>,
         edges: EdgesVec,
         fingerprint: Fingerprint,
     ) -> DepNodeIndex {
@@ -1084,7 +1024,7 @@ impl CurrentDepGraph {
 
     fn intern_node(
         &self,
-        dep_node: DepNode,
+        dep_node: DepNode<K>,
         edges: EdgesVec,
         fingerprint: Fingerprint,
     ) -> DepNodeIndex {
@@ -1101,12 +1041,11 @@ impl CurrentDepGraph {
     }
 }
 
-impl DepGraphData {
+impl<K: DepKind> DepGraphData<K> {
     #[inline(never)]
     fn read_index(&self, source: DepNodeIndex) {
-        ty::tls::with_context_opt(|icx| {
-            let icx = if let Some(icx) = icx { icx } else { return };
-            if let Some(task_deps) = icx.task_deps {
+        K::read_deps(|task_deps| {
+            if let Some(task_deps) = task_deps {
                 let mut task_deps = task_deps.lock();
                 let task_deps = &mut *task_deps;
                 if cfg!(debug_assertions) {
@@ -1135,7 +1074,7 @@ impl DepGraphData {
                             if let Some(ref forbidden_edge) = self.current.forbidden_edge {
                                 let source = data[source].node;
                                 if forbidden_edge.test(&source, &target) {
-                                    bug!("forbidden edge {:?} -> {:?} created", source, target)
+                                    panic!("forbidden edge {:?} -> {:?} created", source, target)
                                 }
                             }
                         }
@@ -1151,12 +1090,25 @@ impl DepGraphData {
 /// The capacity of the `reads` field `SmallVec`
 const TASK_DEPS_READS_CAP: usize = 8;
 type EdgesVec = SmallVec<[DepNodeIndex; TASK_DEPS_READS_CAP]>;
-#[derive(Default)]
-pub struct TaskDeps {
+
+pub struct TaskDeps<K> {
     #[cfg(debug_assertions)]
-    node: Option<DepNode>,
+    node: Option<DepNode<K>>,
     reads: EdgesVec,
     read_set: FxHashSet<DepNodeIndex>,
+    phantom_data: PhantomData<DepNode<K>>,
+}
+
+impl<K> Default for TaskDeps<K> {
+    fn default() -> Self {
+        Self {
+            #[cfg(debug_assertions)]
+            node: None,
+            reads: EdgesVec::new(),
+            read_set: FxHashSet::default(),
+            phantom_data: PhantomData,
+        }
+    }
 }
 
 // A data structure that stores Option<DepNodeColor> values as a contiguous
diff --git a/src/librustc_query_system/dep_graph/mod.rs b/src/librustc_query_system/dep_graph/mod.rs
new file mode 100644
index 00000000000..825b341cd14
--- /dev/null
+++ b/src/librustc_query_system/dep_graph/mod.rs
@@ -0,0 +1,75 @@
+pub mod debug;
+mod dep_node;
+mod graph;
+mod prev;
+mod query;
+mod safe;
+mod serialized;
+
+pub use dep_node::{DepNode, DepNodeParams, WorkProductId};
+pub use graph::WorkProductFileKind;
+pub use graph::{hash_result, DepGraph, DepNodeColor, DepNodeIndex, TaskDeps, WorkProduct};
+pub use prev::PreviousDepGraph;
+pub use query::DepGraphQuery;
+pub use safe::AssertDepGraphSafe;
+pub use safe::DepGraphSafe;
+pub use serialized::{SerializedDepGraph, SerializedDepNodeIndex};
+
+use rustc_data_structures::profiling::SelfProfilerRef;
+use rustc_data_structures::sync::Lock;
+use rustc_data_structures::thin_vec::ThinVec;
+use rustc_errors::Diagnostic;
+
+use std::fmt;
+use std::hash::Hash;
+
+pub trait DepContext: Copy {
+    type DepKind: self::DepKind;
+    type StableHashingContext: crate::HashStableContext;
+
+    /// Create a hashing context for hashing new results.
+    fn create_stable_hashing_context(&self) -> Self::StableHashingContext;
+
+    /// Try to force a dep node to execute and see if it's green.
+    fn try_force_from_dep_node(&self, dep_node: &DepNode<Self::DepKind>) -> bool;
+
+    /// Return whether the current session is tainted by errors.
+    fn has_errors_or_delayed_span_bugs(&self) -> bool;
+
+    /// Return the diagnostic handler.
+    fn diagnostic(&self) -> &rustc_errors::Handler;
+
+    /// Load data from the on-disk cache.
+    fn try_load_from_on_disk_cache(&self, dep_node: &DepNode<Self::DepKind>);
+
+    /// Load diagnostics associated to the node in the previous session.
+    fn load_diagnostics(&self, prev_dep_node_index: SerializedDepNodeIndex) -> Vec<Diagnostic>;
+
+    /// Register diagnostics for the given node, for use in next session.
+    fn store_diagnostics(&self, dep_node_index: DepNodeIndex, diagnostics: ThinVec<Diagnostic>);
+
+    /// Access the profiler.
+    fn profiler(&self) -> &SelfProfilerRef;
+}
+
+/// Describe the different families of dependency nodes.
+pub trait DepKind: Copy + fmt::Debug + Eq + Ord + Hash {
+    /// Return whether this kind always require evaluation.
+    fn is_eval_always(&self) -> bool;
+
+    /// Return whether this kind requires additional parameters to be executed.
+    fn has_params(&self) -> bool;
+
+    /// Implementation of `std::fmt::Debug` for `DepNode`.
+    fn debug_node(node: &DepNode<Self>, f: &mut fmt::Formatter<'_>) -> fmt::Result;
+
+    /// Execute the operation with provided dependencies.
+    fn with_deps<OP, R>(deps: Option<&Lock<TaskDeps<Self>>>, op: OP) -> R
+    where
+        OP: FnOnce() -> R;
+
+    /// Access dependencies from current implicit context.
+    fn read_deps<OP>(op: OP) -> ()
+    where
+        OP: for<'a> FnOnce(Option<&'a Lock<TaskDeps<Self>>>) -> ();
+}
diff --git a/src/librustc/dep_graph/prev.rs b/src/librustc_query_system/dep_graph/prev.rs
index fbc8f7bc997..5cba64cac4b 100644
--- a/src/librustc/dep_graph/prev.rs
+++ b/src/librustc_query_system/dep_graph/prev.rs
@@ -1,16 +1,22 @@
-use super::dep_node::DepNode;
 use super::serialized::{SerializedDepGraph, SerializedDepNodeIndex};
-use crate::ich::Fingerprint;
+use super::{DepKind, DepNode};
+use rustc_data_structures::fingerprint::Fingerprint;
 use rustc_data_structures::fx::FxHashMap;
 
-#[derive(Debug, RustcEncodable, RustcDecodable, Default)]
-pub struct PreviousDepGraph {
-    data: SerializedDepGraph,
-    index: FxHashMap<DepNode, SerializedDepNodeIndex>,
+#[derive(Debug, RustcEncodable, RustcDecodable)]
+pub struct PreviousDepGraph<K: DepKind> {
+    data: SerializedDepGraph<K>,
+    index: FxHashMap<DepNode<K>, SerializedDepNodeIndex>,
 }
 
-impl PreviousDepGraph {
-    pub fn new(data: SerializedDepGraph) -> PreviousDepGraph {
+impl<K: DepKind> Default for PreviousDepGraph<K> {
+    fn default() -> Self {
+        PreviousDepGraph { data: Default::default(), index: Default::default() }
+    }
+}
+
+impl<K: DepKind> PreviousDepGraph<K> {
+    pub fn new(data: SerializedDepGraph<K>) -> PreviousDepGraph<K> {
         let index: FxHashMap<_, _> =
             data.nodes.iter_enumerated().map(|(idx, &dep_node)| (dep_node, idx)).collect();
         PreviousDepGraph { data, index }
@@ -25,22 +31,22 @@ impl PreviousDepGraph {
     }
 
     #[inline]
-    pub fn index_to_node(&self, dep_node_index: SerializedDepNodeIndex) -> DepNode {
+    pub fn index_to_node(&self, dep_node_index: SerializedDepNodeIndex) -> DepNode<K> {
         self.data.nodes[dep_node_index]
     }
 
     #[inline]
-    pub fn node_to_index(&self, dep_node: &DepNode) -> SerializedDepNodeIndex {
+    pub fn node_to_index(&self, dep_node: &DepNode<K>) -> SerializedDepNodeIndex {
         self.index[dep_node]
     }
 
     #[inline]
-    pub fn node_to_index_opt(&self, dep_node: &DepNode) -> Option<SerializedDepNodeIndex> {
+    pub fn node_to_index_opt(&self, dep_node: &DepNode<K>) -> Option<SerializedDepNodeIndex> {
         self.index.get(dep_node).cloned()
     }
 
     #[inline]
-    pub fn fingerprint_of(&self, dep_node: &DepNode) -> Option<Fingerprint> {
+    pub fn fingerprint_of(&self, dep_node: &DepNode<K>) -> Option<Fingerprint> {
         self.index.get(dep_node).map(|&node_index| self.data.fingerprints[node_index])
     }
 
diff --git a/src/librustc/dep_graph/query.rs b/src/librustc_query_system/dep_graph/query.rs
index c71c11ed0eb..4a4283b2a0c 100644
--- a/src/librustc/dep_graph/query.rs
+++ b/src/librustc_query_system/dep_graph/query.rs
@@ -3,15 +3,15 @@ use rustc_data_structures::graph::implementation::{
     Direction, Graph, NodeIndex, INCOMING, OUTGOING,
 };
 
-use super::DepNode;
+use super::{DepKind, DepNode};
 
-pub struct DepGraphQuery {
-    pub graph: Graph<DepNode, ()>,
-    pub indices: FxHashMap<DepNode, NodeIndex>,
+pub struct DepGraphQuery<K> {
+    pub graph: Graph<DepNode<K>, ()>,
+    pub indices: FxHashMap<DepNode<K>, NodeIndex>,
 }
 
-impl DepGraphQuery {
-    pub fn new(nodes: &[DepNode], edges: &[(DepNode, DepNode)]) -> DepGraphQuery {
+impl<K: DepKind> DepGraphQuery<K> {
+    pub fn new(nodes: &[DepNode<K>], edges: &[(DepNode<K>, DepNode<K>)]) -> DepGraphQuery<K> {
         let mut graph = Graph::with_capacity(nodes.len(), edges.len());
         let mut indices = FxHashMap::default();
         for node in nodes {
@@ -27,15 +27,15 @@ impl DepGraphQuery {
         DepGraphQuery { graph, indices }
     }
 
-    pub fn contains_node(&self, node: &DepNode) -> bool {
+    pub fn contains_node(&self, node: &DepNode<K>) -> bool {
         self.indices.contains_key(&node)
     }
 
-    pub fn nodes(&self) -> Vec<&DepNode> {
+    pub fn nodes(&self) -> Vec<&DepNode<K>> {
         self.graph.all_nodes().iter().map(|n| &n.data).collect()
     }
 
-    pub fn edges(&self) -> Vec<(&DepNode, &DepNode)> {
+    pub fn edges(&self) -> Vec<(&DepNode<K>, &DepNode<K>)> {
         self.graph
             .all_edges()
             .iter()
@@ -44,7 +44,7 @@ impl DepGraphQuery {
             .collect()
     }
 
-    fn reachable_nodes(&self, node: &DepNode, direction: Direction) -> Vec<&DepNode> {
+    fn reachable_nodes(&self, node: &DepNode<K>, direction: Direction) -> Vec<&DepNode<K>> {
         if let Some(&index) = self.indices.get(node) {
             self.graph.depth_traverse(index, direction).map(|s| self.graph.node_data(s)).collect()
         } else {
@@ -54,17 +54,17 @@ impl DepGraphQuery {
 
     /// All nodes reachable from `node`. In other words, things that
     /// will have to be recomputed if `node` changes.
-    pub fn transitive_successors(&self, node: &DepNode) -> Vec<&DepNode> {
+    pub fn transitive_successors(&self, node: &DepNode<K>) -> Vec<&DepNode<K>> {
         self.reachable_nodes(node, OUTGOING)
     }
 
     /// All nodes that can reach `node`.
-    pub fn transitive_predecessors(&self, node: &DepNode) -> Vec<&DepNode> {
+    pub fn transitive_predecessors(&self, node: &DepNode<K>) -> Vec<&DepNode<K>> {
         self.reachable_nodes(node, INCOMING)
     }
 
     /// Just the outgoing edges from `node`.
-    pub fn immediate_successors(&self, node: &DepNode) -> Vec<&DepNode> {
+    pub fn immediate_successors(&self, node: &DepNode<K>) -> Vec<&DepNode<K>> {
         if let Some(&index) = self.indices.get(&node) {
             self.graph.successor_nodes(index).map(|s| self.graph.node_data(s)).collect()
         } else {
diff --git a/src/librustc_query_system/dep_graph/safe.rs b/src/librustc_query_system/dep_graph/safe.rs
new file mode 100644
index 00000000000..7bba348f884
--- /dev/null
+++ b/src/librustc_query_system/dep_graph/safe.rs
@@ -0,0 +1,51 @@
+//! The `DepGraphSafe` trait
+
+use rustc_ast::ast::NodeId;
+use rustc_hir::def_id::DefId;
+use rustc_hir::BodyId;
+
+/// The `DepGraphSafe` trait is used to specify what kinds of values
+/// are safe to "leak" into a task. The idea is that this should be
+/// only be implemented for things like the tcx as well as various id
+/// types, which will create reads in the dep-graph whenever the trait
+/// loads anything that might depend on the input program.
+pub trait DepGraphSafe {}
+
+/// A `BodyId` on its own doesn't give access to any particular state.
+/// You must fetch the state from the various maps or generate
+/// on-demand queries, all of which create reads.
+impl DepGraphSafe for BodyId {}
+
+/// A `NodeId` on its own doesn't give access to any particular state.
+/// You must fetch the state from the various maps or generate
+/// on-demand queries, all of which create reads.
+impl DepGraphSafe for NodeId {}
+
+/// A `DefId` on its own doesn't give access to any particular state.
+/// You must fetch the state from the various maps or generate
+/// on-demand queries, all of which create reads.
+impl DepGraphSafe for DefId {}
+
+/// Tuples make it easy to build up state.
+impl<A, B> DepGraphSafe for (A, B)
+where
+    A: DepGraphSafe,
+    B: DepGraphSafe,
+{
+}
+
+/// Shared ref to dep-graph-safe stuff should still be dep-graph-safe.
+impl<'a, A> DepGraphSafe for &'a A where A: DepGraphSafe {}
+
+/// Mut ref to dep-graph-safe stuff should still be dep-graph-safe.
+impl<'a, A> DepGraphSafe for &'a mut A where A: DepGraphSafe {}
+
+/// No data here! :)
+impl DepGraphSafe for () {}
+
+/// A convenient override that lets you pass arbitrary state into a
+/// task. Every use should be accompanied by a comment explaining why
+/// it makes sense (or how it could be refactored away in the future).
+pub struct AssertDepGraphSafe<T>(pub T);
+
+impl<T> DepGraphSafe for AssertDepGraphSafe<T> {}
diff --git a/src/librustc/dep_graph/serialized.rs b/src/librustc_query_system/dep_graph/serialized.rs
index 45ef52dbf39..4a89da23ea6 100644
--- a/src/librustc/dep_graph/serialized.rs
+++ b/src/librustc_query_system/dep_graph/serialized.rs
@@ -1,7 +1,7 @@
 //! The data that we will serialize and deserialize.
 
-use crate::dep_graph::DepNode;
-use crate::ich::Fingerprint;
+use super::{DepKind, DepNode};
+use rustc_data_structures::fingerprint::Fingerprint;
 use rustc_index::vec::IndexVec;
 
 rustc_index::newtype_index! {
@@ -9,10 +9,10 @@ rustc_index::newtype_index! {
 }
 
 /// Data for use when recompiling the **current crate**.
-#[derive(Debug, RustcEncodable, RustcDecodable, Default)]
-pub struct SerializedDepGraph {
+#[derive(Debug, RustcEncodable, RustcDecodable)]
+pub struct SerializedDepGraph<K: DepKind> {
     /// The set of all DepNodes in the graph
-    pub nodes: IndexVec<SerializedDepNodeIndex, DepNode>,
+    pub nodes: IndexVec<SerializedDepNodeIndex, DepNode<K>>,
     /// The set of all Fingerprints in the graph. Each Fingerprint corresponds to
     /// the DepNode at the same index in the nodes vector.
     pub fingerprints: IndexVec<SerializedDepNodeIndex, Fingerprint>,
@@ -25,7 +25,18 @@ pub struct SerializedDepGraph {
     pub edge_list_data: Vec<SerializedDepNodeIndex>,
 }
 
-impl SerializedDepGraph {
+impl<K: DepKind> Default for SerializedDepGraph<K> {
+    fn default() -> Self {
+        SerializedDepGraph {
+            nodes: Default::default(),
+            fingerprints: Default::default(),
+            edge_list_indices: Default::default(),
+            edge_list_data: Default::default(),
+        }
+    }
+}
+
+impl<K: DepKind> SerializedDepGraph<K> {
     #[inline]
     pub fn edge_targets_from(&self, source: SerializedDepNodeIndex) -> &[SerializedDepNodeIndex] {
         let targets = self.edge_list_indices[source];
diff --git a/src/librustc_query_system/lib.rs b/src/librustc_query_system/lib.rs
new file mode 100644
index 00000000000..ef4886828c4
--- /dev/null
+++ b/src/librustc_query_system/lib.rs
@@ -0,0 +1,32 @@
+#![feature(const_fn)]
+#![feature(const_if_match)]
+#![feature(const_panic)]
+#![feature(core_intrinsics)]
+#![feature(specialization)]
+#![feature(stmt_expr_attributes)]
+
+#[macro_use]
+extern crate log;
+
+pub mod dep_graph;
+
+pub trait HashStableContext {
+    fn debug_dep_tasks(&self) -> bool;
+}
+
+/// Something that can provide a stable hashing context.
+pub trait HashStableContextProvider<Ctxt> {
+    fn get_stable_hashing_context(&self) -> Ctxt;
+}
+
+impl<Ctxt, T: HashStableContextProvider<Ctxt>> HashStableContextProvider<Ctxt> for &T {
+    fn get_stable_hashing_context(&self) -> Ctxt {
+        (**self).get_stable_hashing_context()
+    }
+}
+
+impl<Ctxt, T: HashStableContextProvider<Ctxt>> HashStableContextProvider<Ctxt> for &mut T {
+    fn get_stable_hashing_context(&self) -> Ctxt {
+        (**self).get_stable_hashing_context()
+    }
+}
diff --git a/src/librustc_trait_selection/opaque_types.rs b/src/librustc_trait_selection/opaque_types.rs
index 9cd97c34f3b..30189d189f2 100644
--- a/src/librustc_trait_selection/opaque_types.rs
+++ b/src/librustc_trait_selection/opaque_types.rs
@@ -816,11 +816,7 @@ impl TypeFolder<'tcx> for ReverseMapper<'tcx> {
             // The regions that we expect from borrow checking.
             ty::ReEarlyBound(_) | ty::ReFree(_) | ty::ReEmpty(ty::UniverseIndex::ROOT) => {}
 
-            ty::ReEmpty(_)
-            | ty::RePlaceholder(_)
-            | ty::ReVar(_)
-            | ty::ReScope(_)
-            | ty::ReClosureBound(_) => {
+            ty::ReEmpty(_) | ty::RePlaceholder(_) | ty::ReVar(_) | ty::ReScope(_) => {
                 // All of the regions in the type should either have been
                 // erased by writeback, or mapped back to named regions by
                 // borrow checking.
diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index e812fa81e62..6f558ec9b95 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -20,9 +20,9 @@ use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticId};
 use rustc_hir as hir;
 use rustc_hir::def::{CtorOf, DefKind, Namespace, Res};
 use rustc_hir::def_id::DefId;
-use rustc_hir::intravisit::Visitor;
+use rustc_hir::intravisit::{walk_generics, Visitor};
 use rustc_hir::print;
-use rustc_hir::{Constness, ExprKind, GenericArg, GenericArgs};
+use rustc_hir::{Constness, GenericArg, GenericArgs};
 use rustc_session::lint::builtin::{AMBIGUOUS_ASSOCIATED_ITEMS, LATE_BOUND_LIFETIME_ARGUMENTS};
 use rustc_session::parse::feature_err;
 use rustc_session::Session;
@@ -39,8 +39,6 @@ use std::collections::BTreeSet;
 use std::iter;
 use std::slice;
 
-use rustc::mir::interpret::LitToConstInput;
-
 #[derive(Debug)]
 pub struct PathSeg(pub DefId, pub usize);
 
@@ -782,7 +780,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                     }
                 }
                 (GenericParamDefKind::Const, GenericArg::Const(ct)) => {
-                    self.ast_const_to_const(&ct.value, tcx.type_of(param.def_id)).into()
+                    let ct_def_id = tcx.hir().local_def_id(ct.value.hir_id).expect_local();
+                    ty::Const::from_anon_const(tcx, ct_def_id).into()
                 }
                 _ => unreachable!(),
             },
@@ -838,18 +837,6 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                 }
             },
         );
-        if !inferred_params.is_empty() {
-            // We always collect the spans for placeholder types when evaluating `fn`s, but we
-            // only want to emit an error complaining about them if infer types (`_`) are not
-            // allowed. `allow_ty_infer` gates this behavior.
-            crate::collect::placeholder_type_error(
-                tcx,
-                inferred_params[0],
-                &[],
-                inferred_params,
-                false,
-            );
-        }
 
         self.complain_about_missing_type_params(
             missing_type_params,
@@ -2747,7 +2734,13 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
             }
             hir::TyKind::BareFn(ref bf) => {
                 require_c_abi_if_c_variadic(tcx, &bf.decl, bf.abi, ast_ty.span);
-                tcx.mk_fn_ptr(self.ty_of_fn(bf.unsafety, bf.abi, &bf.decl, &[], None))
+                tcx.mk_fn_ptr(self.ty_of_fn(
+                    bf.unsafety,
+                    bf.abi,
+                    &bf.decl,
+                    &hir::Generics::empty(),
+                    None,
+                ))
             }
             hir::TyKind::TraitObject(ref bounds, ref lifetime) => {
                 self.conv_object_ty_poly_trait_ref(ast_ty.span, bounds, lifetime)
@@ -2775,7 +2768,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                     .unwrap_or(tcx.types.err)
             }
             hir::TyKind::Array(ref ty, ref length) => {
-                let length = self.ast_const_to_const(length, tcx.types.usize);
+                let length_def_id = tcx.hir().local_def_id(length.hir_id).expect_local();
+                let length = ty::Const::from_anon_const(tcx, length_def_id);
                 let array_ty = tcx.mk_ty(ty::Array(self.ast_ty_to_ty(&ty), length));
                 self.normalize_ty(ast_ty.span, array_ty)
             }
@@ -2807,75 +2801,6 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
         result_ty
     }
 
-    /// Returns the `DefId` of the constant parameter that the provided expression is a path to.
-    pub fn const_param_def_id(&self, expr: &hir::Expr<'_>) -> Option<DefId> {
-        // Unwrap a block, so that e.g. `{ P }` is recognised as a parameter. Const arguments
-        // currently have to be wrapped in curly brackets, so it's necessary to special-case.
-        let expr = match &expr.kind {
-            ExprKind::Block(block, _) if block.stmts.is_empty() && block.expr.is_some() => {
-                block.expr.as_ref().unwrap()
-            }
-            _ => expr,
-        };
-
-        match &expr.kind {
-            ExprKind::Path(hir::QPath::Resolved(_, path)) => match path.res {
-                Res::Def(DefKind::ConstParam, did) => Some(did),
-                _ => None,
-            },
-            _ => None,
-        }
-    }
-
-    pub fn ast_const_to_const(
-        &self,
-        ast_const: &hir::AnonConst,
-        ty: Ty<'tcx>,
-    ) -> &'tcx ty::Const<'tcx> {
-        debug!("ast_const_to_const(id={:?}, ast_const={:?})", ast_const.hir_id, ast_const);
-
-        let tcx = self.tcx();
-        let def_id = tcx.hir().local_def_id(ast_const.hir_id);
-
-        let expr = &tcx.hir().body(ast_const.body).value;
-
-        let lit_input = match expr.kind {
-            hir::ExprKind::Lit(ref lit) => Some(LitToConstInput { lit: &lit.node, ty, neg: false }),
-            hir::ExprKind::Unary(hir::UnOp::UnNeg, ref expr) => match expr.kind {
-                hir::ExprKind::Lit(ref lit) => {
-                    Some(LitToConstInput { lit: &lit.node, ty, neg: true })
-                }
-                _ => None,
-            },
-            _ => None,
-        };
-
-        if let Some(lit_input) = lit_input {
-            // If an error occurred, ignore that it's a literal and leave reporting the error up to
-            // mir.
-            if let Ok(c) = tcx.at(expr.span).lit_to_const(lit_input) {
-                return c;
-            } else {
-                tcx.sess.delay_span_bug(expr.span, "ast_const_to_const: couldn't lit_to_const");
-            }
-        }
-
-        let kind = if let Some(def_id) = self.const_param_def_id(expr) {
-            // Find the name and index of the const parameter by indexing the generics of the
-            // parent item and construct a `ParamConst`.
-            let hir_id = tcx.hir().as_local_hir_id(def_id).unwrap();
-            let item_id = tcx.hir().get_parent_node(hir_id);
-            let item_def_id = tcx.hir().local_def_id(item_id);
-            let generics = tcx.generics_of(item_def_id);
-            let index = generics.param_def_id_to_index[&tcx.hir().local_def_id(hir_id)];
-            let name = tcx.hir().name(hir_id);
-            ty::ConstKind::Param(ty::ParamConst::new(index, name))
-        } else {
-            ty::ConstKind::Unevaluated(def_id, InternalSubsts::identity_for_item(tcx, def_id), None)
-        };
-        tcx.mk_const(ty::Const { val: kind, ty })
-    }
-
     pub fn impl_trait_ty_to_ty(
         &self,
         def_id: DefId,
@@ -2930,7 +2855,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
         unsafety: hir::Unsafety,
         abi: abi::Abi,
         decl: &hir::FnDecl<'_>,
-        generic_params: &[hir::GenericParam<'_>],
+        generics: &hir::Generics<'_>,
         ident_span: Option<Span>,
     ) -> ty::PolyFnSig<'tcx> {
         debug!("ty_of_fn");
@@ -2942,6 +2867,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
         for ty in decl.inputs {
             visitor.visit_ty(ty);
         }
+        walk_generics(&mut visitor, generics);
+
         let input_tys = decl.inputs.iter().map(|a| self.ty_of_arg(a, None));
         let output_ty = match decl.output {
             hir::FnRetTy::Return(ref output) => {
@@ -2963,7 +2890,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
             crate::collect::placeholder_type_error(
                 tcx,
                 ident_span.map(|sp| sp.shrink_to_hi()).unwrap_or(DUMMY_SP),
-                generic_params,
+                &generics.params[..],
                 visitor.0,
                 ident_span.is_some(),
             );
@@ -2989,8 +2916,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                 tcx.sess,
                 decl.output.span(),
                 E0581,
-                "return type references {} \
-                                            which is not constrained by the fn input types",
+                "return type references {} which is not constrained by the fn input types",
                 lifetime_name
             );
             if let ty::BrAnon(_) = *br {
@@ -3001,8 +2927,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                 // though we can easily give a hint that ought to be
                 // relevant.
                 err.note(
-                    "lifetimes appearing in an associated type \
-                          are not considered constrained",
+                    "lifetimes appearing in an associated type are not considered constrained",
                 );
             }
             err.emit();
diff --git a/src/librustc_typeck/check/expr.rs b/src/librustc_typeck/check/expr.rs
index b42f74cced9..dffed9a836c 100644
--- a/src/librustc_typeck/check/expr.rs
+++ b/src/librustc_typeck/check/expr.rs
@@ -18,7 +18,6 @@ use crate::type_error_struct;
 use crate::util::common::ErrorReported;
 
 use rustc::middle::lang_items;
-use rustc::mir::interpret::ErrorHandled;
 use rustc::ty;
 use rustc::ty::adjustment::{Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability};
 use rustc::ty::Ty;
@@ -1008,13 +1007,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         _expr: &'tcx hir::Expr<'tcx>,
     ) -> Ty<'tcx> {
         let tcx = self.tcx;
-        let count_def_id = tcx.hir().local_def_id(count.hir_id);
-        let count = if self.const_param_def_id(count).is_some() {
-            Ok(self.to_const(count, tcx.type_of(count_def_id)))
-        } else {
-            tcx.const_eval_poly(count_def_id)
-                .map(|val| ty::Const::from_value(tcx, val, tcx.type_of(count_def_id)))
-        };
+        let count = self.to_const(count);
 
         let uty = match expected {
             ExpectHasType(uty) => match uty.kind {
@@ -1042,17 +1035,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         if element_ty.references_error() {
             return tcx.types.err;
         }
-        match count {
-            Ok(count) => tcx.mk_ty(ty::Array(t, count)),
-            Err(ErrorHandled::TooGeneric) => {
-                self.tcx.sess.span_err(
-                    tcx.def_span(count_def_id),
-                    "array lengths can't depend on generic parameters",
-                );
-                tcx.types.err
-            }
-            Err(ErrorHandled::Reported) => tcx.types.err,
-        }
+
+        tcx.mk_ty(ty::Array(t, count))
     }
 
     fn check_expr_tuple(
diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs
index 48c72567b5c..d340d6ff5c2 100644
--- a/src/librustc_typeck/check/method/confirm.rs
+++ b/src/librustc_typeck/check/method/confirm.rs
@@ -331,7 +331,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
                 }
                 (GenericParamDefKind::Type { .. }, GenericArg::Type(ty)) => self.to_ty(ty).into(),
                 (GenericParamDefKind::Const, GenericArg::Const(ct)) => {
-                    self.to_const(&ct.value, self.tcx.type_of(param.def_id)).into()
+                    self.to_const(&ct.value).into()
                 }
                 _ => unreachable!(),
             },
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 3aa76a46f60..085510452c4 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -1003,7 +1003,14 @@ fn typeck_tables_of_with_fallback<'tcx>(
         let fcx = if let (Some(header), Some(decl)) = (fn_header, fn_decl) {
             let fn_sig = if crate::collect::get_infer_ret_ty(&decl.output).is_some() {
                 let fcx = FnCtxt::new(&inh, param_env, body.value.hir_id);
-                AstConv::ty_of_fn(&fcx, header.unsafety, header.abi, decl, &[], None)
+                AstConv::ty_of_fn(
+                    &fcx,
+                    header.unsafety,
+                    header.abi,
+                    decl,
+                    &hir::Generics::empty(),
+                    None,
+                )
             } else {
                 tcx.fn_sig(def_id)
             };
@@ -3279,13 +3286,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         ty
     }
 
-    /// Returns the `DefId` of the constant parameter that the provided expression is a path to.
-    pub fn const_param_def_id(&self, hir_c: &hir::AnonConst) -> Option<DefId> {
-        AstConv::const_param_def_id(self, &self.tcx.hir().body(hir_c.body).value)
-    }
-
-    pub fn to_const(&self, ast_c: &hir::AnonConst, ty: Ty<'tcx>) -> &'tcx ty::Const<'tcx> {
-        AstConv::ast_const_to_const(self, ast_c, ty)
+    pub fn to_const(&self, ast_c: &hir::AnonConst) -> &'tcx ty::Const<'tcx> {
+        let c = self.tcx.hir().local_def_id(ast_c.hir_id).expect_local();
+        ty::Const::from_anon_const(self.tcx, c)
     }
 
     // If the type given by the user has free regions, save it for later, since
@@ -5512,7 +5515,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         self.to_ty(ty).into()
                     }
                     (GenericParamDefKind::Const, GenericArg::Const(ct)) => {
-                        self.to_const(&ct.value, self.tcx.type_of(param.def_id)).into()
+                        self.to_const(&ct.value).into()
                     }
                     _ => unreachable!(),
                 },
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index f1e6655e8fe..8136417de03 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -1486,7 +1486,7 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: DefId) -> ty::PolyFnSig<'_> {
                     sig.header.unsafety,
                     sig.header.abi,
                     &sig.decl,
-                    &generics.params[..],
+                    &generics,
                     Some(ident.span),
                 ),
             }
@@ -1497,14 +1497,9 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: DefId) -> ty::PolyFnSig<'_> {
             ident,
             generics,
             ..
-        }) => AstConv::ty_of_fn(
-            &icx,
-            header.unsafety,
-            header.abi,
-            decl,
-            &generics.params[..],
-            Some(ident.span),
-        ),
+        }) => {
+            AstConv::ty_of_fn(&icx, header.unsafety, header.abi, decl, &generics, Some(ident.span))
+        }
 
         ForeignItem(&hir::ForeignItem { kind: ForeignItemKind::Fn(ref fn_decl, _, _), .. }) => {
             let abi = tcx.hir().get_foreign_abi(hir_id);
@@ -2127,7 +2122,14 @@ fn compute_sig_of_foreign_fn_decl<'tcx>(
     } else {
         hir::Unsafety::Unsafe
     };
-    let fty = AstConv::ty_of_fn(&ItemCtxt::new(tcx, def_id), unsafety, abi, decl, &[], None);
+    let fty = AstConv::ty_of_fn(
+        &ItemCtxt::new(tcx, def_id),
+        unsafety,
+        abi,
+        decl,
+        &hir::Generics::empty(),
+        None,
+    );
 
     // Feature gate SIMD types in FFI, since I am not sure that the
     // ABIs are handled at all correctly. -huonw
diff --git a/src/librustc_typeck/outlives/utils.rs b/src/librustc_typeck/outlives/utils.rs
index 0cc322f8c2d..e1bd78e5113 100644
--- a/src/librustc_typeck/outlives/utils.rs
+++ b/src/librustc_typeck/outlives/utils.rs
@@ -170,7 +170,6 @@ fn is_free_region(tcx: TyCtxt<'_>, region: Region<'_>) -> bool {
 
         // These regions don't appear in types from type declarations:
         RegionKind::ReErased
-        | RegionKind::ReClosureBound(..)
         | RegionKind::ReScope(..)
         | RegionKind::ReVar(..)
         | RegionKind::RePlaceholder(..)
diff --git a/src/librustc_typeck/variance/constraints.rs b/src/librustc_typeck/variance/constraints.rs
index 54f84272ae8..11612066d44 100644
--- a/src/librustc_typeck/variance/constraints.rs
+++ b/src/librustc_typeck/variance/constraints.rs
@@ -449,7 +449,6 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
             }
 
             ty::ReFree(..)
-            | ty::ReClosureBound(..)
             | ty::ReScope(..)
             | ty::ReVar(..)
             | ty::RePlaceholder(..)
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index e69d4ddc2d0..7dfcf0a637e 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -450,7 +450,6 @@ impl Clean<Option<Lifetime>> for ty::RegionKind {
             | ty::ReVar(..)
             | ty::RePlaceholder(..)
             | ty::ReEmpty(_)
-            | ty::ReClosureBound(_)
             | ty::ReErased => {
                 debug!("cannot clean region {:?}", self);
                 None
diff --git a/src/test/compile-fail/issue-52443.rs b/src/test/compile-fail/issue-52443.rs
index 597fbbf00d5..3a022230b39 100644
--- a/src/test/compile-fail/issue-52443.rs
+++ b/src/test/compile-fail/issue-52443.rs
@@ -7,10 +7,5 @@ fn main() {
     //~^ ERROR `while` is not allowed in a `const`
     //~| WARN denote infinite loops with
     [(); { for _ in 0usize.. {}; 0}];
-    //~^ ERROR calls in constants are limited to constant functions
-    //~| ERROR calls in constants are limited to constant functions
-    //~| ERROR `for` is not allowed in a `const`
-    //~| ERROR references in constants may only refer to immutable values
-    //~| ERROR evaluation of constant value failed
-    //~| ERROR constant contains unimplemented expression type
+    //~^ ERROR `for` is not allowed in a `const`
 }
diff --git a/src/test/rustdoc-ui/deny-missing-docs-crate.stderr b/src/test/rustdoc-ui/deny-missing-docs-crate.stderr
index f0a13b70b97..821e6b99f7b 100644
--- a/src/test/rustdoc-ui/deny-missing-docs-crate.stderr
+++ b/src/test/rustdoc-ui/deny-missing-docs-crate.stderr
@@ -1,4 +1,4 @@
-error: missing documentation for crate
+error: missing documentation for the crate
   --> $DIR/deny-missing-docs-crate.rs:1:1
    |
 LL | / #![deny(missing_docs)]
diff --git a/src/test/ui/borrowck/issue-69789-iterator-mut-suggestion.rs b/src/test/ui/borrowck/issue-69789-iterator-mut-suggestion.rs
new file mode 100644
index 00000000000..f6d0e9e04d3
--- /dev/null
+++ b/src/test/ui/borrowck/issue-69789-iterator-mut-suggestion.rs
@@ -0,0 +1,11 @@
+// Regression test for #69789: rustc generated an invalid suggestion
+// when `&` reference from `&mut` iterator is mutated.
+
+fn main() {
+    for item in &mut std::iter::empty::<&'static ()>() {
+        //~^ NOTE this iterator yields `&` references
+        *item = ();
+        //~^ ERROR cannot assign
+        //~| NOTE  cannot be written
+    }
+}
diff --git a/src/test/ui/borrowck/issue-69789-iterator-mut-suggestion.stderr b/src/test/ui/borrowck/issue-69789-iterator-mut-suggestion.stderr
new file mode 100644
index 00000000000..d2865ffd196
--- /dev/null
+++ b/src/test/ui/borrowck/issue-69789-iterator-mut-suggestion.stderr
@@ -0,0 +1,12 @@
+error[E0594]: cannot assign to `*item` which is behind a `&` reference
+  --> $DIR/issue-69789-iterator-mut-suggestion.rs:7:9
+   |
+LL |     for item in &mut std::iter::empty::<&'static ()>() {
+   |                 -------------------------------------- this iterator yields `&` references
+LL |
+LL |         *item = ();
+   |         ^^^^^^^^^^ `item` is a `&` reference, so the data it refers to cannot be written
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0594`.
diff --git a/src/test/ui/closures/issue-52437.rs b/src/test/ui/closures/issue-52437.rs
index 1e649a556e0..634638e1335 100644
--- a/src/test/ui/closures/issue-52437.rs
+++ b/src/test/ui/closures/issue-52437.rs
@@ -3,4 +3,5 @@ fn main() {
     //~^ ERROR: invalid label name `'static`
     //~| ERROR: `loop` is not allowed in a `const`
     //~| ERROR: type annotations needed
+    //~| ERROR mismatched types
 }
diff --git a/src/test/ui/closures/issue-52437.stderr b/src/test/ui/closures/issue-52437.stderr
index b9225e55fe5..acb59c7b02d 100644
--- a/src/test/ui/closures/issue-52437.stderr
+++ b/src/test/ui/closures/issue-52437.stderr
@@ -19,7 +19,15 @@ error[E0282]: type annotations needed
 LL |     [(); &(&'static: loop { |x| {}; }) as *const _ as usize]
    |                              ^ consider giving this closure parameter a type
 
-error: aborting due to 3 previous errors
+error[E0308]: mismatched types
+  --> $DIR/issue-52437.rs:2:5
+   |
+LL | fn main() {
+   |           - expected `()` because of default return type
+LL |     [(); &(&'static: loop { |x| {}; }) as *const _ as usize]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found array `[(); _]`
+
+error: aborting due to 4 previous errors
 
-Some errors have detailed explanations: E0282, E0658.
+Some errors have detailed explanations: E0282, E0308, E0658.
 For more information about an error, try `rustc --explain E0282`.
diff --git a/src/test/ui/const-generics/issues/issue-61336-1.rs b/src/test/ui/const-generics/issues/issue-61336-1.rs
index 5b5e431bf2f..165d3e1c2e6 100644
--- a/src/test/ui/const-generics/issues/issue-61336-1.rs
+++ b/src/test/ui/const-generics/issues/issue-61336-1.rs
@@ -1,9 +1,10 @@
 #![feature(const_generics)]
 //~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
 
+// build-pass
+
 fn f<T: Copy, const N: usize>(x: T) -> [T; N] {
     [x; N]
-    //~^ ERROR array lengths can't depend on generic parameters
 }
 
 fn main() {
diff --git a/src/test/ui/const-generics/issues/issue-61336-1.stderr b/src/test/ui/const-generics/issues/issue-61336-1.stderr
index 949fa896d87..d48d8ff6894 100644
--- a/src/test/ui/const-generics/issues/issue-61336-1.stderr
+++ b/src/test/ui/const-generics/issues/issue-61336-1.stderr
@@ -6,11 +6,3 @@ LL | #![feature(const_generics)]
    |
    = note: `#[warn(incomplete_features)]` on by default
 
-error: array lengths can't depend on generic parameters
-  --> $DIR/issue-61336-1.rs:5:9
-   |
-LL |     [x; N]
-   |         ^
-
-error: aborting due to previous error
-
diff --git a/src/test/ui/const-generics/issues/issue-61336-2.rs b/src/test/ui/const-generics/issues/issue-61336-2.rs
index 7bb36f41b8f..c5bf6b6ce94 100644
--- a/src/test/ui/const-generics/issues/issue-61336-2.rs
+++ b/src/test/ui/const-generics/issues/issue-61336-2.rs
@@ -2,13 +2,12 @@
 //~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
 
 fn f<T: Copy, const N: usize>(x: T) -> [T; N] {
-    [x; {N}]
-    //~^ ERROR array lengths can't depend on generic parameters
+    [x; { N }]
 }
 
 fn g<T, const N: usize>(x: T) -> [T; N] {
-    [x; {N}]
-    //~^ ERROR array lengths can't depend on generic parameters
+    [x; { N }]
+    //~^ ERROR the trait bound `T: std::marker::Copy` is not satisfied
 }
 
 fn main() {
diff --git a/src/test/ui/const-generics/issues/issue-61336-2.stderr b/src/test/ui/const-generics/issues/issue-61336-2.stderr
index 63f86c81b1e..9ced427b93c 100644
--- a/src/test/ui/const-generics/issues/issue-61336-2.stderr
+++ b/src/test/ui/const-generics/issues/issue-61336-2.stderr
@@ -6,17 +6,19 @@ LL | #![feature(const_generics)]
    |
    = note: `#[warn(incomplete_features)]` on by default
 
-error: array lengths can't depend on generic parameters
-  --> $DIR/issue-61336-2.rs:5:9
+error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied
+  --> $DIR/issue-61336-2.rs:9:5
    |
-LL |     [x; {N}]
-   |         ^^^
-
-error: array lengths can't depend on generic parameters
-  --> $DIR/issue-61336-2.rs:10:9
+LL |     [x; { N }]
+   |     ^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `T`
+   |
+help: consider restricting this type parameter with `T: std::marker::Copy`
+  --> $DIR/issue-61336-2.rs:8:6
    |
-LL |     [x; {N}]
-   |         ^^^
+LL | fn g<T, const N: usize>(x: T) -> [T; N] {
+   |      ^
+   = note: the `Copy` trait is required because the repeated element will be copied
 
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/const-generics/issues/issue-61336.rs b/src/test/ui/const-generics/issues/issue-61336.rs
index edc012cbb3d..7e84e62d8be 100644
--- a/src/test/ui/const-generics/issues/issue-61336.rs
+++ b/src/test/ui/const-generics/issues/issue-61336.rs
@@ -3,12 +3,11 @@
 
 fn f<T: Copy, const N: usize>(x: T) -> [T; N] {
     [x; N]
-    //~^ ERROR array lengths can't depend on generic parameters
 }
 
 fn g<T, const N: usize>(x: T) -> [T; N] {
     [x; N]
-    //~^ ERROR array lengths can't depend on generic parameters
+    //~^ ERROR the trait bound `T: std::marker::Copy` is not satisfied
 }
 
 fn main() {
diff --git a/src/test/ui/const-generics/issues/issue-61336.stderr b/src/test/ui/const-generics/issues/issue-61336.stderr
index f96e8e02d4e..ace7955fbdd 100644
--- a/src/test/ui/const-generics/issues/issue-61336.stderr
+++ b/src/test/ui/const-generics/issues/issue-61336.stderr
@@ -6,17 +6,19 @@ LL | #![feature(const_generics)]
    |
    = note: `#[warn(incomplete_features)]` on by default
 
-error: array lengths can't depend on generic parameters
-  --> $DIR/issue-61336.rs:5:9
+error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied
+  --> $DIR/issue-61336.rs:9:5
    |
 LL |     [x; N]
-   |         ^
-
-error: array lengths can't depend on generic parameters
-  --> $DIR/issue-61336.rs:10:9
+   |     ^^^^^^ the trait `std::marker::Copy` is not implemented for `T`
    |
-LL |     [x; N]
-   |         ^
+help: consider restricting this type parameter with `T: std::marker::Copy`
+  --> $DIR/issue-61336.rs:8:6
+   |
+LL | fn g<T, const N: usize>(x: T) -> [T; N] {
+   |      ^
+   = note: the `Copy` trait is required because the repeated element will be copied
 
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/const-generics/issues/issue-62456.rs b/src/test/ui/const-generics/issues/issue-62456.rs
index c5e6fe9104b..14b1190df0f 100644
--- a/src/test/ui/const-generics/issues/issue-62456.rs
+++ b/src/test/ui/const-generics/issues/issue-62456.rs
@@ -1,9 +1,10 @@
 #![feature(const_generics)]
 //~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
 
+// build-pass
+
 fn foo<const N: usize>() {
     let _ = [0u64; N + 1];
-    //~^ ERROR array lengths can't depend on generic parameters
 }
 
 fn main() {}
diff --git a/src/test/ui/const-generics/issues/issue-62456.stderr b/src/test/ui/const-generics/issues/issue-62456.stderr
index 9cdccf8407c..47dd3c01fa9 100644
--- a/src/test/ui/const-generics/issues/issue-62456.stderr
+++ b/src/test/ui/const-generics/issues/issue-62456.stderr
@@ -6,11 +6,3 @@ LL | #![feature(const_generics)]
    |
    = note: `#[warn(incomplete_features)]` on by default
 
-error: array lengths can't depend on generic parameters
-  --> $DIR/issue-62456.rs:5:20
-   |
-LL |     let _ = [0u64; N + 1];
-   |                    ^^^^^
-
-error: aborting due to previous error
-
diff --git a/src/test/ui/const-generics/issues/issue-62504.rs b/src/test/ui/const-generics/issues/issue-62504.rs
index 74ed3d354fc..cd3cfaac3b9 100644
--- a/src/test/ui/const-generics/issues/issue-62504.rs
+++ b/src/test/ui/const-generics/issues/issue-62504.rs
@@ -16,7 +16,7 @@ struct ArrayHolder<const X: usize>([u32; X]);
 impl<const X: usize> ArrayHolder<{ X }> {
     pub const fn new() -> Self {
         ArrayHolder([0; Self::SIZE])
-        //~^ ERROR: array lengths can't depend on generic parameters
+        //~^ ERROR: mismatched types
     }
 }
 
diff --git a/src/test/ui/const-generics/issues/issue-62504.stderr b/src/test/ui/const-generics/issues/issue-62504.stderr
index c2a752ec171..4482389bbdd 100644
--- a/src/test/ui/const-generics/issues/issue-62504.stderr
+++ b/src/test/ui/const-generics/issues/issue-62504.stderr
@@ -1,8 +1,12 @@
-error: array lengths can't depend on generic parameters
-  --> $DIR/issue-62504.rs:18:25
+error[E0308]: mismatched types
+  --> $DIR/issue-62504.rs:18:21
    |
 LL |         ArrayHolder([0; Self::SIZE])
-   |                         ^^^^^^^^^^
+   |                     ^^^^^^^^^^^^^^^ expected `X`, found `Self::SIZE`
+   |
+   = note: expected array `[u32; _]`
+              found array `[u32; _]`
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/const-generics/issues/issue-67739.rs b/src/test/ui/const-generics/issues/issue-67739.rs
index 79c5ac9dd18..3d657b0947b 100644
--- a/src/test/ui/const-generics/issues/issue-67739.rs
+++ b/src/test/ui/const-generics/issues/issue-67739.rs
@@ -1,5 +1,7 @@
 // Regression test for #67739
 
+// check-pass
+
 #![allow(incomplete_features)]
 #![feature(const_generics)]
 
@@ -10,7 +12,6 @@ pub trait Trait {
 
     fn associated_size(&self) -> usize {
         [0u8; mem::size_of::<Self::Associated>()];
-        //~^ ERROR: array lengths can't depend on generic parameters
         0
     }
 }
diff --git a/src/test/ui/const-generics/issues/issue-67739.stderr b/src/test/ui/const-generics/issues/issue-67739.stderr
deleted file mode 100644
index a31b556c086..00000000000
--- a/src/test/ui/const-generics/issues/issue-67739.stderr
+++ /dev/null
@@ -1,8 +0,0 @@
-error: array lengths can't depend on generic parameters
-  --> $DIR/issue-67739.rs:12:15
-   |
-LL |         [0u8; mem::size_of::<Self::Associated>()];
-   |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to previous error
-
diff --git a/src/test/ui/const-generics/std/const-generics-range.rs b/src/test/ui/const-generics/std/const-generics-range.rs
new file mode 100644
index 00000000000..6d56fe0d7b8
--- /dev/null
+++ b/src/test/ui/const-generics/std/const-generics-range.rs
@@ -0,0 +1,30 @@
+// check-pass
+#![allow(incomplete_features)]
+#![feature(const_generics)]
+
+// `Range` should be usable within const generics:
+struct _Range<const R: std::ops::Range<usize>>;
+const RANGE : _Range<{ 0 .. 1000 }> = _Range;
+
+// `RangeFrom` should be usable within const generics:
+struct _RangeFrom<const R: std::ops::RangeFrom<usize>>;
+const RANGE_FROM : _RangeFrom<{ 0 .. }> = _RangeFrom;
+
+// `RangeFull` should be usable within const generics:
+struct _RangeFull<const R: std::ops::RangeFull>;
+const RANGE_FULL : _RangeFull<{ .. }> = _RangeFull;
+
+// Regression test for #70155
+// `RangeInclusive` should be usable within const generics:
+struct _RangeInclusive<const R: std::ops::RangeInclusive<usize>>;
+const RANGE_INCLUSIVE : _RangeInclusive<{ 0 ..= 999 }> = _RangeInclusive;
+
+// `RangeTo` should be usable within const generics:
+struct _RangeTo<const R: std::ops::RangeTo<usize>>;
+const RANGE_TO : _RangeTo<{ .. 1000 }> = _RangeTo;
+
+// `RangeToInclusive` should be usable within const generics:
+struct _RangeToInclusive<const R: std::ops::RangeToInclusive<usize>>;
+const RANGE_TO_INCLUSIVE : _RangeToInclusive<{ ..= 999 }> = _RangeToInclusive;
+
+pub fn main() {}
diff --git a/src/test/ui/consts/const-eval/const-eval-overflow-3.rs b/src/test/ui/consts/const-eval/const-eval-overflow-3.rs
index 6fd8e9cbc80..3ae55ebdbaf 100644
--- a/src/test/ui/consts/const-eval/const-eval-overflow-3.rs
+++ b/src/test/ui/consts/const-eval/const-eval-overflow-3.rs
@@ -19,6 +19,7 @@ const A_I8_I
     : [u32; (i8::MAX as usize) + 1]
     = [0; (i8::MAX + 1) as usize];
 //~^ ERROR evaluation of constant value failed
+//~| ERROR mismatched types
 
 fn main() {
     foo(&A_I8_I[..]);
diff --git a/src/test/ui/consts/const-eval/const-eval-overflow-3.stderr b/src/test/ui/consts/const-eval/const-eval-overflow-3.stderr
index 2c5b4607aa4..94b7c12fc1a 100644
--- a/src/test/ui/consts/const-eval/const-eval-overflow-3.stderr
+++ b/src/test/ui/consts/const-eval/const-eval-overflow-3.stderr
@@ -4,6 +4,16 @@ error[E0080]: evaluation of constant value failed
 LL |     = [0; (i8::MAX + 1) as usize];
    |           ^^^^^^^^^^^^^ attempt to add with overflow
 
-error: aborting due to previous error
+error[E0308]: mismatched types
+  --> $DIR/const-eval-overflow-3.rs:20:7
+   |
+LL |     = [0; (i8::MAX + 1) as usize];
+   |       ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `128usize`, found `(i8::MAX + 1) as usize`
+   |
+   = note: expected array `[u32; 128]`
+              found array `[u32; _]`
+
+error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0080`.
+Some errors have detailed explanations: E0080, E0308.
+For more information about an error, try `rustc --explain E0080`.
diff --git a/src/test/ui/consts/const-eval/const-eval-overflow-3b.rs b/src/test/ui/consts/const-eval/const-eval-overflow-3b.rs
index db6f17a671a..e7b88e00feb 100644
--- a/src/test/ui/consts/const-eval/const-eval-overflow-3b.rs
+++ b/src/test/ui/consts/const-eval/const-eval-overflow-3b.rs
@@ -18,6 +18,7 @@ const A_I8_I
     = [0; (i8::MAX + 1u8) as usize];
 //~^ ERROR mismatched types
 //~| ERROR cannot add `u8` to `i8`
+//~| ERROR mismatched types
 
 fn main() {
     foo(&A_I8_I[..]);
diff --git a/src/test/ui/consts/const-eval/const-eval-overflow-3b.stderr b/src/test/ui/consts/const-eval/const-eval-overflow-3b.stderr
index 3da34fe9af7..aebe4feef8d 100644
--- a/src/test/ui/consts/const-eval/const-eval-overflow-3b.stderr
+++ b/src/test/ui/consts/const-eval/const-eval-overflow-3b.stderr
@@ -12,7 +12,16 @@ LL |     = [0; (i8::MAX + 1u8) as usize];
    |
    = help: the trait `std::ops::Add<u8>` is not implemented for `i8`
 
-error: aborting due to 2 previous errors
+error[E0308]: mismatched types
+  --> $DIR/const-eval-overflow-3b.rs:18:7
+   |
+LL |     = [0; (i8::MAX + 1u8) as usize];
+   |       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `128usize`, found `(i8::MAX + 1u8) as usize`
+   |
+   = note: expected array `[u32; 128]`
+              found array `[u32; _]`
+
+error: aborting due to 3 previous errors
 
 Some errors have detailed explanations: E0277, E0308.
 For more information about an error, try `rustc --explain E0277`.
diff --git a/src/test/ui/consts/const-eval/infinite_loop.rs b/src/test/ui/consts/const-eval/infinite_loop.rs
index af5e7658d48..c8de259354e 100644
--- a/src/test/ui/consts/const-eval/infinite_loop.rs
+++ b/src/test/ui/consts/const-eval/infinite_loop.rs
@@ -2,7 +2,6 @@ fn main() {
     // Tests the Collatz conjecture with an incorrect base case (0 instead of 1).
     // The value of `n` will loop indefinitely (4 - 2 - 1 - 4).
     let _ = [(); {
-        //~^ WARNING Constant evaluating a complex constant, this might take some time
         let mut n = 113383; // #20 in https://oeis.org/A006884
         while n != 0 {
         //~^ ERROR `while` is not allowed in a `const`
diff --git a/src/test/ui/consts/const-eval/infinite_loop.stderr b/src/test/ui/consts/const-eval/infinite_loop.stderr
index e04c31cf397..ebdb73c4467 100644
--- a/src/test/ui/consts/const-eval/infinite_loop.stderr
+++ b/src/test/ui/consts/const-eval/infinite_loop.stderr
@@ -1,5 +1,5 @@
 error[E0658]: `while` is not allowed in a `const`
-  --> $DIR/infinite_loop.rs:7:9
+  --> $DIR/infinite_loop.rs:6:9
    |
 LL | /         while n != 0 {
 LL | |
@@ -14,7 +14,7 @@ LL | |         }
    = help: add `#![feature(const_if_match)]` to the crate attributes to enable
 
 error[E0658]: `if` is not allowed in a `const`
-  --> $DIR/infinite_loop.rs:9:17
+  --> $DIR/infinite_loop.rs:8:17
    |
 LL |             n = if n % 2 == 0 { n/2 } else { 3*n + 1 };
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -22,24 +22,11 @@ LL |             n = if n % 2 == 0 { n/2 } else { 3*n + 1 };
    = note: see issue #49146 <https://github.com/rust-lang/rust/issues/49146> for more information
    = help: add `#![feature(const_if_match)]` to the crate attributes to enable
 
-warning: Constant evaluating a complex constant, this might take some time
-  --> $DIR/infinite_loop.rs:4:18
-   |
-LL |       let _ = [(); {
-   |  __________________^
-LL | |
-LL | |         let mut n = 113383; // #20 in https://oeis.org/A006884
-LL | |         while n != 0 {
-...  |
-LL | |         n
-LL | |     }];
-   | |_____^
-
 error[E0080]: evaluation of constant value failed
-  --> $DIR/infinite_loop.rs:9:20
+  --> $DIR/infinite_loop.rs:8:20
    |
 LL |             n = if n % 2 == 0 { n/2 } else { 3*n + 1 };
-   |                    ^^^^^^^^^^ duplicate interpreter state observed here, const evaluation will never terminate
+   |                    ^^^^^^^^^^ exceeded interpreter step limit (see `#[const_eval_limit]`)
 
 error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/consts/const-eval/issue-52442.rs b/src/test/ui/consts/const-eval/issue-52442.rs
index d820c705161..df4cc8e3026 100644
--- a/src/test/ui/consts/const-eval/issue-52442.rs
+++ b/src/test/ui/consts/const-eval/issue-52442.rs
@@ -1,6 +1,4 @@
 fn main() {
     [();  { &loop { break } as *const _ as usize } ];
-    //~^ ERROR casting pointers to integers in constants is unstable
-    //~| ERROR `loop` is not allowed in a `const`
-    //~| ERROR evaluation of constant value failed
+    //~^ ERROR `loop` is not allowed in a `const`
 }
diff --git a/src/test/ui/consts/const-eval/issue-52442.stderr b/src/test/ui/consts/const-eval/issue-52442.stderr
index eda2dbf0b6b..0ea974f1f66 100644
--- a/src/test/ui/consts/const-eval/issue-52442.stderr
+++ b/src/test/ui/consts/const-eval/issue-52442.stderr
@@ -7,22 +7,6 @@ LL |     [();  { &loop { break } as *const _ as usize } ];
    = note: see issue #52000 <https://github.com/rust-lang/rust/issues/52000> for more information
    = help: add `#![feature(const_loop)]` to the crate attributes to enable
 
-error[E0658]: casting pointers to integers in constants is unstable
-  --> $DIR/issue-52442.rs:2:13
-   |
-LL |     [();  { &loop { break } as *const _ as usize } ];
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #51910 <https://github.com/rust-lang/rust/issues/51910> for more information
-   = help: add `#![feature(const_raw_ptr_to_usize_cast)]` to the crate attributes to enable
-
-error[E0080]: evaluation of constant value failed
-  --> $DIR/issue-52442.rs:2:13
-   |
-LL |     [();  { &loop { break } as *const _ as usize } ];
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ "pointer-to-integer cast" needs an rfc before being allowed inside constants
-
-error: aborting due to 3 previous errors
+error: aborting due to previous error
 
-Some errors have detailed explanations: E0080, E0658.
-For more information about an error, try `rustc --explain E0080`.
+For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/consts/const-eval/issue-52475.rs b/src/test/ui/consts/const-eval/issue-52475.rs
index 3788167f449..869f0b981af 100644
--- a/src/test/ui/consts/const-eval/issue-52475.rs
+++ b/src/test/ui/consts/const-eval/issue-52475.rs
@@ -1,6 +1,5 @@
 fn main() {
     let _ = [(); {
-        //~^ WARNING Constant evaluating a complex constant, this might take some time
         let mut x = &0;
         let mut n = 0;
         while n < 5 {
diff --git a/src/test/ui/consts/const-eval/issue-52475.stderr b/src/test/ui/consts/const-eval/issue-52475.stderr
index 31d87925b2c..b069537ead9 100644
--- a/src/test/ui/consts/const-eval/issue-52475.stderr
+++ b/src/test/ui/consts/const-eval/issue-52475.stderr
@@ -1,5 +1,5 @@
 error[E0658]: `while` is not allowed in a `const`
-  --> $DIR/issue-52475.rs:6:9
+  --> $DIR/issue-52475.rs:5:9
    |
 LL | /         while n < 5 {
 LL | |
@@ -12,24 +12,11 @@ LL | |         }
    = help: add `#![feature(const_loop)]` to the crate attributes to enable
    = help: add `#![feature(const_if_match)]` to the crate attributes to enable
 
-warning: Constant evaluating a complex constant, this might take some time
-  --> $DIR/issue-52475.rs:2:18
-   |
-LL |       let _ = [(); {
-   |  __________________^
-LL | |
-LL | |         let mut x = &0;
-LL | |         let mut n = 0;
-...  |
-LL | |         0
-LL | |     }];
-   | |_____^
-
 error[E0080]: evaluation of constant value failed
-  --> $DIR/issue-52475.rs:8:17
+  --> $DIR/issue-52475.rs:7:17
    |
 LL |             n = (n + 1) % 5;
-   |                 ^^^^^^^^^^^ duplicate interpreter state observed here, const evaluation will never terminate
+   |                 ^^^^^^^^^^^ exceeded interpreter step limit (see `#[const_eval_limit]`)
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/consts/const-eval/match-test-ptr-null.rs b/src/test/ui/consts/const-eval/match-test-ptr-null.rs
index 80494d16629..5cfe36f57e6 100644
--- a/src/test/ui/consts/const-eval/match-test-ptr-null.rs
+++ b/src/test/ui/consts/const-eval/match-test-ptr-null.rs
@@ -2,7 +2,7 @@ fn main() {
     // Make sure match uses the usual pointer comparison code path -- i.e., it should complain
     // that pointer comparison is disallowed, not that parts of a pointer are accessed as raw
     // bytes.
-    let _: [u8; 0] = [4; {
+    let _: [u8; 0] = [4; { //~ ERROR mismatched types
         match &1 as *const i32 as usize {
             //~^ ERROR casting pointers to integers in constants
             //~| ERROR `match` is not allowed in a `const`
diff --git a/src/test/ui/consts/const-eval/match-test-ptr-null.stderr b/src/test/ui/consts/const-eval/match-test-ptr-null.stderr
index b47f6d5f845..7c4da5e7d86 100644
--- a/src/test/ui/consts/const-eval/match-test-ptr-null.stderr
+++ b/src/test/ui/consts/const-eval/match-test-ptr-null.stderr
@@ -28,7 +28,30 @@ error[E0080]: evaluation of constant value failed
 LL |         match &1 as *const i32 as usize {
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^ "pointer-to-integer cast" needs an rfc before being allowed inside constants
 
-error: aborting due to 3 previous errors
+error[E0308]: mismatched types
+  --> $DIR/match-test-ptr-null.rs:5:22
+   |
+LL |       let _: [u8; 0] = [4; {
+   |  ____________-------___^
+   | |            |
+   | |            expected due to this
+LL | |         match &1 as *const i32 as usize {
+LL | |
+LL | |
+...  |
+LL | |         }
+LL | |     }];
+   | |______^ expected `0usize`, found `{
+        match &1 as *const i32 as usize {
+            0 => 42,
+            n => n,
+        }
+    }`
+   |
+   = note: expected array `[u8; 0]`
+              found array `[u8; _]`
+
+error: aborting due to 4 previous errors
 
-Some errors have detailed explanations: E0080, E0658.
+Some errors have detailed explanations: E0080, E0308, E0658.
 For more information about an error, try `rustc --explain E0080`.
diff --git a/src/test/ui/consts/const_limit/const_eval_limit_not_reached.rs b/src/test/ui/consts/const_limit/const_eval_limit_not_reached.rs
index 4ed908312fb..34abcdf08da 100644
--- a/src/test/ui/consts/const_limit/const_eval_limit_not_reached.rs
+++ b/src/test/ui/consts/const_limit/const_eval_limit_not_reached.rs
@@ -1,15 +1,21 @@
 // check-pass
+
 #![feature(const_eval_limit)]
-#![const_eval_limit="1000"]
+#![feature(const_loop, const_if_match)]
 
-const CONSTANT: usize = limit();
+// This needs to be higher than the number of loop iterations since each pass through the loop may
+// hit more than one terminator.
+#![const_eval_limit="4000"]
 
-fn main() {
-    assert_eq!(CONSTANT, 1764);
-}
+const X: usize = {
+    let mut x = 0;
+    while x != 1000 {
+        x += 1;
+    }
 
-const fn limit() -> usize {
-    let x = 42;
+    x
+};
 
-    x * 42
+fn main() {
+    assert_eq!(X, 1000);
 }
diff --git a/src/test/ui/consts/const_limit/const_eval_limit_reached.rs b/src/test/ui/consts/const_limit/const_eval_limit_reached.rs
index d962398d413..b45aca0b13e 100644
--- a/src/test/ui/consts/const_limit/const_eval_limit_reached.rs
+++ b/src/test/ui/consts/const_limit/const_eval_limit_reached.rs
@@ -1,21 +1,18 @@
-// ignore-tidy-linelength
-// only-x86_64
-// check-pass
-// NOTE: We always compile this test with -Copt-level=0 because higher opt-levels
-//       optimize away the const function
-// compile-flags:-Copt-level=0
 #![feature(const_eval_limit)]
-#![const_eval_limit="2"]
+#![feature(const_loop, const_if_match)]
 
-const CONSTANT: usize = limit();
-//~^ WARNING Constant evaluating a complex constant, this might take some time
+#![const_eval_limit="500"]
 
-fn main() {
-    assert_eq!(CONSTANT, 1764);
-}
+const X: usize = {
+    let mut x = 0;
+    while x != 1000 {
+        //~^ ERROR any use of this value will cause an error
+        x += 1;
+    }
 
-const fn limit() -> usize { //~ WARNING Constant evaluating a complex constant, this might take some time
-    let x = 42;
+    x
+};
 
-    x * 42
+fn main() {
+    assert_eq!(X, 1000);
 }
diff --git a/src/test/ui/consts/const_limit/const_eval_limit_reached.stderr b/src/test/ui/consts/const_limit/const_eval_limit_reached.stderr
index e0871ff7185..be522dd6d5d 100644
--- a/src/test/ui/consts/const_limit/const_eval_limit_reached.stderr
+++ b/src/test/ui/consts/const_limit/const_eval_limit_reached.stderr
@@ -1,16 +1,17 @@
-warning: Constant evaluating a complex constant, this might take some time
-  --> $DIR/const_eval_limit_reached.rs:17:1
+error: any use of this value will cause an error
+  --> $DIR/const_eval_limit_reached.rs:8:11
    |
-LL | / const fn limit() -> usize {
-LL | |     let x = 42;
+LL | / const X: usize = {
+LL | |     let mut x = 0;
+LL | |     while x != 1000 {
+   | |           ^^^^^^^^^ exceeded interpreter step limit (see `#[const_eval_limit]`)
 LL | |
-LL | |     x * 42
-LL | | }
-   | |_^
-
-warning: Constant evaluating a complex constant, this might take some time
-  --> $DIR/const_eval_limit_reached.rs:10:1
+...  |
+LL | |     x
+LL | | };
+   | |__-
    |
-LL | const CONSTANT: usize = limit();
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = note: `#[deny(const_err)]` on by default
+
+error: aborting due to previous error
 
diff --git a/src/test/ui/consts/issue-52432.rs b/src/test/ui/consts/issue-52432.rs
index 2d4c939f47d..ded79458e63 100644
--- a/src/test/ui/consts/issue-52432.rs
+++ b/src/test/ui/consts/issue-52432.rs
@@ -6,5 +6,4 @@ fn main() {
     //~| ERROR: type annotations needed
     [(); &(static || {}) as *const _ as usize];
     //~^ ERROR: closures cannot be static
-    //~| ERROR: evaluation of constant value failed
 }
diff --git a/src/test/ui/consts/issue-52432.stderr b/src/test/ui/consts/issue-52432.stderr
index e9539d24118..d25c11138f4 100644
--- a/src/test/ui/consts/issue-52432.stderr
+++ b/src/test/ui/consts/issue-52432.stderr
@@ -16,13 +16,7 @@ error[E0282]: type annotations needed
 LL |     [(); &(static |x| {}) as *const _ as usize];
    |                    ^ consider giving this closure parameter a type
 
-error[E0080]: evaluation of constant value failed
-  --> $DIR/issue-52432.rs:7:10
-   |
-LL |     [(); &(static || {}) as *const _ as usize];
-   |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ "pointer-to-integer cast" needs an rfc before being allowed inside constants
-
-error: aborting due to 4 previous errors
+error: aborting due to 3 previous errors
 
-Some errors have detailed explanations: E0080, E0282, E0697.
-For more information about an error, try `rustc --explain E0080`.
+Some errors have detailed explanations: E0282, E0697.
+For more information about an error, try `rustc --explain E0282`.
diff --git a/src/test/ui/consts/issue-69310-array-size-lit-wrong-ty.rs b/src/test/ui/consts/issue-69310-array-size-lit-wrong-ty.rs
index 98be8c345a9..f0d5fea8e02 100644
--- a/src/test/ui/consts/issue-69310-array-size-lit-wrong-ty.rs
+++ b/src/test/ui/consts/issue-69310-array-size-lit-wrong-ty.rs
@@ -3,7 +3,7 @@
 // we call the query `lit_to_const(input);`.
 // However, the literal `input.lit` would not be of the type expected by `input.ty`.
 // As a result, we immediately called `bug!(...)` instead of bubbling up the problem
-// so that it could be handled by the caller of `lit_to_const` (`ast_const_to_const`).
+// so that it could be handled by the caller of `lit_to_const` (`from_anon_const`).
 
 fn main() {}
 
diff --git a/src/test/ui/consts/too_generic_eval_ice.rs b/src/test/ui/consts/too_generic_eval_ice.rs
index 7a299169bc4..7e4d4dbe446 100644
--- a/src/test/ui/consts/too_generic_eval_ice.rs
+++ b/src/test/ui/consts/too_generic_eval_ice.rs
@@ -7,6 +7,7 @@ impl<A, B> Foo<A, B> {
         [5; Self::HOST_SIZE] == [6; 0] //~ ERROR no associated item named `HOST_SIZE`
         //~^ the size for values of type `A` cannot be known
         //~| the size for values of type `B` cannot be known
+        //~| binary operation `==` cannot be applied to type `[{integer}; _]`
     }
 }
 
diff --git a/src/test/ui/consts/too_generic_eval_ice.stderr b/src/test/ui/consts/too_generic_eval_ice.stderr
index 8836de0023c..ffa28225b79 100644
--- a/src/test/ui/consts/too_generic_eval_ice.stderr
+++ b/src/test/ui/consts/too_generic_eval_ice.stderr
@@ -41,7 +41,15 @@ LL |         [5; Self::HOST_SIZE] == [6; 0]
    = help: the trait `std::marker::Sized` is not implemented for `B`
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
 
-error: aborting due to 3 previous errors
+error[E0369]: binary operation `==` cannot be applied to type `[{integer}; _]`
+  --> $DIR/too_generic_eval_ice.rs:7:30
+   |
+LL |         [5; Self::HOST_SIZE] == [6; 0]
+   |         -------------------- ^^ ------ [{integer}; 0]
+   |         |
+   |         [{integer}; _]
+
+error: aborting due to 4 previous errors
 
-Some errors have detailed explanations: E0277, E0599.
+Some errors have detailed explanations: E0277, E0369, E0599.
 For more information about an error, try `rustc --explain E0277`.
diff --git a/src/test/ui/did_you_mean/bad-assoc-ty.rs b/src/test/ui/did_you_mean/bad-assoc-ty.rs
index 00845a17b11..e66b432ede2 100644
--- a/src/test/ui/did_you_mean/bad-assoc-ty.rs
+++ b/src/test/ui/did_you_mean/bad-assoc-ty.rs
@@ -49,4 +49,36 @@ trait K<A, B> {}
 fn foo<X: K<_, _>>(x: X) {}
 //~^ ERROR the type placeholder `_` is not allowed within types on item signatures
 
+fn bar<F>(_: F) where F: Fn() -> _ {}
+//~^ ERROR the type placeholder `_` is not allowed within types on item signatures
+
+fn baz<F: Fn() -> _>(_: F) {}
+//~^ ERROR the type placeholder `_` is not allowed within types on item signatures
+
+struct L<F>(F) where F: Fn() -> _;
+//~^ ERROR the type placeholder `_` is not allowed within types on item signatures
+struct M<F> where F: Fn() -> _ {
+//~^ ERROR the type placeholder `_` is not allowed within types on item signatures
+    a: F,
+}
+enum N<F> where F: Fn() -> _ {
+//~^ ERROR the type placeholder `_` is not allowed within types on item signatures
+    Foo(F),
+}
+
+union O<F> where F: Fn() -> _ {
+//~^ ERROR the type placeholder `_` is not allowed within types on item signatures
+//~| ERROR unions with non-`Copy` fields are unstable
+    foo: F,
+}
+
+trait P<F> where F: Fn() -> _ {
+//~^ ERROR the type placeholder `_` is not allowed within types on item signatures
+}
+
+trait Q {
+    fn foo<F>(_: F) where F: Fn() -> _ {}
+    //~^ ERROR the type placeholder `_` is not allowed within types on item signatures
+}
+
 fn main() {}
diff --git a/src/test/ui/did_you_mean/bad-assoc-ty.stderr b/src/test/ui/did_you_mean/bad-assoc-ty.stderr
index 6d5f3d9f143..875c02bae4a 100644
--- a/src/test/ui/did_you_mean/bad-assoc-ty.stderr
+++ b/src/test/ui/did_you_mean/bad-assoc-ty.stderr
@@ -57,6 +57,19 @@ LL | type J = ty!(u8);
    |
    = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
 
+error[E0658]: unions with non-`Copy` fields are unstable
+  --> $DIR/bad-assoc-ty.rs:69:1
+   |
+LL | / union O<F> where F: Fn() -> _ {
+LL | |
+LL | |
+LL | |     foo: F,
+LL | | }
+   | |_^
+   |
+   = note: see issue #55149 <https://github.com/rust-lang/rust/issues/55149> for more information
+   = help: add `#![feature(untagged_unions)]` to the crate attributes to enable
+
 error[E0223]: ambiguous associated type
   --> $DIR/bad-assoc-ty.rs:1:10
    |
@@ -129,8 +142,101 @@ LL | fn foo<X: K<_, _>>(x: X) {}
    |             ^  ^ not allowed in type signatures
    |             |
    |             not allowed in type signatures
+   |
+help: use type parameters instead
+   |
+LL | fn foo<X, T: K<T, T>>(x: X) {}
+   |         ^^^    ^  ^
+
+error[E0121]: the type placeholder `_` is not allowed within types on item signatures
+  --> $DIR/bad-assoc-ty.rs:52:34
+   |
+LL | fn bar<F>(_: F) where F: Fn() -> _ {}
+   |                                  ^ not allowed in type signatures
+   |
+help: use type parameters instead
+   |
+LL | fn bar<F, T>(_: F) where F: Fn() -> T {}
+   |         ^^^                         ^
+
+error[E0121]: the type placeholder `_` is not allowed within types on item signatures
+  --> $DIR/bad-assoc-ty.rs:55:19
+   |
+LL | fn baz<F: Fn() -> _>(_: F) {}
+   |                   ^ not allowed in type signatures
+   |
+help: use type parameters instead
+   |
+LL | fn baz<F, T: Fn() -> T>(_: F) {}
+   |         ^^^          ^
+
+error[E0121]: the type placeholder `_` is not allowed within types on item signatures
+  --> $DIR/bad-assoc-ty.rs:58:33
+   |
+LL | struct L<F>(F) where F: Fn() -> _;
+   |                                 ^ not allowed in type signatures
+   |
+help: use type parameters instead
+   |
+LL | struct L<F, T>(F) where F: Fn() -> T;
+   |           ^^^                      ^
+
+error[E0121]: the type placeholder `_` is not allowed within types on item signatures
+  --> $DIR/bad-assoc-ty.rs:60:30
+   |
+LL | struct M<F> where F: Fn() -> _ {
+   |                              ^ not allowed in type signatures
+   |
+help: use type parameters instead
+   |
+LL | struct M<F, T> where F: Fn() -> T {
+   |           ^^^                   ^
+
+error[E0121]: the type placeholder `_` is not allowed within types on item signatures
+  --> $DIR/bad-assoc-ty.rs:64:28
+   |
+LL | enum N<F> where F: Fn() -> _ {
+   |                            ^ not allowed in type signatures
+   |
+help: use type parameters instead
+   |
+LL | enum N<F, T> where F: Fn() -> T {
+   |         ^^^                   ^
+
+error[E0121]: the type placeholder `_` is not allowed within types on item signatures
+  --> $DIR/bad-assoc-ty.rs:69:29
+   |
+LL | union O<F> where F: Fn() -> _ {
+   |                             ^ not allowed in type signatures
+   |
+help: use type parameters instead
+   |
+LL | union O<F, T> where F: Fn() -> T {
+   |          ^^^                   ^
+
+error[E0121]: the type placeholder `_` is not allowed within types on item signatures
+  --> $DIR/bad-assoc-ty.rs:75:29
+   |
+LL | trait P<F> where F: Fn() -> _ {
+   |                             ^ not allowed in type signatures
+   |
+help: use type parameters instead
+   |
+LL | trait P<F, T> where F: Fn() -> T {
+   |          ^^^                   ^
+
+error[E0121]: the type placeholder `_` is not allowed within types on item signatures
+  --> $DIR/bad-assoc-ty.rs:80:38
+   |
+LL |     fn foo<F>(_: F) where F: Fn() -> _ {}
+   |                                      ^ not allowed in type signatures
+   |
+help: use type parameters instead
+   |
+LL |     fn foo<F, T>(_: F) where F: Fn() -> T {}
+   |             ^^^                         ^
 
-error: aborting due to 20 previous errors
+error: aborting due to 29 previous errors
 
-Some errors have detailed explanations: E0121, E0223.
+Some errors have detailed explanations: E0121, E0223, E0658.
 For more information about an error, try `rustc --explain E0121`.
diff --git a/src/test/ui/issues/issue-10656.rs b/src/test/ui/issues/issue-10656.rs
index 8918dadb47a..250c4bc442f 100644
--- a/src/test/ui/issues/issue-10656.rs
+++ b/src/test/ui/issues/issue-10656.rs
@@ -1,3 +1,3 @@
 #![deny(missing_docs)]
 #![crate_type="lib"]
-//~^^ ERROR missing documentation for crate
+//~^^ ERROR missing documentation for the crate
diff --git a/src/test/ui/issues/issue-10656.stderr b/src/test/ui/issues/issue-10656.stderr
index 2e91a598dce..2e4365f1ed7 100644
--- a/src/test/ui/issues/issue-10656.stderr
+++ b/src/test/ui/issues/issue-10656.stderr
@@ -1,4 +1,4 @@
-error: missing documentation for crate
+error: missing documentation for the crate
   --> $DIR/issue-10656.rs:1:1
    |
 LL | / #![deny(missing_docs)]
diff --git a/src/test/ui/issues/issue-39559-2.rs b/src/test/ui/issues/issue-39559-2.rs
index 3a52e4d6216..ec0275b2d6c 100644
--- a/src/test/ui/issues/issue-39559-2.rs
+++ b/src/test/ui/issues/issue-39559-2.rs
@@ -17,4 +17,5 @@ fn main() {
         = [0; Dim3::dim()];
         //~^ ERROR E0015
         //~| ERROR E0080
+        //~| ERROR mismatched types
 }
diff --git a/src/test/ui/issues/issue-39559-2.stderr b/src/test/ui/issues/issue-39559-2.stderr
index 586debbbe53..7cbf63c2da0 100644
--- a/src/test/ui/issues/issue-39559-2.stderr
+++ b/src/test/ui/issues/issue-39559-2.stderr
@@ -22,7 +22,19 @@ error[E0080]: evaluation of constant value failed
 LL |         = [0; Dim3::dim()];
    |               ^^^^^^^^^^^ calling non-const function `<Dim3 as Dim>::dim`
 
-error: aborting due to 4 previous errors
+error[E0308]: mismatched types
+  --> $DIR/issue-39559-2.rs:17:11
+   |
+LL |     let array: [usize; Dim3::dim()]
+   |                -------------------- expected due to this
+...
+LL |         = [0; Dim3::dim()];
+   |           ^^^^^^^^^^^^^^^^ expected `Dim3::dim()`, found `Dim3::dim()`
+   |
+   = note: expected array `[usize; _]`
+              found array `[usize; _]`
+
+error: aborting due to 5 previous errors
 
-Some errors have detailed explanations: E0015, E0080.
+Some errors have detailed explanations: E0015, E0080, E0308.
 For more information about an error, try `rustc --explain E0015`.
diff --git a/src/test/ui/issues/issue-52060.rs b/src/test/ui/issues/issue-52060.rs
index fed08902c8b..2688049fcc9 100644
--- a/src/test/ui/issues/issue-52060.rs
+++ b/src/test/ui/issues/issue-52060.rs
@@ -4,5 +4,6 @@ static A: &'static [u32] = &[1];
 static B: [u32; 1] = [0; A.len()];
 //~^ ERROR [E0013]
 //~| ERROR evaluation of constant value failed
+//~| ERROR mismatched types
 
 fn main() {}
diff --git a/src/test/ui/issues/issue-52060.stderr b/src/test/ui/issues/issue-52060.stderr
index 502825e9766..e076e183937 100644
--- a/src/test/ui/issues/issue-52060.stderr
+++ b/src/test/ui/issues/issue-52060.stderr
@@ -12,7 +12,16 @@ error[E0080]: evaluation of constant value failed
 LL | static B: [u32; 1] = [0; A.len()];
    |                          ^ constant accesses static
 
-error: aborting due to 2 previous errors
+error[E0308]: mismatched types
+  --> $DIR/issue-52060.rs:4:22
+   |
+LL | static B: [u32; 1] = [0; A.len()];
+   |                      ^^^^^^^^^^^^ expected `1usize`, found `A.len()`
+   |
+   = note: expected array `[u32; 1]`
+              found array `[u32; _]`
+
+error: aborting due to 3 previous errors
 
-Some errors have detailed explanations: E0013, E0080.
+Some errors have detailed explanations: E0013, E0080, E0308.
 For more information about an error, try `rustc --explain E0013`.
diff --git a/src/test/ui/issues/issue-69602-type-err-during-codegen-ice.rs b/src/test/ui/issues/issue-69602-type-err-during-codegen-ice.rs
index d060f26fb2a..2c5257ce063 100644
--- a/src/test/ui/issues/issue-69602-type-err-during-codegen-ice.rs
+++ b/src/test/ui/issues/issue-69602-type-err-during-codegen-ice.rs
@@ -19,5 +19,4 @@ impl TraitB for B { //~ ERROR not all trait items implemented, missing: `MyA`
 
 fn main() {
     let _ = [0; B::VALUE];
-    //~^ ERROR array lengths can't depend on generic parameters
 }
diff --git a/src/test/ui/issues/issue-69602-type-err-during-codegen-ice.stderr b/src/test/ui/issues/issue-69602-type-err-during-codegen-ice.stderr
index c6b2b4d27a2..8ae0f8b804c 100644
--- a/src/test/ui/issues/issue-69602-type-err-during-codegen-ice.stderr
+++ b/src/test/ui/issues/issue-69602-type-err-during-codegen-ice.stderr
@@ -13,13 +13,7 @@ LL |     type MyA: TraitA;
 LL | impl TraitB for B {
    | ^^^^^^^^^^^^^^^^^ missing `MyA` in implementation
 
-error: array lengths can't depend on generic parameters
-  --> $DIR/issue-69602-type-err-during-codegen-ice.rs:21:17
-   |
-LL |     let _ = [0; B::VALUE];
-   |                 ^^^^^^^^
-
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
 
 Some errors have detailed explanations: E0046, E0437.
 For more information about an error, try `rustc --explain E0046`.
diff --git a/src/test/ui/json-bom-plus-crlf-multifile.stderr b/src/test/ui/json-bom-plus-crlf-multifile.stderr
index 026943669f8..99f91cc8816 100644
--- a/src/test/ui/json-bom-plus-crlf-multifile.stderr
+++ b/src/test/ui/json-bom-plus-crlf-multifile.stderr
@@ -13,10 +13,10 @@ let x: i32 = \"I am not a number!\";
 ```
 
 This error occurs when the compiler was unable to infer the concrete type of a
-variable. It can occur for several cases, the most common of which is a
-mismatch in the expected type that the compiler inferred for a variable's
-initializing expression, and the actual type explicitly assigned to the
-variable.
+variable. It can happen in several cases, the most common being a mismatch
+between the type that the compiler inferred for a variable based on its
+initializing expression, on the one hand, and the type the author explicitly
+assigned to the variable, on the other hand.
 "},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":621,"byte_end":622,"line_start":17,"line_end":17,"column_start":22,"column_end":23,"is_primary":true,"text":[{"text":"    let s : String = 1;  // Error in the middle of line.","highlight_start":22,"highlight_end":23}],"label":"expected struct `std::string::String`, found integer","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":612,"byte_end":618,"line_start":17,"line_end":17,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":"    let s : String = 1;  // Error in the middle of line.","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"try using a conversion method","code":null,"level":"help","spans":[{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":621,"byte_end":622,"line_start":17,"line_end":17,"column_start":22,"column_end":23,"is_primary":true,"text":[{"text":"    let s : String = 1;  // Error in the middle of line.","highlight_start":22,"highlight_end":23}],"label":null,"suggested_replacement":"1.to_string()","suggestion_applicability":"MaybeIncorrect","expansion":null}],"children":[],"rendered":null}],"rendered":"$DIR/json-bom-plus-crlf-multifile-aux.rs:17:22: error[E0308]: mismatched types
 "}
 {"message":"mismatched types","code":{"code":"E0308","explanation":"Expected type did not match the received type.
@@ -34,10 +34,10 @@ let x: i32 = \"I am not a number!\";
 ```
 
 This error occurs when the compiler was unable to infer the concrete type of a
-variable. It can occur for several cases, the most common of which is a
-mismatch in the expected type that the compiler inferred for a variable's
-initializing expression, and the actual type explicitly assigned to the
-variable.
+variable. It can happen in several cases, the most common being a mismatch
+between the type that the compiler inferred for a variable based on its
+initializing expression, on the one hand, and the type the author explicitly
+assigned to the variable, on the other hand.
 "},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":681,"byte_end":682,"line_start":19,"line_end":19,"column_start":22,"column_end":23,"is_primary":true,"text":[{"text":"    let s : String = 1","highlight_start":22,"highlight_end":23}],"label":"expected struct `std::string::String`, found integer","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":672,"byte_end":678,"line_start":19,"line_end":19,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":"    let s : String = 1","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"try using a conversion method","code":null,"level":"help","spans":[{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":681,"byte_end":682,"line_start":19,"line_end":19,"column_start":22,"column_end":23,"is_primary":true,"text":[{"text":"    let s : String = 1","highlight_start":22,"highlight_end":23}],"label":null,"suggested_replacement":"1.to_string()","suggestion_applicability":"MaybeIncorrect","expansion":null}],"children":[],"rendered":null}],"rendered":"$DIR/json-bom-plus-crlf-multifile-aux.rs:19:22: error[E0308]: mismatched types
 "}
 {"message":"mismatched types","code":{"code":"E0308","explanation":"Expected type did not match the received type.
@@ -55,10 +55,10 @@ let x: i32 = \"I am not a number!\";
 ```
 
 This error occurs when the compiler was unable to infer the concrete type of a
-variable. It can occur for several cases, the most common of which is a
-mismatch in the expected type that the compiler inferred for a variable's
-initializing expression, and the actual type explicitly assigned to the
-variable.
+variable. It can happen in several cases, the most common being a mismatch
+between the type that the compiler inferred for a variable based on its
+initializing expression, on the one hand, and the type the author explicitly
+assigned to the variable, on the other hand.
 "},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":745,"byte_end":746,"line_start":23,"line_end":23,"column_start":1,"column_end":2,"is_primary":true,"text":[{"text":"1;  // Error after the newline.","highlight_start":1,"highlight_end":2}],"label":"expected struct `std::string::String`, found integer","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":735,"byte_end":741,"line_start":22,"line_end":22,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":"    let s : String =","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"try using a conversion method","code":null,"level":"help","spans":[{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":745,"byte_end":746,"line_start":23,"line_end":23,"column_start":1,"column_end":2,"is_primary":true,"text":[{"text":"1;  // Error after the newline.","highlight_start":1,"highlight_end":2}],"label":null,"suggested_replacement":"1.to_string()","suggestion_applicability":"MaybeIncorrect","expansion":null}],"children":[],"rendered":null}],"rendered":"$DIR/json-bom-plus-crlf-multifile-aux.rs:23:1: error[E0308]: mismatched types
 "}
 {"message":"mismatched types","code":{"code":"E0308","explanation":"Expected type did not match the received type.
@@ -76,10 +76,10 @@ let x: i32 = \"I am not a number!\";
 ```
 
 This error occurs when the compiler was unable to infer the concrete type of a
-variable. It can occur for several cases, the most common of which is a
-mismatch in the expected type that the compiler inferred for a variable's
-initializing expression, and the actual type explicitly assigned to the
-variable.
+variable. It can happen in several cases, the most common being a mismatch
+between the type that the compiler inferred for a variable based on its
+initializing expression, on the one hand, and the type the author explicitly
+assigned to the variable, on the other hand.
 "},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":801,"byte_end":809,"line_start":25,"line_end":26,"column_start":22,"column_end":6,"is_primary":true,"text":[{"text":"    let s : String = (","highlight_start":22,"highlight_end":23},{"text":"    );  // Error spanning the newline.","highlight_start":1,"highlight_end":6}],"label":"expected struct `std::string::String`, found `()`","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":792,"byte_end":798,"line_start":25,"line_end":25,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":"    let s : String = (","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[],"rendered":"$DIR/json-bom-plus-crlf-multifile-aux.rs:25:22: error[E0308]: mismatched types
 "}
 {"message":"aborting due to 4 previous errors","code":null,"level":"error","spans":[],"children":[],"rendered":"error: aborting due to 4 previous errors
diff --git a/src/test/ui/json-bom-plus-crlf.stderr b/src/test/ui/json-bom-plus-crlf.stderr
index 735a46b8c87..3e84f5ef54d 100644
--- a/src/test/ui/json-bom-plus-crlf.stderr
+++ b/src/test/ui/json-bom-plus-crlf.stderr
@@ -13,10 +13,10 @@ let x: i32 = \"I am not a number!\";
 ```
 
 This error occurs when the compiler was unable to infer the concrete type of a
-variable. It can occur for several cases, the most common of which is a
-mismatch in the expected type that the compiler inferred for a variable's
-initializing expression, and the actual type explicitly assigned to the
-variable.
+variable. It can happen in several cases, the most common being a mismatch
+between the type that the compiler inferred for a variable based on its
+initializing expression, on the one hand, and the type the author explicitly
+assigned to the variable, on the other hand.
 "},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":606,"byte_end":607,"line_start":16,"line_end":16,"column_start":22,"column_end":23,"is_primary":true,"text":[{"text":"    let s : String = 1;  // Error in the middle of line.","highlight_start":22,"highlight_end":23}],"label":"expected struct `std::string::String`, found integer","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":597,"byte_end":603,"line_start":16,"line_end":16,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":"    let s : String = 1;  // Error in the middle of line.","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"try using a conversion method","code":null,"level":"help","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":606,"byte_end":607,"line_start":16,"line_end":16,"column_start":22,"column_end":23,"is_primary":true,"text":[{"text":"    let s : String = 1;  // Error in the middle of line.","highlight_start":22,"highlight_end":23}],"label":null,"suggested_replacement":"1.to_string()","suggestion_applicability":"MaybeIncorrect","expansion":null}],"children":[],"rendered":null}],"rendered":"$DIR/json-bom-plus-crlf.rs:16:22: error[E0308]: mismatched types
 "}
 {"message":"mismatched types","code":{"code":"E0308","explanation":"Expected type did not match the received type.
@@ -34,10 +34,10 @@ let x: i32 = \"I am not a number!\";
 ```
 
 This error occurs when the compiler was unable to infer the concrete type of a
-variable. It can occur for several cases, the most common of which is a
-mismatch in the expected type that the compiler inferred for a variable's
-initializing expression, and the actual type explicitly assigned to the
-variable.
+variable. It can happen in several cases, the most common being a mismatch
+between the type that the compiler inferred for a variable based on its
+initializing expression, on the one hand, and the type the author explicitly
+assigned to the variable, on the other hand.
 "},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":666,"byte_end":667,"line_start":18,"line_end":18,"column_start":22,"column_end":23,"is_primary":true,"text":[{"text":"    let s : String = 1","highlight_start":22,"highlight_end":23}],"label":"expected struct `std::string::String`, found integer","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":657,"byte_end":663,"line_start":18,"line_end":18,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":"    let s : String = 1","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"try using a conversion method","code":null,"level":"help","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":666,"byte_end":667,"line_start":18,"line_end":18,"column_start":22,"column_end":23,"is_primary":true,"text":[{"text":"    let s : String = 1","highlight_start":22,"highlight_end":23}],"label":null,"suggested_replacement":"1.to_string()","suggestion_applicability":"MaybeIncorrect","expansion":null}],"children":[],"rendered":null}],"rendered":"$DIR/json-bom-plus-crlf.rs:18:22: error[E0308]: mismatched types
 "}
 {"message":"mismatched types","code":{"code":"E0308","explanation":"Expected type did not match the received type.
@@ -55,10 +55,10 @@ let x: i32 = \"I am not a number!\";
 ```
 
 This error occurs when the compiler was unable to infer the concrete type of a
-variable. It can occur for several cases, the most common of which is a
-mismatch in the expected type that the compiler inferred for a variable's
-initializing expression, and the actual type explicitly assigned to the
-variable.
+variable. It can happen in several cases, the most common being a mismatch
+between the type that the compiler inferred for a variable based on its
+initializing expression, on the one hand, and the type the author explicitly
+assigned to the variable, on the other hand.
 "},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":730,"byte_end":731,"line_start":22,"line_end":22,"column_start":1,"column_end":2,"is_primary":true,"text":[{"text":"1;  // Error after the newline.","highlight_start":1,"highlight_end":2}],"label":"expected struct `std::string::String`, found integer","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":720,"byte_end":726,"line_start":21,"line_end":21,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":"    let s : String =","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"try using a conversion method","code":null,"level":"help","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":730,"byte_end":731,"line_start":22,"line_end":22,"column_start":1,"column_end":2,"is_primary":true,"text":[{"text":"1;  // Error after the newline.","highlight_start":1,"highlight_end":2}],"label":null,"suggested_replacement":"1.to_string()","suggestion_applicability":"MaybeIncorrect","expansion":null}],"children":[],"rendered":null}],"rendered":"$DIR/json-bom-plus-crlf.rs:22:1: error[E0308]: mismatched types
 "}
 {"message":"mismatched types","code":{"code":"E0308","explanation":"Expected type did not match the received type.
@@ -76,10 +76,10 @@ let x: i32 = \"I am not a number!\";
 ```
 
 This error occurs when the compiler was unable to infer the concrete type of a
-variable. It can occur for several cases, the most common of which is a
-mismatch in the expected type that the compiler inferred for a variable's
-initializing expression, and the actual type explicitly assigned to the
-variable.
+variable. It can happen in several cases, the most common being a mismatch
+between the type that the compiler inferred for a variable based on its
+initializing expression, on the one hand, and the type the author explicitly
+assigned to the variable, on the other hand.
 "},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":786,"byte_end":794,"line_start":24,"line_end":25,"column_start":22,"column_end":6,"is_primary":true,"text":[{"text":"    let s : String = (","highlight_start":22,"highlight_end":23},{"text":"    );  // Error spanning the newline.","highlight_start":1,"highlight_end":6}],"label":"expected struct `std::string::String`, found `()`","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":777,"byte_end":783,"line_start":24,"line_end":24,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":"    let s : String = (","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[],"rendered":"$DIR/json-bom-plus-crlf.rs:24:22: error[E0308]: mismatched types
 "}
 {"message":"aborting due to 4 previous errors","code":null,"level":"error","spans":[],"children":[],"rendered":"error: aborting due to 4 previous errors
diff --git a/src/test/ui/lint/lint-missing-doc.rs b/src/test/ui/lint/lint-missing-doc.rs
index 77f9a3770a3..bab6f4e9e5e 100644
--- a/src/test/ui/lint/lint-missing-doc.rs
+++ b/src/test/ui/lint/lint-missing-doc.rs
@@ -50,8 +50,8 @@ trait B {
 }
 
 pub trait C { //~ ERROR: missing documentation for a trait
-    fn foo(&self); //~ ERROR: missing documentation for a trait method
-    fn foo_with_impl(&self) {} //~ ERROR: missing documentation for a trait method
+    fn foo(&self); //~ ERROR: missing documentation for an associated function
+    fn foo_with_impl(&self) {} //~ ERROR: missing documentation for an associated function
 }
 
 #[allow(missing_docs)]
@@ -78,7 +78,7 @@ impl Foo {
 }
 
 impl PubFoo {
-    pub fn foo() {} //~ ERROR: missing documentation for a method
+    pub fn foo() {} //~ ERROR: missing documentation for an associated function
     /// dox
     pub fn foo1() {}
     fn foo2() {}
diff --git a/src/test/ui/lint/lint-missing-doc.stderr b/src/test/ui/lint/lint-missing-doc.stderr
index a18a97e5f7f..21da4fae4c1 100644
--- a/src/test/ui/lint/lint-missing-doc.stderr
+++ b/src/test/ui/lint/lint-missing-doc.stderr
@@ -40,13 +40,13 @@ error: missing documentation for a trait
 LL | pub trait C {
    | ^^^^^^^^^^^
 
-error: missing documentation for a trait method
+error: missing documentation for an associated function
   --> $DIR/lint-missing-doc.rs:53:5
    |
 LL |     fn foo(&self);
    |     ^^^^^^^^^^^^^^
 
-error: missing documentation for a trait method
+error: missing documentation for an associated function
   --> $DIR/lint-missing-doc.rs:54:5
    |
 LL |     fn foo_with_impl(&self) {}
@@ -64,7 +64,7 @@ error: missing documentation for an associated type
 LL |     type AssociatedTypeDef = Self;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: missing documentation for a method
+error: missing documentation for an associated function
   --> $DIR/lint-missing-doc.rs:81:5
    |
 LL |     pub fn foo() {}
diff --git a/src/test/ui/lint/lints-in-foreign-macros.rs b/src/test/ui/lint/lints-in-foreign-macros.rs
index c96b8f1a5cf..1e8b6788a60 100644
--- a/src/test/ui/lint/lints-in-foreign-macros.rs
+++ b/src/test/ui/lint/lints-in-foreign-macros.rs
@@ -1,7 +1,7 @@
 // aux-build:lints-in-foreign-macros.rs
 // check-pass
 
-#![warn(unused_imports)] //~ missing documentation for crate [missing_docs]
+#![warn(unused_imports)] //~ missing documentation for the crate [missing_docs]
 #![warn(missing_docs)]
 
 #[macro_use]
diff --git a/src/test/ui/lint/lints-in-foreign-macros.stderr b/src/test/ui/lint/lints-in-foreign-macros.stderr
index 207d85a89c7..dcea5adb863 100644
--- a/src/test/ui/lint/lints-in-foreign-macros.stderr
+++ b/src/test/ui/lint/lints-in-foreign-macros.stderr
@@ -26,7 +26,7 @@ warning: unused import: `std::string::ToString`
 LL | mod d { baz2!(use std::string::ToString;); }
    |                   ^^^^^^^^^^^^^^^^^^^^^
 
-warning: missing documentation for crate
+warning: missing documentation for the crate
   --> $DIR/lints-in-foreign-macros.rs:4:1
    |
 LL | / #![warn(unused_imports)]
diff --git a/src/test/ui/nll/ty-outlives/projection-one-region-closure.stderr b/src/test/ui/nll/ty-outlives/projection-one-region-closure.stderr
index e8aba9d8d4d..d551ccf9cf6 100644
--- a/src/test/ui/nll/ty-outlives/projection-one-region-closure.stderr
+++ b/src/test/ui/nll/ty-outlives/projection-one-region-closure.stderr
@@ -111,7 +111,7 @@ LL |     with_signature(cell, t, |cell, t| require(cell, t));
                (),
            ]
    = note: number of external vids: 4
-   = note: where <T as Anything<ReClosureBound('_#2r)>>::AssocType: '_#3r
+   = note: where <T as Anything<ReEarlyBound(1, 'b)>>::AssocType: '_#3r
 
 note: no external requirements
   --> $DIR/projection-one-region-closure.rs:62:1
diff --git a/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.stderr b/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.stderr
index 58ea527d959..3e17de1bf0f 100644
--- a/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.stderr
+++ b/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.stderr
@@ -93,7 +93,7 @@ LL |     with_signature(cell, t, |cell, t| require(cell, t));
                (),
            ]
    = note: number of external vids: 4
-   = note: where <T as Anything<ReClosureBound('_#2r)>>::AssocType: '_#3r
+   = note: where <T as Anything<ReEarlyBound(1, 'b)>>::AssocType: '_#3r
 
 note: no external requirements
   --> $DIR/projection-one-region-trait-bound-closure.rs:52:1
diff --git a/src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.stderr b/src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.stderr
index 7c82b147394..e354f1b5f7e 100644
--- a/src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.stderr
+++ b/src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.stderr
@@ -11,7 +11,7 @@ LL |     with_signature(cell, t, |cell, t| require(cell, t));
            ]
    = note: late-bound region is '_#4r
    = note: number of external vids: 5
-   = note: where <T as Anything<ReClosureBound('_#1r), ReClosureBound('_#2r)>>::AssocType: '_#3r
+   = note: where <T as Anything<ReEarlyBound(0, 'b), ReEarlyBound(1, 'c)>>::AssocType: '_#3r
 
 note: no external requirements
   --> $DIR/projection-two-region-trait-bound-closure.rs:34:1
@@ -27,13 +27,13 @@ LL | | }
    |
    = note: defining type: no_relationships_late::<'_#1r, '_#2r, T>
 
-error[E0309]: the associated type `<T as Anything<'_#5r, '_#6r>>::AssocType` may not live long enough
+error[E0309]: the associated type `<T as Anything<ReEarlyBound(0, 'b), ReEarlyBound(1, 'c)>>::AssocType` may not live long enough
   --> $DIR/projection-two-region-trait-bound-closure.rs:38:29
    |
 LL |     with_signature(cell, t, |cell, t| require(cell, t));
    |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: consider adding an explicit lifetime bound `<T as Anything<'_#5r, '_#6r>>::AssocType: 'a`...
+   = help: consider adding an explicit lifetime bound `<T as Anything<ReEarlyBound(0, 'b), ReEarlyBound(1, 'c)>>::AssocType: 'a`...
 
 note: external requirements
   --> $DIR/projection-two-region-trait-bound-closure.rs:48:29
@@ -47,7 +47,7 @@ LL |     with_signature(cell, t, |cell, t| require(cell, t));
                (),
            ]
    = note: number of external vids: 5
-   = note: where <T as Anything<ReClosureBound('_#2r), ReClosureBound('_#3r)>>::AssocType: '_#4r
+   = note: where <T as Anything<ReEarlyBound(1, 'b), ReEarlyBound(2, 'c)>>::AssocType: '_#4r
 
 note: no external requirements
   --> $DIR/projection-two-region-trait-bound-closure.rs:43:1
@@ -63,13 +63,13 @@ LL | | }
    |
    = note: defining type: no_relationships_early::<'_#1r, '_#2r, '_#3r, T>
 
-error[E0309]: the associated type `<T as Anything<'_#6r, '_#7r>>::AssocType` may not live long enough
+error[E0309]: the associated type `<T as Anything<ReEarlyBound(1, 'b), ReEarlyBound(2, 'c)>>::AssocType` may not live long enough
   --> $DIR/projection-two-region-trait-bound-closure.rs:48:29
    |
 LL |     with_signature(cell, t, |cell, t| require(cell, t));
    |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: consider adding an explicit lifetime bound `<T as Anything<'_#6r, '_#7r>>::AssocType: 'a`...
+   = help: consider adding an explicit lifetime bound `<T as Anything<ReEarlyBound(1, 'b), ReEarlyBound(2, 'c)>>::AssocType: 'a`...
 
 note: external requirements
   --> $DIR/projection-two-region-trait-bound-closure.rs:61:29
@@ -83,7 +83,7 @@ LL |     with_signature(cell, t, |cell, t| require(cell, t));
                (),
            ]
    = note: number of external vids: 5
-   = note: where <T as Anything<ReClosureBound('_#2r), ReClosureBound('_#3r)>>::AssocType: '_#4r
+   = note: where <T as Anything<ReEarlyBound(1, 'b), ReEarlyBound(2, 'c)>>::AssocType: '_#4r
 
 note: no external requirements
   --> $DIR/projection-two-region-trait-bound-closure.rs:53:1
@@ -111,7 +111,7 @@ LL |     with_signature(cell, t, |cell, t| require(cell, t));
                (),
            ]
    = note: number of external vids: 5
-   = note: where <T as Anything<ReClosureBound('_#2r), ReClosureBound('_#3r)>>::AssocType: '_#4r
+   = note: where <T as Anything<ReEarlyBound(1, 'b), ReEarlyBound(2, 'c)>>::AssocType: '_#4r
 
 note: no external requirements
   --> $DIR/projection-two-region-trait-bound-closure.rs:65:1
@@ -139,7 +139,7 @@ LL |     with_signature(cell, t, |cell, t| require(cell, t));
                (),
            ]
    = note: number of external vids: 5
-   = note: where <T as Anything<ReClosureBound('_#2r), ReClosureBound('_#3r)>>::AssocType: '_#4r
+   = note: where <T as Anything<ReEarlyBound(1, 'b), ReEarlyBound(2, 'c)>>::AssocType: '_#4r
 
 note: no external requirements
   --> $DIR/projection-two-region-trait-bound-closure.rs:74:1
@@ -168,7 +168,7 @@ LL |     with_signature(cell, t, |cell, t| require(cell, t));
            ]
    = note: late-bound region is '_#3r
    = note: number of external vids: 4
-   = note: where <T as Anything<ReClosureBound('_#1r), ReClosureBound('_#1r)>>::AssocType: '_#2r
+   = note: where <T as Anything<ReEarlyBound(0, 'b), ReEarlyBound(0, 'b)>>::AssocType: '_#2r
 
 note: no external requirements
   --> $DIR/projection-two-region-trait-bound-closure.rs:83:1
@@ -209,7 +209,7 @@ LL |     with_signature(cell, t, |cell, t| require(cell, t));
                (),
            ]
    = note: number of external vids: 4
-   = note: where <T as Anything<ReClosureBound('_#2r), ReClosureBound('_#2r)>>::AssocType: '_#3r
+   = note: where <T as Anything<ReEarlyBound(1, 'b), ReEarlyBound(1, 'b)>>::AssocType: '_#3r
 
 note: no external requirements
   --> $DIR/projection-two-region-trait-bound-closure.rs:92:1
@@ -237,7 +237,7 @@ LL |     with_signature(cell, t, |cell, t| require(cell, t));
                (),
            ]
    = note: number of external vids: 3
-   = note: where <T as Anything<ReClosureBound('_#1r), ReClosureBound('_#1r)>>::AssocType: '_#2r
+   = note: where <T as Anything<ReEarlyBound(0, 'a), ReEarlyBound(0, 'a)>>::AssocType: '_#2r
 
 note: no external requirements
   --> $DIR/projection-two-region-trait-bound-closure.rs:101:1
diff --git a/src/test/ui/privacy/private-in-public-non-principal.rs b/src/test/ui/privacy/private-in-public-non-principal.rs
index 5d89d8105b1..b306849ac8e 100644
--- a/src/test/ui/privacy/private-in-public-non-principal.rs
+++ b/src/test/ui/privacy/private-in-public-non-principal.rs
@@ -10,7 +10,7 @@ pub fn leak_dyn_nonprincipal() -> Box<dyn PubPrincipal + PrivNonPrincipal> { loo
 #[deny(missing_docs)]
 fn container() {
     impl dyn PubPrincipal {
-        pub fn check_doc_lint() {} //~ ERROR missing documentation for a method
+        pub fn check_doc_lint() {} //~ ERROR missing documentation for an associated function
     }
     impl dyn PubPrincipal + PrivNonPrincipal {
         pub fn check_doc_lint() {} // OK, no missing doc lint
diff --git a/src/test/ui/privacy/private-in-public-non-principal.stderr b/src/test/ui/privacy/private-in-public-non-principal.stderr
index 2a41fae43c6..778c98671ad 100644
--- a/src/test/ui/privacy/private-in-public-non-principal.stderr
+++ b/src/test/ui/privacy/private-in-public-non-principal.stderr
@@ -8,7 +8,7 @@ LL | pub fn leak_dyn_nonprincipal() -> Box<dyn PubPrincipal + PrivNonPrincipal>
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #34537 <https://github.com/rust-lang/rust/issues/34537>
 
-error: missing documentation for a method
+error: missing documentation for an associated function
   --> $DIR/private-in-public-non-principal.rs:13:9
    |
 LL |         pub fn check_doc_lint() {}
diff --git a/src/test/ui/repeat_count.stderr b/src/test/ui/repeat_count.stderr
index efad00b272c..4a2d1d9f921 100644
--- a/src/test/ui/repeat_count.stderr
+++ b/src/test/ui/repeat_count.stderr
@@ -29,6 +29,12 @@ LL |     let e = [0; "foo"];
    |                 ^^^^^ expected `usize`, found `&str`
 
 error[E0308]: mismatched types
+  --> $DIR/repeat_count.rs:28:17
+   |
+LL |     let g = [0; G { g: () }];
+   |                 ^^^^^^^^^^^ expected `usize`, found struct `main::G`
+
+error[E0308]: mismatched types
   --> $DIR/repeat_count.rs:19:17
    |
 LL |     let f = [0; -4_isize];
@@ -50,12 +56,6 @@ help: you can convert an `isize` to `usize` and panic if the converted value wou
 LL |     let f = [0_usize; (-1_isize).try_into().unwrap()];
    |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error[E0308]: mismatched types
-  --> $DIR/repeat_count.rs:28:17
-   |
-LL |     let g = [0; G { g: () }];
-   |                 ^^^^^^^^^^^ expected `usize`, found struct `main::G`
-
 error: aborting due to 8 previous errors
 
 Some errors have detailed explanations: E0308, E0435.
diff --git a/src/test/ui/resolve/issue-65035-static-with-parent-generics.rs b/src/test/ui/resolve/issue-65035-static-with-parent-generics.rs
index 63d3431ec9b..708d72a2df7 100644
--- a/src/test/ui/resolve/issue-65035-static-with-parent-generics.rs
+++ b/src/test/ui/resolve/issue-65035-static-with-parent-generics.rs
@@ -24,6 +24,7 @@ fn i<const N: usize>() {
     static a: [u8; N] = [0; N];
     //~^ ERROR can't use generic parameters from outer function
     //~^^ ERROR can't use generic parameters from outer function
+    //~| ERROR mismatched types
 }
 
 fn main() {}
diff --git a/src/test/ui/resolve/issue-65035-static-with-parent-generics.stderr b/src/test/ui/resolve/issue-65035-static-with-parent-generics.stderr
index 82e2aa2db8e..97c60c72298 100644
--- a/src/test/ui/resolve/issue-65035-static-with-parent-generics.stderr
+++ b/src/test/ui/resolve/issue-65035-static-with-parent-generics.stderr
@@ -48,6 +48,16 @@ LL | #![feature(const_generics)]
    |
    = note: `#[warn(incomplete_features)]` on by default
 
-error: aborting due to 5 previous errors
+error[E0308]: mismatched types
+  --> $DIR/issue-65035-static-with-parent-generics.rs:24:25
+   |
+LL |     static a: [u8; N] = [0; N];
+   |                         ^^^^^^ expected `N`, found `N`
+   |
+   = note: expected array `[u8; _]`
+              found array `[u8; _]`
+
+error: aborting due to 6 previous errors
 
-For more information about this error, try `rustc --explain E0401`.
+Some errors have detailed explanations: E0308, E0401.
+For more information about an error, try `rustc --explain E0308`.
diff --git a/src/test/ui/typeck/typeck_type_placeholder_item.rs b/src/test/ui/typeck/typeck_type_placeholder_item.rs
index 6cd2b8c75b6..5444fc62d82 100644
--- a/src/test/ui/typeck/typeck_type_placeholder_item.rs
+++ b/src/test/ui/typeck/typeck_type_placeholder_item.rs
@@ -158,12 +158,9 @@ trait BadTrait<_> {}
 //~^ ERROR expected identifier, found reserved identifier `_`
 impl BadTrait<_> for BadStruct<_> {}
 //~^ ERROR the type placeholder `_` is not allowed within types on item signatures
-//~| ERROR the type placeholder `_` is not allowed within types on item signatures
-//~| ERROR the type placeholder `_` is not allowed within types on item signatures
 
 fn impl_trait() -> impl BadTrait<_> {
 //~^ ERROR the type placeholder `_` is not allowed within types on item signatures
-//~| ERROR the type placeholder `_` is not allowed within types on item signatures
     unimplemented!()
 }
 
@@ -178,14 +175,12 @@ struct BadStruct2<_, T>(_, T);
 
 type X = Box<_>;
 //~^ ERROR the type placeholder `_` is not allowed within types on item signatures
-//~| ERROR the type placeholder `_` is not allowed within types on item signatures
 
 struct Struct;
 trait Trait<T> {}
 impl Trait<usize> for Struct {}
 type Y = impl Trait<_>;
 //~^ ERROR the type placeholder `_` is not allowed within types on item signatures
-//~| ERROR the type placeholder `_` is not allowed within types on item signatures
 fn foo() -> Y {
     Struct
 }
diff --git a/src/test/ui/typeck/typeck_type_placeholder_item.stderr b/src/test/ui/typeck/typeck_type_placeholder_item.stderr
index dc86ab30dfe..955765e1175 100644
--- a/src/test/ui/typeck/typeck_type_placeholder_item.stderr
+++ b/src/test/ui/typeck/typeck_type_placeholder_item.stderr
@@ -11,25 +11,25 @@ LL | trait BadTrait<_> {}
    |                ^ expected identifier, found reserved identifier
 
 error: expected identifier, found reserved identifier `_`
-  --> $DIR/typeck_type_placeholder_item.rs:170:19
+  --> $DIR/typeck_type_placeholder_item.rs:167:19
    |
 LL | struct BadStruct1<_, _>(_);
    |                   ^ expected identifier, found reserved identifier
 
 error: expected identifier, found reserved identifier `_`
-  --> $DIR/typeck_type_placeholder_item.rs:170:22
+  --> $DIR/typeck_type_placeholder_item.rs:167:22
    |
 LL | struct BadStruct1<_, _>(_);
    |                      ^ expected identifier, found reserved identifier
 
 error: expected identifier, found reserved identifier `_`
-  --> $DIR/typeck_type_placeholder_item.rs:175:19
+  --> $DIR/typeck_type_placeholder_item.rs:172:19
    |
 LL | struct BadStruct2<_, T>(_, T);
    |                   ^ expected identifier, found reserved identifier
 
 error: associated constant in `impl` without body
-  --> $DIR/typeck_type_placeholder_item.rs:208:5
+  --> $DIR/typeck_type_placeholder_item.rs:203:5
    |
 LL |     const C: _;
    |     ^^^^^^^^^^-
@@ -37,7 +37,7 @@ LL |     const C: _;
    |               help: provide a definition for the constant: `= <expr>;`
 
 error[E0403]: the name `_` is already used for a generic parameter in this item's generic parameters
-  --> $DIR/typeck_type_placeholder_item.rs:170:22
+  --> $DIR/typeck_type_placeholder_item.rs:167:22
    |
 LL | struct BadStruct1<_, _>(_);
    |                   -  ^ already used
@@ -352,18 +352,6 @@ LL | struct BadStruct<T>(T);
    |                  ^  ^
 
 error[E0121]: the type placeholder `_` is not allowed within types on item signatures
-  --> $DIR/typeck_type_placeholder_item.rs:159:32
-   |
-LL | impl BadTrait<_> for BadStruct<_> {}
-   |                                ^ not allowed in type signatures
-
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures
-  --> $DIR/typeck_type_placeholder_item.rs:159:15
-   |
-LL | impl BadTrait<_> for BadStruct<_> {}
-   |               ^ not allowed in type signatures
-
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures
   --> $DIR/typeck_type_placeholder_item.rs:159:15
    |
 LL | impl BadTrait<_> for BadStruct<_> {}
@@ -377,13 +365,13 @@ LL | impl<T> BadTrait<T> for BadStruct<T> {}
    |     ^^^          ^                ^
 
 error[E0121]: the type placeholder `_` is not allowed within types on item signatures
-  --> $DIR/typeck_type_placeholder_item.rs:164:34
+  --> $DIR/typeck_type_placeholder_item.rs:162:34
    |
 LL | fn impl_trait() -> impl BadTrait<_> {
    |                                  ^ not allowed in type signatures
 
 error[E0121]: the type placeholder `_` is not allowed within types on item signatures
-  --> $DIR/typeck_type_placeholder_item.rs:170:25
+  --> $DIR/typeck_type_placeholder_item.rs:167:25
    |
 LL | struct BadStruct1<_, _>(_);
    |                         ^ not allowed in type signatures
@@ -394,7 +382,7 @@ LL | struct BadStruct1<T, _>(T);
    |                   ^     ^
 
 error[E0121]: the type placeholder `_` is not allowed within types on item signatures
-  --> $DIR/typeck_type_placeholder_item.rs:175:25
+  --> $DIR/typeck_type_placeholder_item.rs:172:25
    |
 LL | struct BadStruct2<_, T>(_, T);
    |                         ^ not allowed in type signatures
@@ -405,13 +393,7 @@ LL | struct BadStruct2<K, T>(K, T);
    |                   ^     ^
 
 error[E0121]: the type placeholder `_` is not allowed within types on item signatures
-  --> $DIR/typeck_type_placeholder_item.rs:179:14
-   |
-LL | type X = Box<_>;
-   |              ^ not allowed in type signatures
-
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures
-  --> $DIR/typeck_type_placeholder_item.rs:179:14
+  --> $DIR/typeck_type_placeholder_item.rs:176:14
    |
 LL | type X = Box<_>;
    |              ^ not allowed in type signatures
@@ -531,37 +513,25 @@ LL |         fn clone_from<T>(&mut self, other: T) { *self = FnTest9; }
    |                      ^^^                   ^
 
 error[E0121]: the type placeholder `_` is not allowed within types on item signatures
-  --> $DIR/typeck_type_placeholder_item.rs:164:34
-   |
-LL | fn impl_trait() -> impl BadTrait<_> {
-   |                                  ^ not allowed in type signatures
-
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures
-  --> $DIR/typeck_type_placeholder_item.rs:186:21
-   |
-LL | type Y = impl Trait<_>;
-   |                     ^ not allowed in type signatures
-
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures
-  --> $DIR/typeck_type_placeholder_item.rs:186:21
+  --> $DIR/typeck_type_placeholder_item.rs:182:21
    |
 LL | type Y = impl Trait<_>;
    |                     ^ not allowed in type signatures
 
 error[E0121]: the type placeholder `_` is not allowed within types on item signatures
-  --> $DIR/typeck_type_placeholder_item.rs:195:14
+  --> $DIR/typeck_type_placeholder_item.rs:190:14
    |
 LL |     type B = _;
    |              ^ not allowed in type signatures
 
 error[E0121]: the type placeholder `_` is not allowed within types on item signatures
-  --> $DIR/typeck_type_placeholder_item.rs:197:14
+  --> $DIR/typeck_type_placeholder_item.rs:192:14
    |
 LL |     const C: _;
    |              ^ not allowed in type signatures
 
 error[E0121]: the type placeholder `_` is not allowed within types on item signatures
-  --> $DIR/typeck_type_placeholder_item.rs:199:14
+  --> $DIR/typeck_type_placeholder_item.rs:194:14
    |
 LL |     const D: _ = 42;
    |              ^
@@ -606,25 +576,25 @@ LL |         fn clone(&self) -> _ { FnTest9 }
    |                            help: replace with the correct return type: `main::FnTest9`
 
 error[E0121]: the type placeholder `_` is not allowed within types on item signatures
-  --> $DIR/typeck_type_placeholder_item.rs:204:14
+  --> $DIR/typeck_type_placeholder_item.rs:199:14
    |
 LL |     type A = _;
    |              ^ not allowed in type signatures
 
 error[E0121]: the type placeholder `_` is not allowed within types on item signatures
-  --> $DIR/typeck_type_placeholder_item.rs:206:14
+  --> $DIR/typeck_type_placeholder_item.rs:201:14
    |
 LL |     type B = _;
    |              ^ not allowed in type signatures
 
 error[E0121]: the type placeholder `_` is not allowed within types on item signatures
-  --> $DIR/typeck_type_placeholder_item.rs:208:14
+  --> $DIR/typeck_type_placeholder_item.rs:203:14
    |
 LL |     const C: _;
    |              ^ not allowed in type signatures
 
 error[E0121]: the type placeholder `_` is not allowed within types on item signatures
-  --> $DIR/typeck_type_placeholder_item.rs:211:14
+  --> $DIR/typeck_type_placeholder_item.rs:206:14
    |
 LL |     const D: _ = 42;
    |              ^
@@ -632,7 +602,7 @@ LL |     const D: _ = 42;
    |              not allowed in type signatures
    |              help: replace `_` with the correct type: `i32`
 
-error: aborting due to 71 previous errors
+error: aborting due to 66 previous errors
 
 Some errors have detailed explanations: E0121, E0282, E0403.
 For more information about an error, try `rustc --explain E0121`.