about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock22
-rw-r--r--Cargo.toml1
-rw-r--r--compiler/rustc_macros/src/query.rs29
-rw-r--r--compiler/rustc_metadata/src/native_libs.rs7
-rw-r--r--compiler/rustc_middle/src/arena.rs2
-rw-r--r--compiler/rustc_middle/src/dep_graph/dep_node.rs35
-rw-r--r--compiler/rustc_middle/src/infer/canonical.rs20
-rw-r--r--compiler/rustc_middle/src/mir/interpret/mod.rs2
-rw-r--r--compiler/rustc_middle/src/mir/interpret/value.rs20
-rw-r--r--compiler/rustc_middle/src/mir/mod.rs3
-rw-r--r--compiler/rustc_middle/src/mir/syntax.rs13
-rw-r--r--compiler/rustc_middle/src/mir/terminator.rs2
-rw-r--r--compiler/rustc_middle/src/mir/type_foldable.rs204
-rw-r--r--compiler/rustc_middle/src/mir/type_visitable.rs166
-rw-r--r--compiler/rustc_middle/src/query/mod.rs3
-rw-r--r--compiler/rustc_middle/src/ty/adjustment.rs8
-rw-r--r--compiler/rustc_middle/src/ty/consts/kind.rs2
-rw-r--r--compiler/rustc_middle/src/ty/context.rs4
-rw-r--r--compiler/rustc_middle/src/ty/error.rs4
-rw-r--r--compiler/rustc_middle/src/ty/instance.rs4
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs19
-rw-r--r--compiler/rustc_middle/src/ty/structural_impls.rs478
-rw-r--r--compiler/rustc_middle/src/ty/sty.rs20
-rw-r--r--compiler/rustc_middle/src/ty/subst.rs8
-rw-r--r--compiler/rustc_mir_build/src/build/block.rs188
-rw-r--r--compiler/rustc_mir_build/src/build/matches/mod.rs40
-rw-r--r--compiler/rustc_query_impl/src/on_disk_cache.rs6
-rw-r--r--compiler/rustc_query_impl/src/plumbing.rs20
-rw-r--r--compiler/rustc_query_impl/src/profiling_support.rs8
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/confirmation.rs22
-rw-r--r--compiler/rustc_typeck/src/check/closure.rs60
-rw-r--r--compiler/rustc_typeck/src/check/region.rs35
-rw-r--r--library/core/src/ops/function.rs25
-rw-r--r--src/bootstrap/compile.rs37
-rw-r--r--src/bootstrap/test.rs2
-rw-r--r--src/bootstrap/tool.rs1
-rw-r--r--src/etc/check_missing_items.py202
-rw-r--r--src/librustdoc/html/static/css/rustdoc.css1
-rw-r--r--src/rustdoc-json-types/lib.rs4
-rw-r--r--src/test/mir-opt/retag.main-{closure#0}.SimplifyCfg-elaborate-drops.after.mir2
-rw-r--r--src/test/run-make/raw-dylib-alt-calling-convention/extern.c15
-rw-r--r--src/test/run-make/raw-dylib-alt-calling-convention/lib.rs9
-rw-r--r--src/test/run-make/raw-dylib-alt-calling-convention/output.msvc.txt1
-rw-r--r--src/test/run-make/raw-dylib-alt-calling-convention/output.txt2
-rw-r--r--src/test/run-make/raw-dylib-c/extern_1.c5
-rw-r--r--src/test/run-make/raw-dylib-c/lib.rs3
-rw-r--r--src/test/run-make/raw-dylib-c/output.txt1
-rw-r--r--src/test/run-make/raw-dylib-import-name-type/driver.rs46
-rw-r--r--src/test/run-make/raw-dylib-import-name-type/extern.c38
-rw-r--r--src/test/run-make/raw-dylib-import-name-type/extern.gnu.def3
-rw-r--r--src/test/run-make/raw-dylib-import-name-type/extern.msvc.def7
-rw-r--r--src/test/run-make/raw-dylib-import-name-type/output.txt7
-rw-r--r--src/test/rustdoc-json/type/extern.rs10
-rw-r--r--src/test/ui/async-await/async-await-let-else.no-drop-tracking.stderr2
-rw-r--r--src/test/ui/closure-expected-type/expect-fn-supply-fn.stderr12
-rw-r--r--src/test/ui/closure-expected-type/expect-two-infer-vars-supply-ty-with-bound-region.stderr2
-rw-r--r--src/test/ui/let-else/issue-99975.rs20
-rw-r--r--src/test/ui/let-else/let-else-temporary-lifetime.rs1
-rw-r--r--src/test/ui/type-alias-impl-trait/closure_args.rs16
-rw-r--r--src/test/ui/type-alias-impl-trait/closure_args2.rs23
-rw-r--r--src/test/ui/type-alias-impl-trait/issue-60371.stderr2
-rw-r--r--src/test/ui/unsized/issue-75899-but-gats.rs21
-rw-r--r--src/test/ui/unsized/issue-75899.rs18
-rw-r--r--src/tools/compiletest/src/common.rs3
-rw-r--r--src/tools/compiletest/src/main.rs2
-rw-r--r--src/tools/compiletest/src/runtest.rs7
-rw-r--r--src/tools/jsondoclint/Cargo.toml12
-rw-r--r--src/tools/jsondoclint/src/item_kind.rs184
-rw-r--r--src/tools/jsondoclint/src/json_find.rs74
-rw-r--r--src/tools/jsondoclint/src/main.rs64
-rw-r--r--src/tools/jsondoclint/src/validator.rs442
-rw-r--r--triagebot.toml4
72 files changed, 1515 insertions, 1270 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 4e0e72d3415..69f96bcbe63 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -103,9 +103,9 @@ dependencies = [
 
 [[package]]
 name = "anyhow"
-version = "1.0.60"
+version = "1.0.65"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c794e162a5eff65c72ef524dfe393eb923c354e350bb78b9c7383df13f3bc142"
+checksum = "98161a4e3e2184da77bb14f02184cdd111e83bbbcc9979dfee3c44b9a85f5602"
 
 [[package]]
 name = "array_tool"
@@ -1362,9 +1362,9 @@ dependencies = [
 
 [[package]]
 name = "fs-err"
-version = "2.5.0"
+version = "2.8.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bcd1163ae48bda72a20ae26d66a04d3094135cadab911cff418ae5e33f253431"
+checksum = "64db3e262960f0662f43a6366788d5f10f7f244b8f7d7d987f560baf5ded5c50"
 
 [[package]]
 name = "fs_extra"
@@ -1892,6 +1892,16 @@ dependencies = [
 ]
 
 [[package]]
+name = "jsondoclint"
+version = "0.1.0"
+dependencies = [
+ "anyhow",
+ "fs-err",
+ "rustdoc-json-types",
+ "serde_json",
+]
+
+[[package]]
 name = "jsonpath_lib"
 version = "0.2.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -4445,9 +4455,9 @@ dependencies = [
 
 [[package]]
 name = "serde_json"
-version = "1.0.83"
+version = "1.0.85"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "38dd04e3c8279e75b31ef29dbdceebfe5ad89f4d0937213c53f7d49d01b3d5a7"
+checksum = "e55a28e3aaef9d5ce0506d0a14dbba8054ddc7e499ef522dd8b26859ec9d4a44"
 dependencies = [
  "indexmap",
  "itoa",
diff --git a/Cargo.toml b/Cargo.toml
index 5753730053f..e49fe5e2f63 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -33,6 +33,7 @@ members = [
   "src/tools/unicode-table-generator",
   "src/tools/expand-yaml-anchors",
   "src/tools/jsondocck",
+  "src/tools/jsondoclint",
   "src/tools/html-checker",
   "src/tools/bump-stage0",
   "src/tools/replace-version-placeholder",
diff --git a/compiler/rustc_macros/src/query.rs b/compiler/rustc_macros/src/query.rs
index 742ae964f5c..d49926c90ca 100644
--- a/compiler/rustc_macros/src/query.rs
+++ b/compiler/rustc_macros/src/query.rs
@@ -289,7 +289,6 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream {
 
     let mut query_stream = quote! {};
     let mut query_description_stream = quote! {};
-    let mut dep_node_def_stream = quote! {};
     let mut cached_queries = quote! {};
 
     for query in queries.0 {
@@ -331,6 +330,10 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream {
         if modifiers.cache.is_some() {
             attributes.push(quote! { (cache) });
         }
+        // Pass on the cache modifier
+        if modifiers.cache.is_some() {
+            attributes.push(quote! { (cache) });
+        }
 
         // This uses the span of the query definition for the commas,
         // which can be important if we later encounter any ambiguity
@@ -340,45 +343,27 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream {
         // be very useful.
         let span = name.span();
         let attribute_stream = quote_spanned! {span=> #(#attributes),*};
-        let doc_comments = query.doc_comments.iter();
+        let doc_comments = &query.doc_comments;
         // Add the query to the group
         query_stream.extend(quote! {
             #(#doc_comments)*
             [#attribute_stream] fn #name(#arg) #result,
         });
 
-        // Create a dep node for the query
-        dep_node_def_stream.extend(quote! {
-            [#attribute_stream] #name(#arg),
-        });
-
         add_query_description_impl(&query, &mut query_description_stream);
     }
 
     TokenStream::from(quote! {
         #[macro_export]
         macro_rules! rustc_query_append {
-            ($macro:ident !) => {
+            ($macro:ident! $( [$($other:tt)*] )?) => {
                 $macro! {
+                    $( $($other)* )?
                     #query_stream
                 }
             }
         }
-        macro_rules! rustc_dep_node_append {
-            ($macro:ident! [$($other:tt)*]) => {
-                $macro!(
-                    $($other)*
 
-                    #dep_node_def_stream
-                );
-            }
-        }
-        #[macro_export]
-        macro_rules! rustc_cached_queries {
-            ( $macro:ident! ) => {
-                $macro!(#cached_queries);
-            }
-        }
         #[macro_export]
         macro_rules! rustc_query_description {
             #query_description_stream
diff --git a/compiler/rustc_metadata/src/native_libs.rs b/compiler/rustc_metadata/src/native_libs.rs
index cc33ad07db6..257741c13f5 100644
--- a/compiler/rustc_metadata/src/native_libs.rs
+++ b/compiler/rustc_metadata/src/native_libs.rs
@@ -560,14 +560,13 @@ impl<'tcx> Collector<'tcx> {
             }
         };
 
-        let import_name_type = self
-            .tcx
-            .codegen_fn_attrs(item.id.def_id)
+        let codegen_fn_attrs = self.tcx.codegen_fn_attrs(item.id.def_id);
+        let import_name_type = codegen_fn_attrs
             .link_ordinal
             .map_or(import_name_type, |ord| Some(PeImportNameType::Ordinal(ord)));
 
         DllImport {
-            name: item.ident.name,
+            name: codegen_fn_attrs.link_name.unwrap_or(item.ident.name),
             import_name_type,
             calling_convention,
             span: item.span,
diff --git a/compiler/rustc_middle/src/arena.rs b/compiler/rustc_middle/src/arena.rs
index 9b1fedd0b53..6bdf5a023b6 100644
--- a/compiler/rustc_middle/src/arena.rs
+++ b/compiler/rustc_middle/src/arena.rs
@@ -102,7 +102,7 @@ macro_rules! arena_types {
 
             [] dep_kind: rustc_middle::dep_graph::DepKindStruct<'tcx>,
 
-            [] trait_impl_trait_tys: rustc_data_structures::fx::FxHashMap<rustc_hir::def_id::DefId, rustc_middle::ty::Ty<'tcx>>,
+            [decode] trait_impl_trait_tys: rustc_data_structures::fx::FxHashMap<rustc_hir::def_id::DefId, rustc_middle::ty::Ty<'tcx>>,
         ]);
     )
 }
diff --git a/compiler/rustc_middle/src/dep_graph/dep_node.rs b/compiler/rustc_middle/src/dep_graph/dep_node.rs
index aae12705e3d..eded3b3eedc 100644
--- a/compiler/rustc_middle/src/dep_graph/dep_node.rs
+++ b/compiler/rustc_middle/src/dep_graph/dep_node.rs
@@ -144,11 +144,9 @@ impl DepKind {
 
 macro_rules! define_dep_nodes {
     (
-    $(
-        [$($attrs:tt)*]
-        $variant:ident $(( $tuple_arg_ty:ty $(,)? ))*
-      ,)*
-    ) => (
+     $($(#[$attr:meta])*
+        [$($modifiers:tt)*] fn $variant:ident($($K:tt)*) -> $V:ty,)*) => {
+
         #[macro_export]
         macro_rules! make_dep_kind_array {
             ($mod:ident) => {[ $($mod::$variant()),* ]};
@@ -158,7 +156,7 @@ macro_rules! define_dep_nodes {
         #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Encodable, Decodable)]
         #[allow(non_camel_case_types)]
         pub enum DepKind {
-            $($variant),*
+            $( $( #[$attr] )* $variant),*
         }
 
         fn dep_kind_from_label_string(label: &str) -> Result<DepKind, ()> {
@@ -176,24 +174,17 @@ macro_rules! define_dep_nodes {
                 pub const $variant: &str = stringify!($variant);
             )*
         }
-    );
+    };
 }
 
-rustc_dep_node_append!(define_dep_nodes![
-    // We use this for most things when incr. comp. is turned off.
-    [] Null,
-
-    // We use this to create a forever-red node.
-    [] Red,
-
-    [anon] TraitSelect,
-
-    // WARNING: if `Symbol` is changed, make sure you update `make_compile_codegen_unit` below.
-    [] CompileCodegenUnit(Symbol),
-
-    // WARNING: if `MonoItem` is changed, make sure you update `make_compile_mono_item` below.
-    // Only used by rustc_codegen_cranelift
-    [] CompileMonoItem(MonoItem),
+rustc_query_append!(define_dep_nodes![
+    /// We use this for most things when incr. comp. is turned off.
+    [] fn Null() -> (),
+    /// We use this to create a forever-red node.
+    [] fn Red() -> (),
+    [] fn TraitSelect() -> (),
+    [] fn CompileCodegenUnit() -> (),
+    [] fn CompileMonoItem() -> (),
 ]);
 
 // WARNING: `construct` is generic and does not know that `CompileCodegenUnit` takes `Symbol`s as keys.
diff --git a/compiler/rustc_middle/src/infer/canonical.rs b/compiler/rustc_middle/src/infer/canonical.rs
index e467ca13c8e..d3cf519b633 100644
--- a/compiler/rustc_middle/src/infer/canonical.rs
+++ b/compiler/rustc_middle/src/infer/canonical.rs
@@ -44,6 +44,15 @@ pub struct Canonical<'tcx, V> {
 
 pub type CanonicalVarInfos<'tcx> = &'tcx List<CanonicalVarInfo<'tcx>>;
 
+impl<'tcx> ty::TypeFoldable<'tcx> for CanonicalVarInfos<'tcx> {
+    fn try_fold_with<F: ty::FallibleTypeFolder<'tcx>>(
+        self,
+        folder: &mut F,
+    ) -> Result<Self, F::Error> {
+        ty::util::fold_list(self, folder, |tcx, v| tcx.intern_canonical_var_infos(v))
+    }
+}
+
 /// A set of values corresponding to the canonical variables from some
 /// `Canonical`. You can give these values to
 /// `canonical_value.substitute` to substitute them into the canonical
@@ -90,6 +99,7 @@ impl<'tcx> Default for OriginalQueryValues<'tcx> {
 /// a copy of the canonical value in some other inference context,
 /// with fresh inference variables replacing the canonical values.
 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, TyDecodable, TyEncodable, HashStable)]
+#[derive(TypeFoldable, TypeVisitable)]
 pub struct CanonicalVarInfo<'tcx> {
     pub kind: CanonicalVarKind<'tcx>,
 }
@@ -115,6 +125,7 @@ impl<'tcx> CanonicalVarInfo<'tcx> {
 /// in the type-theory sense of the term -- i.e., a "meta" type system
 /// that analyzes type-like values.
 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, TyDecodable, TyEncodable, HashStable)]
+#[derive(TypeFoldable, TypeVisitable)]
 pub enum CanonicalVarKind<'tcx> {
     /// Some kind of type inference variable.
     Ty(CanonicalTyVarKind),
@@ -299,14 +310,7 @@ pub type QueryOutlivesConstraint<'tcx> = (
 TrivialTypeTraversalAndLiftImpls! {
     for <'tcx> {
         crate::infer::canonical::Certainty,
-        crate::infer::canonical::CanonicalVarInfo<'tcx>,
-        crate::infer::canonical::CanonicalVarKind<'tcx>,
-    }
-}
-
-TrivialTypeTraversalImpls! {
-    for <'tcx> {
-        crate::infer::canonical::CanonicalVarInfos<'tcx>,
+        crate::infer::canonical::CanonicalTyVarKind,
     }
 }
 
diff --git a/compiler/rustc_middle/src/mir/interpret/mod.rs b/compiler/rustc_middle/src/mir/interpret/mod.rs
index 0fc1217d571..5e3dfcbcc49 100644
--- a/compiler/rustc_middle/src/mir/interpret/mod.rs
+++ b/compiler/rustc_middle/src/mir/interpret/mod.rs
@@ -137,7 +137,7 @@ pub use self::pointer::{Pointer, PointerArithmetic, Provenance};
 /// - A constant
 /// - A static
 #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, TyEncodable, TyDecodable)]
-#[derive(HashStable, Lift)]
+#[derive(HashStable, Lift, TypeFoldable, TypeVisitable)]
 pub struct GlobalId<'tcx> {
     /// For a constant or static, the `Instance` of the item itself.
     /// For a promoted global, the `Instance` of the function they belong to.
diff --git a/compiler/rustc_middle/src/mir/interpret/value.rs b/compiler/rustc_middle/src/mir/interpret/value.rs
index d4fad7f1ecd..ac5fddb7ad1 100644
--- a/compiler/rustc_middle/src/mir/interpret/value.rs
+++ b/compiler/rustc_middle/src/mir/interpret/value.rs
@@ -8,7 +8,7 @@ use rustc_apfloat::{
 use rustc_macros::HashStable;
 use rustc_target::abi::{HasDataLayout, Size};
 
-use crate::ty::{Lift, ParamEnv, ScalarInt, Ty, TyCtxt};
+use crate::ty::{ParamEnv, ScalarInt, Ty, TyCtxt};
 
 use super::{
     AllocId, AllocRange, ConstAllocation, InterpResult, Pointer, PointerArithmetic, Provenance,
@@ -27,7 +27,7 @@ pub struct ConstAlloc<'tcx> {
 /// Represents a constant value in Rust. `Scalar` and `Slice` are optimizations for
 /// array length computations, enum discriminants and the pattern matching logic.
 #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, TyEncodable, TyDecodable, Hash)]
-#[derive(HashStable)]
+#[derive(HashStable, Lift)]
 pub enum ConstValue<'tcx> {
     /// Used only for types with `layout::abi::Scalar` ABI.
     ///
@@ -53,22 +53,6 @@ pub enum ConstValue<'tcx> {
 #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
 static_assert_size!(ConstValue<'_>, 32);
 
-impl<'a, 'tcx> Lift<'tcx> for ConstValue<'a> {
-    type Lifted = ConstValue<'tcx>;
-    fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<ConstValue<'tcx>> {
-        Some(match self {
-            ConstValue::Scalar(s) => ConstValue::Scalar(s),
-            ConstValue::ZeroSized => ConstValue::ZeroSized,
-            ConstValue::Slice { data, start, end } => {
-                ConstValue::Slice { data: tcx.lift(data)?, start, end }
-            }
-            ConstValue::ByRef { alloc, offset } => {
-                ConstValue::ByRef { alloc: tcx.lift(alloc)?, offset }
-            }
-        })
-    }
-}
-
 impl<'tcx> ConstValue<'tcx> {
     #[inline]
     pub fn try_to_scalar(&self) -> Option<Scalar<AllocId>> {
diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs
index 526bb5d7285..af00118fcbe 100644
--- a/compiler/rustc_middle/src/mir/mod.rs
+++ b/compiler/rustc_middle/src/mir/mod.rs
@@ -2028,6 +2028,7 @@ impl<'tcx> Debug for Rvalue<'tcx> {
 /// particular, one must be wary of `NaN`!
 
 #[derive(Clone, Copy, PartialEq, TyEncodable, TyDecodable, Hash, HashStable)]
+#[derive(TypeFoldable, TypeVisitable)]
 pub struct Constant<'tcx> {
     pub span: Span,
 
@@ -2551,8 +2552,6 @@ impl UserTypeProjection {
     }
 }
 
-TrivialTypeTraversalAndLiftImpls! { ProjectionKind, }
-
 impl<'tcx> TypeFoldable<'tcx> for UserTypeProjection {
     fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
         Ok(UserTypeProjection {
diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs
index d2bb897b5b6..c7d0283aac9 100644
--- a/compiler/rustc_middle/src/mir/syntax.rs
+++ b/compiler/rustc_middle/src/mir/syntax.rs
@@ -488,7 +488,7 @@ pub struct CopyNonOverlapping<'tcx> {
 ///     must also be `cleanup`. This is a part of the type system and checked statically, so it is
 ///     still an error to have such an edge in the CFG even if it's known that it won't be taken at
 ///     runtime.
-#[derive(Clone, TyEncodable, TyDecodable, Hash, HashStable, PartialEq)]
+#[derive(Clone, TyEncodable, TyDecodable, Hash, HashStable, PartialEq, TypeFoldable, TypeVisitable)]
 pub enum TerminatorKind<'tcx> {
     /// Block has one successor; we continue execution there.
     Goto { target: BasicBlock },
@@ -741,7 +741,7 @@ pub enum TerminatorKind<'tcx> {
 }
 
 /// Information about an assertion failure.
-#[derive(Clone, TyEncodable, TyDecodable, Hash, HashStable, PartialEq)]
+#[derive(Clone, TyEncodable, TyDecodable, Hash, HashStable, PartialEq, TypeFoldable, TypeVisitable)]
 pub enum AssertKind<O> {
     BoundsCheck { len: O, index: O },
     Overflow(BinOp, O, O),
@@ -863,7 +863,7 @@ pub type AssertMessage<'tcx> = AssertKind<Operand<'tcx>>;
 ///
 /// Rust currently requires that every place obey those two rules. This is checked by MIRI and taken
 /// advantage of by codegen (via `gep inbounds`). That is possibly subject to change.
-#[derive(Copy, Clone, PartialEq, Eq, Hash, TyEncodable, HashStable)]
+#[derive(Copy, Clone, PartialEq, Eq, Hash, TyEncodable, HashStable, TypeFoldable, TypeVisitable)]
 pub struct Place<'tcx> {
     pub local: Local,
 
@@ -872,7 +872,7 @@ pub struct Place<'tcx> {
 }
 
 #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
-#[derive(TyEncodable, TyDecodable, HashStable)]
+#[derive(TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)]
 pub enum ProjectionElem<V, T> {
     Deref,
     Field(Field, T),
@@ -955,7 +955,7 @@ pub type PlaceElem<'tcx> = ProjectionElem<Local, Ty<'tcx>>;
 /// **Needs clarifiation:** Is loading a place that has its variant index set well-formed? Miri
 /// currently implements it, but it seems like this may be something to check against in the
 /// validator.
-#[derive(Clone, PartialEq, TyEncodable, TyDecodable, Hash, HashStable)]
+#[derive(Clone, PartialEq, TyEncodable, TyDecodable, Hash, HashStable, TypeFoldable, TypeVisitable)]
 pub enum Operand<'tcx> {
     /// Creates a value by loading the given place.
     ///
@@ -986,7 +986,7 @@ pub enum Operand<'tcx> {
 /// Computing any rvalue begins by evaluating the places and operands in some order (**Needs
 /// clarification**: Which order?). These are then used to produce a "value" - the same kind of
 /// value that an [`Operand`] produces.
-#[derive(Clone, TyEncodable, TyDecodable, Hash, HashStable, PartialEq)]
+#[derive(Clone, TyEncodable, TyDecodable, Hash, HashStable, PartialEq, TypeFoldable, TypeVisitable)]
 pub enum Rvalue<'tcx> {
     /// Yields the operand unchanged
     Use(Operand<'tcx>),
@@ -1146,6 +1146,7 @@ pub enum CastKind {
 }
 
 #[derive(Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)]
+#[derive(TypeFoldable, TypeVisitable)]
 pub enum AggregateKind<'tcx> {
     /// The type is of the element
     Array(Ty<'tcx>),
diff --git a/compiler/rustc_middle/src/mir/terminator.rs b/compiler/rustc_middle/src/mir/terminator.rs
index 02a9958525b..4ea333cff7d 100644
--- a/compiler/rustc_middle/src/mir/terminator.rs
+++ b/compiler/rustc_middle/src/mir/terminator.rs
@@ -102,7 +102,7 @@ impl<'a> Iterator for SwitchTargetsIter<'a> {
 
 impl<'a> ExactSizeIterator for SwitchTargetsIter<'a> {}
 
-#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable)]
+#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)]
 pub struct Terminator<'tcx> {
     pub source_info: SourceInfo,
     pub kind: TerminatorKind<'tcx>,
diff --git a/compiler/rustc_middle/src/mir/type_foldable.rs b/compiler/rustc_middle/src/mir/type_foldable.rs
index 82a6b0c506f..b8f8f697a9c 100644
--- a/compiler/rustc_middle/src/mir/type_foldable.rs
+++ b/compiler/rustc_middle/src/mir/type_foldable.rs
@@ -1,8 +1,9 @@
 //! `TypeFoldable` implementations for MIR types
 
+use rustc_ast::InlineAsmTemplatePiece;
+
 use super::*;
 use crate::ty;
-use rustc_data_structures::functor::IdFunctor;
 
 TrivialTypeTraversalAndLiftImpls! {
     BlockTailInfo,
@@ -13,96 +14,27 @@ TrivialTypeTraversalAndLiftImpls! {
     SourceScope,
     SourceScopeLocalData,
     UserTypeAnnotationIndex,
+    BorrowKind,
+    CastKind,
+    BinOp,
+    NullOp,
+    UnOp,
+    hir::Movability,
+    BasicBlock,
+    SwitchTargets,
+    GeneratorKind,
+    GeneratorSavedLocal,
 }
 
-impl<'tcx> TypeFoldable<'tcx> for Terminator<'tcx> {
-    fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
-        use crate::mir::TerminatorKind::*;
-
-        let kind = match self.kind {
-            Goto { target } => Goto { target },
-            SwitchInt { discr, switch_ty, targets } => SwitchInt {
-                discr: discr.try_fold_with(folder)?,
-                switch_ty: switch_ty.try_fold_with(folder)?,
-                targets,
-            },
-            Drop { place, target, unwind } => {
-                Drop { place: place.try_fold_with(folder)?, target, unwind }
-            }
-            DropAndReplace { place, value, target, unwind } => DropAndReplace {
-                place: place.try_fold_with(folder)?,
-                value: value.try_fold_with(folder)?,
-                target,
-                unwind,
-            },
-            Yield { value, resume, resume_arg, drop } => Yield {
-                value: value.try_fold_with(folder)?,
-                resume,
-                resume_arg: resume_arg.try_fold_with(folder)?,
-                drop,
-            },
-            Call { func, args, destination, target, cleanup, from_hir_call, fn_span } => Call {
-                func: func.try_fold_with(folder)?,
-                args: args.try_fold_with(folder)?,
-                destination: destination.try_fold_with(folder)?,
-                target,
-                cleanup,
-                from_hir_call,
-                fn_span,
-            },
-            Assert { cond, expected, msg, target, cleanup } => {
-                use AssertKind::*;
-                let msg = match msg {
-                    BoundsCheck { len, index } => BoundsCheck {
-                        len: len.try_fold_with(folder)?,
-                        index: index.try_fold_with(folder)?,
-                    },
-                    Overflow(op, l, r) => {
-                        Overflow(op, l.try_fold_with(folder)?, r.try_fold_with(folder)?)
-                    }
-                    OverflowNeg(op) => OverflowNeg(op.try_fold_with(folder)?),
-                    DivisionByZero(op) => DivisionByZero(op.try_fold_with(folder)?),
-                    RemainderByZero(op) => RemainderByZero(op.try_fold_with(folder)?),
-                    ResumedAfterReturn(_) | ResumedAfterPanic(_) => msg,
-                };
-                Assert { cond: cond.try_fold_with(folder)?, expected, msg, target, cleanup }
-            }
-            GeneratorDrop => GeneratorDrop,
-            Resume => Resume,
-            Abort => Abort,
-            Return => Return,
-            Unreachable => Unreachable,
-            FalseEdge { real_target, imaginary_target } => {
-                FalseEdge { real_target, imaginary_target }
-            }
-            FalseUnwind { real_target, unwind } => FalseUnwind { real_target, unwind },
-            InlineAsm { template, operands, options, line_spans, destination, cleanup } => {
-                InlineAsm {
-                    template,
-                    operands: operands.try_fold_with(folder)?,
-                    options,
-                    line_spans,
-                    destination,
-                    cleanup,
-                }
-            }
-        };
-        Ok(Terminator { source_info: self.source_info, kind })
-    }
-}
-
-impl<'tcx> TypeFoldable<'tcx> for GeneratorKind {
-    fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, _: &mut F) -> Result<Self, F::Error> {
+impl<'tcx> TypeFoldable<'tcx> for &'tcx [InlineAsmTemplatePiece] {
+    fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, _folder: &mut F) -> Result<Self, F::Error> {
         Ok(self)
     }
 }
 
-impl<'tcx> TypeFoldable<'tcx> for Place<'tcx> {
-    fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
-        Ok(Place {
-            local: self.local.try_fold_with(folder)?,
-            projection: self.projection.try_fold_with(folder)?,
-        })
+impl<'tcx> TypeFoldable<'tcx> for &'tcx [Span] {
+    fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, _folder: &mut F) -> Result<Self, F::Error> {
+        Ok(self)
     }
 }
 
@@ -112,114 +44,12 @@ impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<PlaceElem<'tcx>> {
     }
 }
 
-impl<'tcx> TypeFoldable<'tcx> for Rvalue<'tcx> {
-    fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
-        use crate::mir::Rvalue::*;
-        Ok(match self {
-            Use(op) => Use(op.try_fold_with(folder)?),
-            Repeat(op, len) => Repeat(op.try_fold_with(folder)?, len.try_fold_with(folder)?),
-            ThreadLocalRef(did) => ThreadLocalRef(did.try_fold_with(folder)?),
-            Ref(region, bk, place) => {
-                Ref(region.try_fold_with(folder)?, bk, place.try_fold_with(folder)?)
-            }
-            CopyForDeref(place) => CopyForDeref(place.try_fold_with(folder)?),
-            AddressOf(mutability, place) => AddressOf(mutability, place.try_fold_with(folder)?),
-            Len(place) => Len(place.try_fold_with(folder)?),
-            Cast(kind, op, ty) => Cast(kind, op.try_fold_with(folder)?, ty.try_fold_with(folder)?),
-            BinaryOp(op, box (rhs, lhs)) => {
-                BinaryOp(op, Box::new((rhs.try_fold_with(folder)?, lhs.try_fold_with(folder)?)))
-            }
-            CheckedBinaryOp(op, box (rhs, lhs)) => CheckedBinaryOp(
-                op,
-                Box::new((rhs.try_fold_with(folder)?, lhs.try_fold_with(folder)?)),
-            ),
-            UnaryOp(op, val) => UnaryOp(op, val.try_fold_with(folder)?),
-            Discriminant(place) => Discriminant(place.try_fold_with(folder)?),
-            NullaryOp(op, ty) => NullaryOp(op, ty.try_fold_with(folder)?),
-            Aggregate(kind, fields) => {
-                let kind = kind.try_map_id(|kind| {
-                    Ok(match kind {
-                        AggregateKind::Array(ty) => AggregateKind::Array(ty.try_fold_with(folder)?),
-                        AggregateKind::Tuple => AggregateKind::Tuple,
-                        AggregateKind::Adt(def, v, substs, user_ty, n) => AggregateKind::Adt(
-                            def,
-                            v,
-                            substs.try_fold_with(folder)?,
-                            user_ty.try_fold_with(folder)?,
-                            n,
-                        ),
-                        AggregateKind::Closure(id, substs) => {
-                            AggregateKind::Closure(id, substs.try_fold_with(folder)?)
-                        }
-                        AggregateKind::Generator(id, substs, movablity) => {
-                            AggregateKind::Generator(id, substs.try_fold_with(folder)?, movablity)
-                        }
-                    })
-                })?;
-                Aggregate(kind, fields.try_fold_with(folder)?)
-            }
-            ShallowInitBox(op, ty) => {
-                ShallowInitBox(op.try_fold_with(folder)?, ty.try_fold_with(folder)?)
-            }
-        })
-    }
-}
-
-impl<'tcx> TypeFoldable<'tcx> for Operand<'tcx> {
-    fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
-        Ok(match self {
-            Operand::Copy(place) => Operand::Copy(place.try_fold_with(folder)?),
-            Operand::Move(place) => Operand::Move(place.try_fold_with(folder)?),
-            Operand::Constant(c) => Operand::Constant(c.try_fold_with(folder)?),
-        })
-    }
-}
-
-impl<'tcx> TypeFoldable<'tcx> for PlaceElem<'tcx> {
-    fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
-        use crate::mir::ProjectionElem::*;
-
-        Ok(match self {
-            Deref => Deref,
-            Field(f, ty) => Field(f, ty.try_fold_with(folder)?),
-            Index(v) => Index(v.try_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 },
-        })
-    }
-}
-
-impl<'tcx> TypeFoldable<'tcx> for Field {
-    fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, _: &mut F) -> Result<Self, F::Error> {
-        Ok(self)
-    }
-}
-
-impl<'tcx> TypeFoldable<'tcx> for GeneratorSavedLocal {
-    fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, _: &mut F) -> Result<Self, F::Error> {
-        Ok(self)
-    }
-}
-
 impl<'tcx, R: Idx, C: Idx> TypeFoldable<'tcx> for BitMatrix<R, C> {
     fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, _: &mut F) -> Result<Self, F::Error> {
         Ok(self)
     }
 }
 
-impl<'tcx> TypeFoldable<'tcx> for Constant<'tcx> {
-    fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
-        Ok(Constant {
-            span: self.span,
-            user_ty: self.user_ty.try_fold_with(folder)?,
-            literal: self.literal.try_fold_with(folder)?,
-        })
-    }
-}
-
 impl<'tcx> TypeFoldable<'tcx> for ConstantKind<'tcx> {
     #[inline(always)]
     fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
diff --git a/compiler/rustc_middle/src/mir/type_visitable.rs b/compiler/rustc_middle/src/mir/type_visitable.rs
index 6a0801cb0dd..27a251f2f56 100644
--- a/compiler/rustc_middle/src/mir/type_visitable.rs
+++ b/compiler/rustc_middle/src/mir/type_visitable.rs
@@ -1,165 +1,6 @@
 //! `TypeVisitable` implementations for MIR types
 
 use super::*;
-use crate::ty;
-
-impl<'tcx> TypeVisitable<'tcx> for Terminator<'tcx> {
-    fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
-        use crate::mir::TerminatorKind::*;
-
-        match self.kind {
-            SwitchInt { ref discr, switch_ty, .. } => {
-                discr.visit_with(visitor)?;
-                switch_ty.visit_with(visitor)
-            }
-            Drop { ref place, .. } => place.visit_with(visitor),
-            DropAndReplace { ref place, ref value, .. } => {
-                place.visit_with(visitor)?;
-                value.visit_with(visitor)
-            }
-            Yield { ref value, .. } => value.visit_with(visitor),
-            Call { ref func, ref args, ref destination, .. } => {
-                destination.visit_with(visitor)?;
-                func.visit_with(visitor)?;
-                args.visit_with(visitor)
-            }
-            Assert { ref cond, ref msg, .. } => {
-                cond.visit_with(visitor)?;
-                use AssertKind::*;
-                match msg {
-                    BoundsCheck { ref len, ref index } => {
-                        len.visit_with(visitor)?;
-                        index.visit_with(visitor)
-                    }
-                    Overflow(_, l, r) => {
-                        l.visit_with(visitor)?;
-                        r.visit_with(visitor)
-                    }
-                    OverflowNeg(op) | DivisionByZero(op) | RemainderByZero(op) => {
-                        op.visit_with(visitor)
-                    }
-                    ResumedAfterReturn(_) | ResumedAfterPanic(_) => ControlFlow::CONTINUE,
-                }
-            }
-            InlineAsm { ref operands, .. } => operands.visit_with(visitor),
-            Goto { .. }
-            | Resume
-            | Abort
-            | Return
-            | GeneratorDrop
-            | Unreachable
-            | FalseEdge { .. }
-            | FalseUnwind { .. } => ControlFlow::CONTINUE,
-        }
-    }
-}
-
-impl<'tcx> TypeVisitable<'tcx> for GeneratorKind {
-    fn visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> ControlFlow<V::BreakTy> {
-        ControlFlow::CONTINUE
-    }
-}
-
-impl<'tcx> TypeVisitable<'tcx> for Place<'tcx> {
-    fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
-        self.local.visit_with(visitor)?;
-        self.projection.visit_with(visitor)
-    }
-}
-
-impl<'tcx> TypeVisitable<'tcx> for &'tcx ty::List<PlaceElem<'tcx>> {
-    fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
-        self.iter().try_for_each(|t| t.visit_with(visitor))
-    }
-}
-
-impl<'tcx> TypeVisitable<'tcx> for Rvalue<'tcx> {
-    fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
-        use crate::mir::Rvalue::*;
-        match *self {
-            Use(ref op) => op.visit_with(visitor),
-            CopyForDeref(ref place) => {
-                let op = &Operand::Copy(*place);
-                op.visit_with(visitor)
-            }
-            Repeat(ref op, _) => op.visit_with(visitor),
-            ThreadLocalRef(did) => did.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(_, box (ref rhs, ref lhs)) | CheckedBinaryOp(_, box (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 => {}
-                    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)
-            }
-            ShallowInitBox(ref op, ty) => {
-                op.visit_with(visitor)?;
-                ty.visit_with(visitor)
-            }
-        }
-    }
-}
-
-impl<'tcx> TypeVisitable<'tcx> for Operand<'tcx> {
-    fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
-        match *self {
-            Operand::Copy(ref place) | Operand::Move(ref place) => place.visit_with(visitor),
-            Operand::Constant(ref c) => c.visit_with(visitor),
-        }
-    }
-}
-
-impl<'tcx> TypeVisitable<'tcx> for PlaceElem<'tcx> {
-    fn visit_with<Vs: TypeVisitor<'tcx>>(&self, visitor: &mut Vs) -> ControlFlow<Vs::BreakTy> {
-        use crate::mir::ProjectionElem::*;
-
-        match self {
-            Field(_, ty) => ty.visit_with(visitor),
-            Index(v) => v.visit_with(visitor),
-            _ => ControlFlow::CONTINUE,
-        }
-    }
-}
-
-impl<'tcx> TypeVisitable<'tcx> for Field {
-    fn visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> ControlFlow<V::BreakTy> {
-        ControlFlow::CONTINUE
-    }
-}
-
-impl<'tcx> TypeVisitable<'tcx> for GeneratorSavedLocal {
-    fn visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> ControlFlow<V::BreakTy> {
-        ControlFlow::CONTINUE
-    }
-}
 
 impl<'tcx, R: Idx, C: Idx> TypeVisitable<'tcx> for BitMatrix<R, C> {
     fn visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> ControlFlow<V::BreakTy> {
@@ -167,13 +8,6 @@ impl<'tcx, R: Idx, C: Idx> TypeVisitable<'tcx> for BitMatrix<R, C> {
     }
 }
 
-impl<'tcx> TypeVisitable<'tcx> for Constant<'tcx> {
-    fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
-        self.literal.visit_with(visitor)?;
-        self.user_ty.visit_with(visitor)
-    }
-}
-
 impl<'tcx> TypeVisitable<'tcx> for ConstantKind<'tcx> {
     fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
         visitor.visit_mir_const(*self)
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index 312777230aa..53c254119f4 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -164,7 +164,8 @@ rustc_queries! {
     query collect_trait_impl_trait_tys(key: DefId)
         -> Result<&'tcx FxHashMap<DefId, Ty<'tcx>>, ErrorGuaranteed>
     {
-        desc { "better description please" }
+        desc { "compare an impl and trait method signature, inferring any hidden `impl Trait` types in the process" }
+        cache_on_disk_if { key.is_local() }
         separate_provide_extern
     }
 
diff --git a/compiler/rustc_middle/src/ty/adjustment.rs b/compiler/rustc_middle/src/ty/adjustment.rs
index d36cf2fe3f8..b809f176760 100644
--- a/compiler/rustc_middle/src/ty/adjustment.rs
+++ b/compiler/rustc_middle/src/ty/adjustment.rs
@@ -77,7 +77,7 @@ pub enum PointerCast {
 ///    At some point, of course, `Box` should move out of the compiler, in which
 ///    case this is analogous to transforming a struct. E.g., `Box<[i32; 4]>` ->
 ///    `Box<[i32]>` is an `Adjust::Unsize` with the target `Box<[i32]>`.
-#[derive(Clone, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)]
+#[derive(Clone, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable, Lift)]
 pub struct Adjustment<'tcx> {
     pub kind: Adjust<'tcx>,
     pub target: Ty<'tcx>,
@@ -89,7 +89,7 @@ impl<'tcx> Adjustment<'tcx> {
     }
 }
 
-#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)]
+#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable, Lift)]
 pub enum Adjust<'tcx> {
     /// Go from ! to any type.
     NeverToAny,
@@ -108,7 +108,7 @@ pub enum Adjust<'tcx> {
 /// The target type is `U` in both cases, with the region and mutability
 /// being those shared by both the receiver and the returned reference.
 #[derive(Copy, Clone, PartialEq, Debug, TyEncodable, TyDecodable, HashStable)]
-#[derive(TypeFoldable, TypeVisitable)]
+#[derive(TypeFoldable, TypeVisitable, Lift)]
 pub struct OverloadedDeref<'tcx> {
     pub region: ty::Region<'tcx>,
     pub mutbl: hir::Mutability,
@@ -167,7 +167,7 @@ impl From<AutoBorrowMutability> for hir::Mutability {
 }
 
 #[derive(Copy, Clone, PartialEq, Debug, TyEncodable, TyDecodable, HashStable)]
-#[derive(TypeFoldable, TypeVisitable)]
+#[derive(TypeFoldable, TypeVisitable, Lift)]
 pub enum AutoBorrow<'tcx> {
     /// Converts from T to &T.
     Ref(ty::Region<'tcx>, AutoBorrowMutability),
diff --git a/compiler/rustc_middle/src/ty/consts/kind.rs b/compiler/rustc_middle/src/ty/consts/kind.rs
index ff20da65c01..2f7352e0aff 100644
--- a/compiler/rustc_middle/src/ty/consts/kind.rs
+++ b/compiler/rustc_middle/src/ty/consts/kind.rs
@@ -50,7 +50,7 @@ impl<'tcx, P: Default> Unevaluated<'tcx, P> {
 
 /// Represents a constant in Rust.
 #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, TyEncodable, TyDecodable)]
-#[derive(Hash, HashStable)]
+#[derive(Hash, HashStable, TypeFoldable, TypeVisitable)]
 pub enum ConstKind<'tcx> {
     /// A const generic parameter.
     Param(ty::ParamConst),
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index c70478d0daa..4a9fbc5511c 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -1820,7 +1820,9 @@ nop_list_lift! {bound_variable_kinds; ty::BoundVariableKind => ty::BoundVariable
 // This is the impl for `&'a InternalSubsts<'a>`.
 nop_list_lift! {substs; GenericArg<'a> => GenericArg<'tcx>}
 
-CloneLiftImpls! { for<'tcx> { Constness, traits::WellFormedLoc, } }
+CloneLiftImpls! { for<'tcx> {
+    Constness, traits::WellFormedLoc, ImplPolarity, crate::mir::ReturnConstraint,
+} }
 
 pub mod tls {
     use super::{ptr_eq, GlobalCtxt, TyCtxt};
diff --git a/compiler/rustc_middle/src/ty/error.rs b/compiler/rustc_middle/src/ty/error.rs
index 279c8c8d6d1..01e1e97b21a 100644
--- a/compiler/rustc_middle/src/ty/error.rs
+++ b/compiler/rustc_middle/src/ty/error.rs
@@ -14,7 +14,7 @@ use rustc_target::spec::abi;
 use std::borrow::Cow;
 use std::fmt;
 
-#[derive(Clone, Copy, Debug, PartialEq, Eq, TypeFoldable, TypeVisitable)]
+#[derive(Clone, Copy, Debug, PartialEq, Eq, TypeFoldable, TypeVisitable, Lift)]
 pub struct ExpectedFound<T> {
     pub expected: T,
     pub found: T,
@@ -31,7 +31,7 @@ impl<T> ExpectedFound<T> {
 }
 
 // Data structures used in type unification
-#[derive(Copy, Clone, Debug, TypeFoldable, TypeVisitable)]
+#[derive(Copy, Clone, Debug, TypeFoldable, TypeVisitable, Lift)]
 #[rustc_pass_by_value]
 pub enum TypeError<'tcx> {
     Mismatch,
diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs
index 53218225d53..9afd6620756 100644
--- a/compiler/rustc_middle/src/ty/instance.rs
+++ b/compiler/rustc_middle/src/ty/instance.rs
@@ -20,14 +20,14 @@ use std::fmt;
 /// simply couples a potentially generic `InstanceDef` with some substs, and codegen and const eval
 /// will do all required substitution as they run.
 #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, TyEncodable, TyDecodable)]
-#[derive(HashStable, Lift)]
+#[derive(HashStable, Lift, TypeFoldable, TypeVisitable)]
 pub struct Instance<'tcx> {
     pub def: InstanceDef<'tcx>,
     pub substs: SubstsRef<'tcx>,
 }
 
 #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
-#[derive(TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)]
+#[derive(TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable, Lift)]
 pub enum InstanceDef<'tcx> {
     /// A user-defined callable item.
     ///
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index 6641ab9b756..e8fe37e7dab 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -636,7 +636,7 @@ impl rustc_errors::IntoDiagnosticArg for Predicate<'_> {
 }
 
 #[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable)]
-#[derive(HashStable, TypeFoldable, TypeVisitable)]
+#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)]
 pub enum PredicateKind<'tcx> {
     /// Corresponds to `where Foo: Bar<A, B, C>`. `Foo` here would be
     /// the `Self` type of the trait reference and `A`, `B`, and `C`
@@ -808,7 +808,7 @@ impl<'tcx> Predicate<'tcx> {
 }
 
 #[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable)]
-#[derive(HashStable, TypeFoldable, TypeVisitable)]
+#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)]
 pub struct TraitPredicate<'tcx> {
     pub trait_ref: TraitRef<'tcx>,
 
@@ -888,7 +888,7 @@ impl<'tcx> PolyTraitPredicate<'tcx> {
 }
 
 #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, TyEncodable, TyDecodable)]
-#[derive(HashStable, TypeFoldable, TypeVisitable)]
+#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)]
 pub struct OutlivesPredicate<A, B>(pub A, pub B); // `A: B`
 pub type RegionOutlivesPredicate<'tcx> = OutlivesPredicate<ty::Region<'tcx>, ty::Region<'tcx>>;
 pub type TypeOutlivesPredicate<'tcx> = OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>;
@@ -899,7 +899,7 @@ pub type PolyTypeOutlivesPredicate<'tcx> = ty::Binder<'tcx, TypeOutlivesPredicat
 /// whether the `a` type is the type that we should label as "expected" when
 /// presenting user diagnostics.
 #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, TyEncodable, TyDecodable)]
-#[derive(HashStable, TypeFoldable, TypeVisitable)]
+#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)]
 pub struct SubtypePredicate<'tcx> {
     pub a_is_expected: bool,
     pub a: Ty<'tcx>,
@@ -909,7 +909,7 @@ pub type PolySubtypePredicate<'tcx> = ty::Binder<'tcx, SubtypePredicate<'tcx>>;
 
 /// Encodes that we have to coerce *from* the `a` type to the `b` type.
 #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, TyEncodable, TyDecodable)]
-#[derive(HashStable, TypeFoldable, TypeVisitable)]
+#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)]
 pub struct CoercePredicate<'tcx> {
     pub a: Ty<'tcx>,
     pub b: Ty<'tcx>,
@@ -1058,7 +1058,7 @@ impl<'tcx> TermKind<'tcx> {
 /// Form #2 eventually yields one of these `ProjectionPredicate`
 /// instances to normalize the LHS.
 #[derive(Copy, Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable)]
-#[derive(HashStable, TypeFoldable, TypeVisitable)]
+#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)]
 pub struct ProjectionPredicate<'tcx> {
     pub projection_ty: ProjectionTy<'tcx>,
     pub term: Term<'tcx>,
@@ -1526,7 +1526,7 @@ impl<'tcx> TypeFoldable<'tcx> for ParamEnv<'tcx> {
         Ok(ParamEnv::new(
             self.caller_bounds().try_fold_with(folder)?,
             self.reveal().try_fold_with(folder)?,
-            self.constness().try_fold_with(folder)?,
+            self.constness(),
         ))
     }
 }
@@ -1534,8 +1534,7 @@ impl<'tcx> TypeFoldable<'tcx> for ParamEnv<'tcx> {
 impl<'tcx> TypeVisitable<'tcx> for ParamEnv<'tcx> {
     fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
         self.caller_bounds().visit_with(visitor)?;
-        self.reveal().visit_with(visitor)?;
-        self.constness().visit_with(visitor)
+        self.reveal().visit_with(visitor)
     }
 }
 
@@ -1692,7 +1691,7 @@ impl<'tcx> PolyTraitRef<'tcx> {
 }
 
 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, TypeFoldable, TypeVisitable)]
-#[derive(HashStable)]
+#[derive(HashStable, Lift)]
 pub struct ParamEnvAnd<'tcx, T> {
     pub param_env: ParamEnv<'tcx>,
     pub value: T,
diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs
index d7e74d675de..f5fd1f6ffaf 100644
--- a/compiler/rustc_middle/src/ty/structural_impls.rs
+++ b/compiler/rustc_middle/src/ty/structural_impls.rs
@@ -9,7 +9,6 @@ use crate::ty::print::{with_no_trimmed_paths, FmtPrinter, Printer};
 use crate::ty::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor};
 use crate::ty::{self, InferConst, Lift, Term, TermKind, Ty, TyCtxt};
 use rustc_data_structures::functor::IdFunctor;
-use rustc_hir as hir;
 use rustc_hir::def::Namespace;
 use rustc_index::vec::{Idx, IndexVec};
 
@@ -238,12 +237,24 @@ TrivialTypeTraversalAndLiftImpls! {
     crate::ty::Variance,
     ::rustc_span::Span,
     ::rustc_errors::ErrorGuaranteed,
+    Field,
+    interpret::Scalar,
+    rustc_target::abi::Size,
+    ty::DelaySpanBugEmitted,
+    rustc_type_ir::DebruijnIndex,
+    ty::BoundVar,
+    ty::Placeholder<ty::BoundVar>,
+}
+
+TrivialTypeTraversalAndLiftImpls! {
+    for<'tcx> {
+        ty::ValTree<'tcx>,
+    }
 }
 
 ///////////////////////////////////////////////////////////////////////////
 // Lift implementations
 
-// FIXME(eddyb) replace all the uses of `Option::map` with `?`.
 impl<'tcx, A: Lift<'tcx>, B: Lift<'tcx>> Lift<'tcx> for (A, B) {
     type Lifted = (A::Lifted, B::Lifted);
     fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
@@ -261,10 +272,7 @@ impl<'tcx, A: Lift<'tcx>, B: Lift<'tcx>, C: Lift<'tcx>> Lift<'tcx> for (A, B, C)
 impl<'tcx, T: Lift<'tcx>> Lift<'tcx> for Option<T> {
     type Lifted = Option<T::Lifted>;
     fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
-        match self {
-            Some(x) => tcx.lift(x).map(Some),
-            None => Some(None),
-        }
+        tcx.lift(self?).map(Some)
     }
 }
 
@@ -281,21 +289,21 @@ impl<'tcx, T: Lift<'tcx>, E: Lift<'tcx>> Lift<'tcx> for Result<T, E> {
 impl<'tcx, T: Lift<'tcx>> Lift<'tcx> for Box<T> {
     type Lifted = Box<T::Lifted>;
     fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
-        tcx.lift(*self).map(Box::new)
+        Some(Box::new(tcx.lift(*self)?))
     }
 }
 
 impl<'tcx, T: Lift<'tcx> + Clone> Lift<'tcx> for Rc<T> {
     type Lifted = Rc<T::Lifted>;
     fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
-        tcx.lift(self.as_ref().clone()).map(Rc::new)
+        Some(Rc::new(tcx.lift(self.as_ref().clone())?))
     }
 }
 
 impl<'tcx, T: Lift<'tcx> + Clone> Lift<'tcx> for Arc<T> {
     type Lifted = Arc<T::Lifted>;
     fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
-        tcx.lift(self.as_ref().clone()).map(Arc::new)
+        Some(Arc::new(tcx.lift(self.as_ref().clone())?))
     }
 }
 impl<'tcx, T: Lift<'tcx>> Lift<'tcx> for Vec<T> {
@@ -312,35 +320,6 @@ impl<'tcx, I: Idx, T: Lift<'tcx>> Lift<'tcx> for IndexVec<I, T> {
     }
 }
 
-impl<'a, 'tcx> Lift<'tcx> for ty::TraitRef<'a> {
-    type Lifted = ty::TraitRef<'tcx>;
-    fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
-        tcx.lift(self.substs).map(|substs| ty::TraitRef { def_id: self.def_id, substs })
-    }
-}
-
-impl<'a, 'tcx> Lift<'tcx> for ty::ExistentialTraitRef<'a> {
-    type Lifted = ty::ExistentialTraitRef<'tcx>;
-    fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
-        tcx.lift(self.substs).map(|substs| ty::ExistentialTraitRef { def_id: self.def_id, substs })
-    }
-}
-
-impl<'a, 'tcx> Lift<'tcx> for ty::ExistentialPredicate<'a> {
-    type Lifted = ty::ExistentialPredicate<'tcx>;
-    fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
-        match self {
-            ty::ExistentialPredicate::Trait(x) => tcx.lift(x).map(ty::ExistentialPredicate::Trait),
-            ty::ExistentialPredicate::Projection(x) => {
-                tcx.lift(x).map(ty::ExistentialPredicate::Projection)
-            }
-            ty::ExistentialPredicate::AutoTrait(def_id) => {
-                Some(ty::ExistentialPredicate::AutoTrait(def_id))
-            }
-        }
-    }
-}
-
 impl<'a, 'tcx> Lift<'tcx> for Term<'a> {
     type Lifted = ty::Term<'tcx>;
     fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
@@ -353,121 +332,6 @@ impl<'a, 'tcx> Lift<'tcx> for Term<'a> {
         )
     }
 }
-
-impl<'a, 'tcx> Lift<'tcx> for ty::TraitPredicate<'a> {
-    type Lifted = ty::TraitPredicate<'tcx>;
-    fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<ty::TraitPredicate<'tcx>> {
-        tcx.lift(self.trait_ref).map(|trait_ref| ty::TraitPredicate {
-            trait_ref,
-            constness: self.constness,
-            polarity: self.polarity,
-        })
-    }
-}
-
-impl<'a, 'tcx> Lift<'tcx> for ty::SubtypePredicate<'a> {
-    type Lifted = ty::SubtypePredicate<'tcx>;
-    fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<ty::SubtypePredicate<'tcx>> {
-        tcx.lift((self.a, self.b)).map(|(a, b)| ty::SubtypePredicate {
-            a_is_expected: self.a_is_expected,
-            a,
-            b,
-        })
-    }
-}
-
-impl<'a, 'tcx> Lift<'tcx> for ty::CoercePredicate<'a> {
-    type Lifted = ty::CoercePredicate<'tcx>;
-    fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<ty::CoercePredicate<'tcx>> {
-        tcx.lift((self.a, self.b)).map(|(a, b)| ty::CoercePredicate { a, b })
-    }
-}
-
-impl<'tcx, A: Copy + Lift<'tcx>, B: Copy + Lift<'tcx>> Lift<'tcx> for ty::OutlivesPredicate<A, B> {
-    type Lifted = ty::OutlivesPredicate<A::Lifted, B::Lifted>;
-    fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
-        tcx.lift((self.0, self.1)).map(|(a, b)| ty::OutlivesPredicate(a, b))
-    }
-}
-
-impl<'a, 'tcx> Lift<'tcx> for ty::ProjectionTy<'a> {
-    type Lifted = ty::ProjectionTy<'tcx>;
-    fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<ty::ProjectionTy<'tcx>> {
-        tcx.lift(self.substs)
-            .map(|substs| ty::ProjectionTy { item_def_id: self.item_def_id, substs })
-    }
-}
-
-impl<'a, 'tcx> Lift<'tcx> for ty::ProjectionPredicate<'a> {
-    type Lifted = ty::ProjectionPredicate<'tcx>;
-    fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<ty::ProjectionPredicate<'tcx>> {
-        tcx.lift((self.projection_ty, self.term))
-            .map(|(projection_ty, term)| ty::ProjectionPredicate { projection_ty, term })
-    }
-}
-
-impl<'a, 'tcx> Lift<'tcx> for ty::ExistentialProjection<'a> {
-    type Lifted = ty::ExistentialProjection<'tcx>;
-    fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
-        tcx.lift(self.substs).map(|substs| ty::ExistentialProjection {
-            substs,
-            term: tcx.lift(self.term).expect("type must lift when substs do"),
-            item_def_id: self.item_def_id,
-        })
-    }
-}
-
-impl<'a, 'tcx> Lift<'tcx> for ty::PredicateKind<'a> {
-    type Lifted = ty::PredicateKind<'tcx>;
-    fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
-        match self {
-            ty::PredicateKind::Trait(data) => tcx.lift(data).map(ty::PredicateKind::Trait),
-            ty::PredicateKind::Subtype(data) => tcx.lift(data).map(ty::PredicateKind::Subtype),
-            ty::PredicateKind::Coerce(data) => tcx.lift(data).map(ty::PredicateKind::Coerce),
-            ty::PredicateKind::RegionOutlives(data) => {
-                tcx.lift(data).map(ty::PredicateKind::RegionOutlives)
-            }
-            ty::PredicateKind::TypeOutlives(data) => {
-                tcx.lift(data).map(ty::PredicateKind::TypeOutlives)
-            }
-            ty::PredicateKind::Projection(data) => {
-                tcx.lift(data).map(ty::PredicateKind::Projection)
-            }
-            ty::PredicateKind::WellFormed(ty) => tcx.lift(ty).map(ty::PredicateKind::WellFormed),
-            ty::PredicateKind::ClosureKind(closure_def_id, closure_substs, kind) => {
-                tcx.lift(closure_substs).map(|closure_substs| {
-                    ty::PredicateKind::ClosureKind(closure_def_id, closure_substs, kind)
-                })
-            }
-            ty::PredicateKind::ObjectSafe(trait_def_id) => {
-                Some(ty::PredicateKind::ObjectSafe(trait_def_id))
-            }
-            ty::PredicateKind::ConstEvaluatable(uv) => {
-                tcx.lift(uv).map(|uv| ty::PredicateKind::ConstEvaluatable(uv))
-            }
-            ty::PredicateKind::ConstEquate(c1, c2) => {
-                tcx.lift((c1, c2)).map(|(c1, c2)| ty::PredicateKind::ConstEquate(c1, c2))
-            }
-            ty::PredicateKind::TypeWellFormedFromEnv(ty) => {
-                tcx.lift(ty).map(ty::PredicateKind::TypeWellFormedFromEnv)
-            }
-        }
-    }
-}
-
-impl<'a, 'tcx, T: Lift<'tcx>> Lift<'tcx> for ty::Binder<'a, T>
-where
-    <T as Lift<'tcx>>::Lifted: TypeVisitable<'tcx>,
-{
-    type Lifted = ty::Binder<'tcx, T::Lifted>;
-    fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
-        let bound_vars = tcx.lift(self.bound_vars());
-        tcx.lift(self.skip_binder())
-            .zip(bound_vars)
-            .map(|(value, vars)| ty::Binder::bind_with_vars(value, vars))
-    }
-}
-
 impl<'a, 'tcx> Lift<'tcx> for ty::ParamEnv<'a> {
     type Lifted = ty::ParamEnv<'tcx>;
     fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
@@ -476,192 +340,6 @@ impl<'a, 'tcx> Lift<'tcx> for ty::ParamEnv<'a> {
     }
 }
 
-impl<'a, 'tcx, T: Lift<'tcx>> Lift<'tcx> for ty::ParamEnvAnd<'a, T> {
-    type Lifted = ty::ParamEnvAnd<'tcx, T::Lifted>;
-    fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
-        tcx.lift(self.param_env).and_then(|param_env| {
-            tcx.lift(self.value).map(|value| ty::ParamEnvAnd { param_env, value })
-        })
-    }
-}
-
-impl<'a, 'tcx> Lift<'tcx> for ty::ClosureSubsts<'a> {
-    type Lifted = ty::ClosureSubsts<'tcx>;
-    fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
-        tcx.lift(self.substs).map(|substs| ty::ClosureSubsts { substs })
-    }
-}
-
-impl<'a, 'tcx> Lift<'tcx> for ty::GeneratorSubsts<'a> {
-    type Lifted = ty::GeneratorSubsts<'tcx>;
-    fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
-        tcx.lift(self.substs).map(|substs| ty::GeneratorSubsts { substs })
-    }
-}
-
-impl<'a, 'tcx> Lift<'tcx> for ty::adjustment::Adjustment<'a> {
-    type Lifted = ty::adjustment::Adjustment<'tcx>;
-    fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
-        let ty::adjustment::Adjustment { kind, target } = self;
-        tcx.lift(kind).and_then(|kind| {
-            tcx.lift(target).map(|target| ty::adjustment::Adjustment { kind, target })
-        })
-    }
-}
-
-impl<'a, 'tcx> Lift<'tcx> for ty::adjustment::Adjust<'a> {
-    type Lifted = ty::adjustment::Adjust<'tcx>;
-    fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
-        match self {
-            ty::adjustment::Adjust::NeverToAny => Some(ty::adjustment::Adjust::NeverToAny),
-            ty::adjustment::Adjust::Pointer(ptr) => Some(ty::adjustment::Adjust::Pointer(ptr)),
-            ty::adjustment::Adjust::Deref(overloaded) => {
-                tcx.lift(overloaded).map(ty::adjustment::Adjust::Deref)
-            }
-            ty::adjustment::Adjust::Borrow(autoref) => {
-                tcx.lift(autoref).map(ty::adjustment::Adjust::Borrow)
-            }
-        }
-    }
-}
-
-impl<'a, 'tcx> Lift<'tcx> for ty::adjustment::OverloadedDeref<'a> {
-    type Lifted = ty::adjustment::OverloadedDeref<'tcx>;
-    fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
-        tcx.lift(self.region).map(|region| ty::adjustment::OverloadedDeref {
-            region,
-            mutbl: self.mutbl,
-            span: self.span,
-        })
-    }
-}
-
-impl<'a, 'tcx> Lift<'tcx> for ty::adjustment::AutoBorrow<'a> {
-    type Lifted = ty::adjustment::AutoBorrow<'tcx>;
-    fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
-        match self {
-            ty::adjustment::AutoBorrow::Ref(r, m) => {
-                tcx.lift(r).map(|r| ty::adjustment::AutoBorrow::Ref(r, m))
-            }
-            ty::adjustment::AutoBorrow::RawPtr(m) => Some(ty::adjustment::AutoBorrow::RawPtr(m)),
-        }
-    }
-}
-
-impl<'a, 'tcx> Lift<'tcx> for ty::GenSig<'a> {
-    type Lifted = ty::GenSig<'tcx>;
-    fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
-        tcx.lift((self.resume_ty, self.yield_ty, self.return_ty))
-            .map(|(resume_ty, yield_ty, return_ty)| ty::GenSig { resume_ty, yield_ty, return_ty })
-    }
-}
-
-impl<'a, 'tcx> Lift<'tcx> for ty::FnSig<'a> {
-    type Lifted = ty::FnSig<'tcx>;
-    fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
-        tcx.lift(self.inputs_and_output).map(|x| ty::FnSig {
-            inputs_and_output: x,
-            c_variadic: self.c_variadic,
-            unsafety: self.unsafety,
-            abi: self.abi,
-        })
-    }
-}
-
-impl<'tcx, T: Lift<'tcx>> Lift<'tcx> for ty::error::ExpectedFound<T> {
-    type Lifted = ty::error::ExpectedFound<T::Lifted>;
-    fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
-        let ty::error::ExpectedFound { expected, found } = self;
-        tcx.lift(expected).and_then(|expected| {
-            tcx.lift(found).map(|found| ty::error::ExpectedFound { expected, found })
-        })
-    }
-}
-
-impl<'a, 'tcx> Lift<'tcx> for ty::error::TypeError<'a> {
-    type Lifted = ty::error::TypeError<'tcx>;
-    fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
-        use crate::ty::error::TypeError::*;
-
-        Some(match self {
-            Mismatch => Mismatch,
-            ConstnessMismatch(x) => ConstnessMismatch(x),
-            PolarityMismatch(x) => PolarityMismatch(x),
-            UnsafetyMismatch(x) => UnsafetyMismatch(x),
-            AbiMismatch(x) => AbiMismatch(x),
-            Mutability => Mutability,
-            ArgumentMutability(i) => ArgumentMutability(i),
-            TupleSize(x) => TupleSize(x),
-            FixedArraySize(x) => FixedArraySize(x),
-            ArgCount => ArgCount,
-            FieldMisMatch(x, y) => FieldMisMatch(x, y),
-            RegionsDoesNotOutlive(a, b) => {
-                return tcx.lift((a, b)).map(|(a, b)| RegionsDoesNotOutlive(a, b));
-            }
-            RegionsInsufficientlyPolymorphic(a, b) => {
-                return tcx.lift(b).map(|b| RegionsInsufficientlyPolymorphic(a, b));
-            }
-            RegionsOverlyPolymorphic(a, b) => {
-                return tcx.lift(b).map(|b| RegionsOverlyPolymorphic(a, b));
-            }
-            RegionsPlaceholderMismatch => RegionsPlaceholderMismatch,
-            IntMismatch(x) => IntMismatch(x),
-            FloatMismatch(x) => FloatMismatch(x),
-            Traits(x) => Traits(x),
-            VariadicMismatch(x) => VariadicMismatch(x),
-            CyclicTy(t) => return tcx.lift(t).map(|t| CyclicTy(t)),
-            CyclicConst(ct) => return tcx.lift(ct).map(|ct| CyclicConst(ct)),
-            ProjectionMismatched(x) => ProjectionMismatched(x),
-            ArgumentSorts(x, i) => return tcx.lift(x).map(|x| ArgumentSorts(x, i)),
-            Sorts(x) => return tcx.lift(x).map(Sorts),
-            ExistentialMismatch(x) => return tcx.lift(x).map(ExistentialMismatch),
-            ConstMismatch(x) => return tcx.lift(x).map(ConstMismatch),
-            IntrinsicCast => IntrinsicCast,
-            TargetFeatureCast(x) => TargetFeatureCast(x),
-            ObjectUnsafeCoercion(x) => return tcx.lift(x).map(ObjectUnsafeCoercion),
-        })
-    }
-}
-
-impl<'a, 'tcx> Lift<'tcx> for ty::InstanceDef<'a> {
-    type Lifted = ty::InstanceDef<'tcx>;
-    fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
-        match self {
-            ty::InstanceDef::Item(def_id) => Some(ty::InstanceDef::Item(def_id)),
-            ty::InstanceDef::VTableShim(def_id) => Some(ty::InstanceDef::VTableShim(def_id)),
-            ty::InstanceDef::ReifyShim(def_id) => Some(ty::InstanceDef::ReifyShim(def_id)),
-            ty::InstanceDef::Intrinsic(def_id) => Some(ty::InstanceDef::Intrinsic(def_id)),
-            ty::InstanceDef::FnPtrShim(def_id, ty) => {
-                Some(ty::InstanceDef::FnPtrShim(def_id, tcx.lift(ty)?))
-            }
-            ty::InstanceDef::Virtual(def_id, n) => Some(ty::InstanceDef::Virtual(def_id, n)),
-            ty::InstanceDef::ClosureOnceShim { call_once, track_caller } => {
-                Some(ty::InstanceDef::ClosureOnceShim { call_once, track_caller })
-            }
-            ty::InstanceDef::DropGlue(def_id, ty) => {
-                Some(ty::InstanceDef::DropGlue(def_id, tcx.lift(ty)?))
-            }
-            ty::InstanceDef::CloneShim(def_id, ty) => {
-                Some(ty::InstanceDef::CloneShim(def_id, tcx.lift(ty)?))
-            }
-        }
-    }
-}
-
-impl<'tcx> Lift<'tcx> for Field {
-    type Lifted = Field;
-    fn lift_to_tcx(self, _tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
-        Some(self)
-    }
-}
-
-impl<'tcx> Lift<'tcx> for crate::mir::ReturnConstraint {
-    type Lifted = crate::mir::ReturnConstraint;
-    fn lift_to_tcx(self, _tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
-        Some(self)
-    }
-}
-
 ///////////////////////////////////////////////////////////////////////////
 // TypeFoldable implementations.
 
@@ -924,88 +602,12 @@ impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<ty::Binder<'tcx, ty::Existentia
     }
 }
 
-impl<'tcx> TypeVisitable<'tcx>
-    for &'tcx ty::List<ty::Binder<'tcx, ty::ExistentialPredicate<'tcx>>>
-{
-    fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
-        self.iter().try_for_each(|p| p.visit_with(visitor))
-    }
-}
-
 impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<ProjectionKind> {
     fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
         ty::util::fold_list(self, folder, |tcx, v| tcx.intern_projs(v))
     }
 }
 
-impl<'tcx> TypeVisitable<'tcx> for &'tcx ty::List<ProjectionKind> {
-    fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
-        self.iter().try_for_each(|t| t.visit_with(visitor))
-    }
-}
-
-impl<'tcx> TypeFoldable<'tcx> for ty::instance::Instance<'tcx> {
-    fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
-        use crate::ty::InstanceDef::*;
-        Ok(Self {
-            substs: self.substs.try_fold_with(folder)?,
-            def: match self.def {
-                Item(def) => Item(def.try_fold_with(folder)?),
-                VTableShim(did) => VTableShim(did.try_fold_with(folder)?),
-                ReifyShim(did) => ReifyShim(did.try_fold_with(folder)?),
-                Intrinsic(did) => Intrinsic(did.try_fold_with(folder)?),
-                FnPtrShim(did, ty) => {
-                    FnPtrShim(did.try_fold_with(folder)?, ty.try_fold_with(folder)?)
-                }
-                Virtual(did, i) => Virtual(did.try_fold_with(folder)?, i),
-                ClosureOnceShim { call_once, track_caller } => {
-                    ClosureOnceShim { call_once: call_once.try_fold_with(folder)?, track_caller }
-                }
-                DropGlue(did, ty) => {
-                    DropGlue(did.try_fold_with(folder)?, ty.try_fold_with(folder)?)
-                }
-                CloneShim(did, ty) => {
-                    CloneShim(did.try_fold_with(folder)?, ty.try_fold_with(folder)?)
-                }
-            },
-        })
-    }
-}
-
-impl<'tcx> TypeVisitable<'tcx> for ty::instance::Instance<'tcx> {
-    fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
-        use crate::ty::InstanceDef::*;
-        self.substs.visit_with(visitor)?;
-        match self.def {
-            Item(def) => def.visit_with(visitor),
-            VTableShim(did) | ReifyShim(did) | Intrinsic(did) | Virtual(did, _) => {
-                did.visit_with(visitor)
-            }
-            FnPtrShim(did, ty) | CloneShim(did, ty) => {
-                did.visit_with(visitor)?;
-                ty.visit_with(visitor)
-            }
-            DropGlue(did, ty) => {
-                did.visit_with(visitor)?;
-                ty.visit_with(visitor)
-            }
-            ClosureOnceShim { call_once, track_caller: _ } => call_once.visit_with(visitor),
-        }
-    }
-}
-
-impl<'tcx> TypeFoldable<'tcx> for interpret::GlobalId<'tcx> {
-    fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
-        Ok(Self { instance: self.instance.try_fold_with(folder)?, promoted: self.promoted })
-    }
-}
-
-impl<'tcx> TypeVisitable<'tcx> for interpret::GlobalId<'tcx> {
-    fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
-        self.instance.visit_with(visitor)
-    }
-}
-
 impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> {
     fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
         folder.try_fold_ty(self)
@@ -1181,12 +783,6 @@ impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<ty::Predicate<'tcx>> {
     }
 }
 
-impl<'tcx> TypeVisitable<'tcx> for &'tcx ty::List<ty::Predicate<'tcx>> {
-    fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
-        self.iter().try_for_each(|p| p.visit_with(visitor))
-    }
-}
-
 impl<'tcx, T: TypeFoldable<'tcx>, I: Idx> TypeFoldable<'tcx> for IndexVec<I, T> {
     fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
         self.try_map_id(|x| x.try_fold_with(folder))
@@ -1233,34 +829,6 @@ impl<'tcx> TypeSuperVisitable<'tcx> for ty::Const<'tcx> {
     }
 }
 
-impl<'tcx> TypeFoldable<'tcx> for ty::ConstKind<'tcx> {
-    fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
-        Ok(match self {
-            ty::ConstKind::Infer(ic) => ty::ConstKind::Infer(ic.try_fold_with(folder)?),
-            ty::ConstKind::Param(p) => ty::ConstKind::Param(p.try_fold_with(folder)?),
-            ty::ConstKind::Unevaluated(uv) => ty::ConstKind::Unevaluated(uv.try_fold_with(folder)?),
-            ty::ConstKind::Value(_)
-            | ty::ConstKind::Bound(..)
-            | ty::ConstKind::Placeholder(..)
-            | ty::ConstKind::Error(_) => self,
-        })
-    }
-}
-
-impl<'tcx> TypeVisitable<'tcx> for ty::ConstKind<'tcx> {
-    fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
-        match *self {
-            ty::ConstKind::Infer(ic) => ic.visit_with(visitor),
-            ty::ConstKind::Param(p) => p.visit_with(visitor),
-            ty::ConstKind::Unevaluated(uv) => uv.visit_with(visitor),
-            ty::ConstKind::Value(_)
-            | ty::ConstKind::Bound(..)
-            | ty::ConstKind::Placeholder(_)
-            | ty::ConstKind::Error(_) => ControlFlow::CONTINUE,
-        }
-    }
-}
-
 impl<'tcx> TypeFoldable<'tcx> for InferConst<'tcx> {
     fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, _folder: &mut F) -> Result<Self, F::Error> {
         Ok(self)
@@ -1315,15 +883,3 @@ impl<'tcx> TypeVisitable<'tcx> for ty::Unevaluated<'tcx, ()> {
         self.expand().visit_with(visitor)
     }
 }
-
-impl<'tcx> TypeFoldable<'tcx> for hir::Constness {
-    fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, _: &mut F) -> Result<Self, F::Error> {
-        Ok(self)
-    }
-}
-
-impl<'tcx> TypeVisitable<'tcx> for hir::Constness {
-    fn visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> ControlFlow<V::BreakTy> {
-        ControlFlow::CONTINUE
-    }
-}
diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs
index 18169045c90..36e56085039 100644
--- a/compiler/rustc_middle/src/ty/sty.rs
+++ b/compiler/rustc_middle/src/ty/sty.rs
@@ -202,7 +202,7 @@ static_assert_size!(TyKind<'_>, 32);
 /// * `GR`: The "return type", which is the type of value returned upon
 ///   completion of the generator.
 /// * `GW`: The "generator witness".
-#[derive(Copy, Clone, Debug, TypeFoldable, TypeVisitable)]
+#[derive(Copy, Clone, Debug, TypeFoldable, TypeVisitable, Lift)]
 pub struct ClosureSubsts<'tcx> {
     /// Lifetime and type parameters from the enclosing function,
     /// concatenated with a tuple containing the types of the upvars.
@@ -333,7 +333,7 @@ impl<'tcx> ClosureSubsts<'tcx> {
 }
 
 /// Similar to `ClosureSubsts`; see the above documentation for more.
-#[derive(Copy, Clone, Debug, TypeFoldable, TypeVisitable)]
+#[derive(Copy, Clone, Debug, TypeFoldable, TypeVisitable, Lift)]
 pub struct GeneratorSubsts<'tcx> {
     pub substs: SubstsRef<'tcx>,
 }
@@ -660,7 +660,7 @@ impl<'tcx> InlineConstSubsts<'tcx> {
 }
 
 #[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Ord, Eq, Hash, TyEncodable, TyDecodable)]
-#[derive(HashStable, TypeFoldable, TypeVisitable)]
+#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)]
 pub enum ExistentialPredicate<'tcx> {
     /// E.g., `Iterator`.
     Trait(ExistentialTraitRef<'tcx>),
@@ -789,7 +789,7 @@ impl<'tcx> List<ty::Binder<'tcx, ExistentialPredicate<'tcx>>> {
 /// Trait references also appear in object types like `Foo<U>`, but in
 /// that case the `Self` parameter is absent from the substitutions.
 #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, TyEncodable, TyDecodable)]
-#[derive(HashStable, TypeFoldable, TypeVisitable)]
+#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)]
 pub struct TraitRef<'tcx> {
     pub def_id: DefId,
     pub substs: SubstsRef<'tcx>,
@@ -867,7 +867,7 @@ impl rustc_errors::IntoDiagnosticArg for PolyTraitRef<'_> {
 /// The substitutions don't include the erased `Self`, only trait
 /// type and lifetime parameters (`[X, Y]` and `['a, 'b]` above).
 #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, TyEncodable, TyDecodable)]
-#[derive(HashStable, TypeFoldable, TypeVisitable)]
+#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)]
 pub struct ExistentialTraitRef<'tcx> {
     pub def_id: DefId,
     pub substs: SubstsRef<'tcx>,
@@ -1023,7 +1023,7 @@ impl BoundVariableKind {
 ///
 /// `Decodable` and `Encodable` are implemented for `Binder<T>` using the `impl_binder_encode_decode!` macro.
 #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
-#[derive(HashStable)]
+#[derive(HashStable, Lift)]
 pub struct Binder<'tcx, T>(T, &'tcx List<BoundVariableKind>);
 
 impl<'tcx, T> Binder<'tcx, T>
@@ -1185,7 +1185,7 @@ impl<'tcx, T> Binder<'tcx, Option<T>> {
 /// Represents the projection of an associated type. In explicit UFCS
 /// form this would be written `<T as Trait<..>>::N`.
 #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, TyEncodable, TyDecodable)]
-#[derive(HashStable, TypeFoldable, TypeVisitable)]
+#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)]
 pub struct ProjectionTy<'tcx> {
     /// The parameters of the associated item.
     pub substs: SubstsRef<'tcx>,
@@ -1237,7 +1237,7 @@ impl<'tcx> ProjectionTy<'tcx> {
     }
 }
 
-#[derive(Copy, Clone, Debug, TypeFoldable, TypeVisitable)]
+#[derive(Copy, Clone, Debug, TypeFoldable, TypeVisitable, Lift)]
 pub struct GenSig<'tcx> {
     pub resume_ty: Ty<'tcx>,
     pub yield_ty: Ty<'tcx>,
@@ -1253,7 +1253,7 @@ pub type PolyGenSig<'tcx> = Binder<'tcx, GenSig<'tcx>>;
 /// - `output`: is the return type.
 /// - `c_variadic`: indicates whether this is a C-variadic function.
 #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, TyEncodable, TyDecodable)]
-#[derive(HashStable, TypeFoldable, TypeVisitable)]
+#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)]
 pub struct FnSig<'tcx> {
     pub inputs_and_output: &'tcx List<Ty<'tcx>>,
     pub c_variadic: bool,
@@ -1435,7 +1435,7 @@ impl From<BoundVar> for BoundTy {
 
 /// A `ProjectionPredicate` for an `ExistentialTraitRef`.
 #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, TyEncodable, TyDecodable)]
-#[derive(HashStable, TypeFoldable, TypeVisitable)]
+#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)]
 pub struct ExistentialProjection<'tcx> {
     pub item_def_id: DefId,
     pub substs: SubstsRef<'tcx>,
diff --git a/compiler/rustc_middle/src/ty/subst.rs b/compiler/rustc_middle/src/ty/subst.rs
index 6262aa18075..8e69bf067d0 100644
--- a/compiler/rustc_middle/src/ty/subst.rs
+++ b/compiler/rustc_middle/src/ty/subst.rs
@@ -459,12 +459,6 @@ impl<'tcx> TypeFoldable<'tcx> for SubstsRef<'tcx> {
     }
 }
 
-impl<'tcx> TypeVisitable<'tcx> for SubstsRef<'tcx> {
-    fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
-        self.iter().try_for_each(|t| t.visit_with(visitor))
-    }
-}
-
 impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<Ty<'tcx>> {
     fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
         // This code is fairly hot, though not as hot as `SubstsRef`.
@@ -497,7 +491,7 @@ impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<Ty<'tcx>> {
     }
 }
 
-impl<'tcx> TypeVisitable<'tcx> for &'tcx ty::List<Ty<'tcx>> {
+impl<'tcx, T: TypeVisitable<'tcx>> TypeVisitable<'tcx> for &'tcx ty::List<T> {
     fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
         self.iter().try_for_each(|t| t.visit_with(visitor))
     }
diff --git a/compiler/rustc_mir_build/src/build/block.rs b/compiler/rustc_mir_build/src/build/block.rs
index c8d4a1bf2c9..7ab7870c464 100644
--- a/compiler/rustc_mir_build/src/build/block.rs
+++ b/compiler/rustc_mir_build/src/build/block.rs
@@ -112,10 +112,167 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 StmtKind::Let {
                     remainder_scope,
                     init_scope,
+                    pattern,
+                    initializer: Some(initializer),
+                    lint_level,
+                    else_block: Some(else_block),
+                } => {
+                    // When lowering the statement `let <pat> = <expr> else { <else> };`,
+                    // the `<else>` block is nested in the parent scope enclosing this statment.
+                    // That scope is usually either the enclosing block scope,
+                    // or the remainder scope of the last statement.
+                    // This is to make sure that temporaries instantiated in `<expr>` are dropped
+                    // as well.
+                    // In addition, even though bindings in `<pat>` only come into scope if
+                    // the pattern matching passes, in the MIR building the storages for them
+                    // are declared as live any way.
+                    // This is similar to `let x;` statements without an initializer expression,
+                    // where the value of `x` in this example may or may be assigned,
+                    // because the storage for their values may not be live after all due to
+                    // failure in pattern matching.
+                    // For this reason, we declare those storages as live but we do not schedule
+                    // any drop yet- they are scheduled later after the pattern matching.
+                    // The generated MIR will have `StorageDead` whenever the control flow breaks out
+                    // of the parent scope, regardless of the result of the pattern matching.
+                    // However, the drops are inserted in MIR only when the control flow breaks out of
+                    // the scope of the remainder scope associated with this `let .. else` statement.
+                    // Pictorial explanation of the scope structure:
+                    // ┌─────────────────────────────────┐
+                    // │  Scope of the enclosing block,  │
+                    // │  or the last remainder scope    │
+                    // │  ┌───────────────────────────┐  │
+                    // │  │  Scope for <else> block   │  │
+                    // │  └───────────────────────────┘  │
+                    // │  ┌───────────────────────────┐  │
+                    // │  │  Remainder scope of       │  │
+                    // │  │  this let-else statement  │  │
+                    // │  │  ┌─────────────────────┐  │  │
+                    // │  │  │ <expr> scope        │  │  │
+                    // │  │  └─────────────────────┘  │  │
+                    // │  │  extended temporaries in  │  │
+                    // │  │  <expr> lives in this     │  │
+                    // │  │  scope                    │  │
+                    // │  │  ┌─────────────────────┐  │  │
+                    // │  │  │ Scopes for the rest │  │  │
+                    // │  │  └─────────────────────┘  │  │
+                    // │  └───────────────────────────┘  │
+                    // └─────────────────────────────────┘
+                    // Generated control flow:
+                    //          │ let Some(x) = y() else { return; }
+                    //          │
+                    // ┌────────▼───────┐
+                    // │ evaluate y()   │
+                    // └────────┬───────┘
+                    //          │              ┌────────────────┐
+                    // ┌────────▼───────┐      │Drop temporaries│
+                    // │Test the pattern├──────►in y()          │
+                    // └────────┬───────┘      │because breaking│
+                    //          │              │out of <expr>   │
+                    // ┌────────▼───────┐      │scope           │
+                    // │Move value into │      └───────┬────────┘
+                    // │binding x       │              │
+                    // └────────┬───────┘      ┌───────▼────────┐
+                    //          │              │Drop extended   │
+                    // ┌────────▼───────┐      │temporaries in  │
+                    // │Drop temporaries│      │<expr> because  │
+                    // │in y()          │      │breaking out of │
+                    // │because breaking│      │remainder scope │
+                    // │out of <expr>   │      └───────┬────────┘
+                    // │scope           │              │
+                    // └────────┬───────┘      ┌───────▼────────┐
+                    //          │              │Enter <else>    ├────────►
+                    // ┌────────▼───────┐      │block           │ return;
+                    // │Continue...     │      └────────────────┘
+                    // └────────────────┘
+
+                    let ignores_expr_result = matches!(pattern.kind, PatKind::Wild);
+                    this.block_context.push(BlockFrame::Statement { ignores_expr_result });
+
+                    // Lower the `else` block first because its parent scope is actually
+                    // enclosing the rest of the `let .. else ..` parts.
+                    let else_block_span = this.thir[*else_block].span;
+                    // This place is not really used because this destination place
+                    // should never be used to take values at the end of the failure
+                    // block.
+                    let dummy_place = this.temp(this.tcx.types.never, else_block_span);
+                    let failure_entry = this.cfg.start_new_block();
+                    let failure_block;
+                    unpack!(
+                        failure_block = this.ast_block(
+                            dummy_place,
+                            failure_entry,
+                            *else_block,
+                            this.source_info(else_block_span),
+                        )
+                    );
+                    this.cfg.terminate(
+                        failure_block,
+                        this.source_info(else_block_span),
+                        TerminatorKind::Unreachable,
+                    );
+
+                    // Declare the bindings, which may create a source scope.
+                    let remainder_span = remainder_scope.span(this.tcx, this.region_scope_tree);
+                    this.push_scope((*remainder_scope, source_info));
+                    let_scope_stack.push(remainder_scope);
+
+                    let visibility_scope =
+                        Some(this.new_source_scope(remainder_span, LintLevel::Inherited, None));
+
+                    let init = &this.thir[*initializer];
+                    let initializer_span = init.span;
+                    this.declare_bindings(
+                        visibility_scope,
+                        remainder_span,
+                        pattern,
+                        ArmHasGuard(false),
+                        Some((None, initializer_span)),
+                    );
+                    this.visit_primary_bindings(
+                        pattern,
+                        UserTypeProjections::none(),
+                        &mut |this, _, _, _, node, span, _, _| {
+                            this.storage_live_binding(block, node, span, OutsideGuard, false);
+                        },
+                    );
+                    let failure = unpack!(
+                        block = this.in_opt_scope(
+                            opt_destruction_scope.map(|de| (de, source_info)),
+                            |this| {
+                                let scope = (*init_scope, source_info);
+                                this.in_scope(scope, *lint_level, |this| {
+                                    this.ast_let_else(
+                                        block,
+                                        init,
+                                        initializer_span,
+                                        *else_block,
+                                        &last_remainder_scope,
+                                        pattern,
+                                    )
+                                })
+                            }
+                        )
+                    );
+                    this.cfg.goto(failure, source_info, failure_entry);
+
+                    if let Some(source_scope) = visibility_scope {
+                        this.source_scope = source_scope;
+                    }
+                    last_remainder_scope = *remainder_scope;
+                }
+                StmtKind::Let { init_scope, initializer: None, else_block: Some(_), .. } => {
+                    span_bug!(
+                        init_scope.span(this.tcx, this.region_scope_tree),
+                        "initializer is missing, but else block is present in this let binding",
+                    )
+                }
+                StmtKind::Let {
+                    remainder_scope,
+                    init_scope,
                     ref pattern,
                     initializer,
                     lint_level,
-                    else_block,
+                    else_block: None,
                 } => {
                     let ignores_expr_result = matches!(pattern.kind, PatKind::Wild);
                     this.block_context.push(BlockFrame::Statement { ignores_expr_result });
@@ -141,27 +298,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                                 |this| {
                                     let scope = (*init_scope, source_info);
                                     this.in_scope(scope, *lint_level, |this| {
-                                        if let Some(else_block) = else_block {
-                                            this.ast_let_else(
-                                                block,
-                                                init,
-                                                initializer_span,
-                                                *else_block,
-                                                visibility_scope,
-                                                last_remainder_scope,
-                                                remainder_span,
-                                                pattern,
-                                            )
-                                        } else {
-                                            this.declare_bindings(
-                                                visibility_scope,
-                                                remainder_span,
-                                                pattern,
-                                                ArmHasGuard(false),
-                                                Some((None, initializer_span)),
-                                            );
-                                            this.expr_into_pattern(block, pattern, init) // irrefutable pattern
-                                        }
+                                        this.declare_bindings(
+                                            visibility_scope,
+                                            remainder_span,
+                                            pattern,
+                                            ArmHasGuard(false),
+                                            Some((None, initializer_span)),
+                                        );
+                                        this.expr_into_pattern(block, &pattern, init) // irrefutable pattern
                                     })
                                 },
                             )
diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs
index b1cb9b9f084..e0727725f68 100644
--- a/compiler/rustc_mir_build/src/build/matches/mod.rs
+++ b/compiler/rustc_mir_build/src/build/matches/mod.rs
@@ -699,7 +699,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         self.cfg.push(block, Statement { source_info, kind: StatementKind::StorageLive(local_id) });
         // Although there is almost always scope for given variable in corner cases
         // like #92893 we might get variable with no scope.
-        if let Some(region_scope) = self.region_scope_tree.var_scope(var.0.local_id) && schedule_drop{
+        if let Some(region_scope) = self.region_scope_tree.var_scope(var.0.local_id) && schedule_drop {
             self.schedule_drop(span, region_scope, local_id, DropKind::Storage);
         }
         Place::from(local_id)
@@ -2274,23 +2274,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         init: &Expr<'tcx>,
         initializer_span: Span,
         else_block: BlockId,
-        visibility_scope: Option<SourceScope>,
-        remainder_scope: region::Scope,
-        remainder_span: Span,
+        let_else_scope: &region::Scope,
         pattern: &Pat<'tcx>,
-    ) -> BlockAnd<()> {
+    ) -> BlockAnd<BasicBlock> {
         let else_block_span = self.thir[else_block].span;
-        let (matching, failure) = self.in_if_then_scope(remainder_scope, |this| {
+        let (matching, failure) = self.in_if_then_scope(*let_else_scope, |this| {
             let scrutinee = unpack!(block = this.lower_scrutinee(block, init, initializer_span));
             let pat = Pat { ty: init.ty, span: else_block_span, kind: PatKind::Wild };
             let mut wildcard = Candidate::new(scrutinee.clone(), &pat, false);
-            this.declare_bindings(
-                visibility_scope,
-                remainder_span,
-                pattern,
-                ArmHasGuard(false),
-                Some((None, initializer_span)),
-            );
             let mut candidate = Candidate::new(scrutinee.clone(), pattern, false);
             let fake_borrow_temps = this.lower_match_tree(
                 block,
@@ -2321,28 +2312,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 None,
                 None,
             );
-            this.break_for_else(failure, remainder_scope, this.source_info(initializer_span));
+            this.break_for_else(failure, *let_else_scope, this.source_info(initializer_span));
             matching.unit()
         });
-
-        // This place is not really used because this destination place
-        // should never be used to take values at the end of the failure
-        // block.
-        let dummy_place = self.temp(self.tcx.types.never, else_block_span);
-        let failure_block;
-        unpack!(
-            failure_block = self.ast_block(
-                dummy_place,
-                failure,
-                else_block,
-                self.source_info(else_block_span),
-            )
-        );
-        self.cfg.terminate(
-            failure_block,
-            self.source_info(else_block_span),
-            TerminatorKind::Unreachable,
-        );
-        matching.unit()
+        matching.and(failure)
     }
 }
diff --git a/compiler/rustc_query_impl/src/on_disk_cache.rs b/compiler/rustc_query_impl/src/on_disk_cache.rs
index 5ef95911f56..0e93f3ce1d6 100644
--- a/compiler/rustc_query_impl/src/on_disk_cache.rs
+++ b/compiler/rustc_query_impl/src/on_disk_cache.rs
@@ -798,6 +798,12 @@ impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for &'tcx FxHashSet<LocalDefId>
     }
 }
 
+impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for &'tcx FxHashMap<DefId, Ty<'tcx>> {
+    fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Self {
+        RefDecodable::decode(d)
+    }
+}
+
 impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>>
     for &'tcx IndexVec<mir::Promoted, mir::Body<'tcx>>
 {
diff --git a/compiler/rustc_query_impl/src/plumbing.rs b/compiler/rustc_query_impl/src/plumbing.rs
index 6fb3c69b1f4..6f39bbfc0dc 100644
--- a/compiler/rustc_query_impl/src/plumbing.rs
+++ b/compiler/rustc_query_impl/src/plumbing.rs
@@ -151,19 +151,31 @@ impl<'tcx> QueryCtxt<'tcx> {
         encoder: &mut on_disk_cache::CacheEncoder<'_, 'tcx>,
         query_result_index: &mut on_disk_cache::EncodedDepNodeIndex,
     ) {
+        macro_rules! expand_if_cached {
+            ([] $encode:expr) => {};
+            ([(cache) $($rest:tt)*] $encode:expr) => {
+                $encode
+            };
+            ([$other:tt $($modifiers:tt)*] $encode:expr) => {
+                expand_if_cached!([$($modifiers)*] $encode)
+            };
+        }
+
         macro_rules! encode_queries {
-            ($($query:ident,)*) => {
+            (
+            $($(#[$attr:meta])*
+                [$($modifiers:tt)*] fn $query:ident($($K:tt)*) -> $V:ty,)*) => {
                 $(
-                    on_disk_cache::encode_query_results::<_, super::queries::$query<'_>>(
+                    expand_if_cached!([$($modifiers)*] on_disk_cache::encode_query_results::<_, super::queries::$query<'_>>(
                         self,
                         encoder,
                         query_result_index
-                    );
+                    ));
                 )*
             }
         }
 
-        rustc_cached_queries!(encode_queries!);
+        rustc_query_append!(encode_queries!);
     }
 
     pub fn try_print_query_stack(
diff --git a/compiler/rustc_query_impl/src/profiling_support.rs b/compiler/rustc_query_impl/src/profiling_support.rs
index 260af0d5408..98ec3bc0977 100644
--- a/compiler/rustc_query_impl/src/profiling_support.rs
+++ b/compiler/rustc_query_impl/src/profiling_support.rs
@@ -307,16 +307,16 @@ pub fn alloc_self_profile_query_strings(tcx: TyCtxt<'_>) {
 
     macro_rules! alloc_once {
         (
-            $($(#[$attr:meta])* [$($modifiers:tt)*] fn $name:ident($K:ty) -> $V:ty,)*
-        ) => {
-            $({
+        $($(#[$attr:meta])*
+            [$($modifiers:tt)*] fn $name:ident($($K:tt)*) -> $V:ty,)*) => {
+            $(
                 alloc_self_profile_query_strings_for_query_cache(
                     tcx,
                     stringify!($name),
                     &tcx.query_caches.$name,
                     &mut string_cache,
                 );
-            })*
+            )+
         }
     }
 
diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
index 43c4ddd3f6f..d1deef78407 100644
--- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
@@ -1039,9 +1039,25 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                     return Err(Unimplemented);
                 }
 
-                // Extract `TailField<T>` and `TailField<U>` from `Struct<T>` and `Struct<U>`.
-                let source_tail = tail_field_ty.subst(tcx, substs_a);
-                let target_tail = tail_field_ty.subst(tcx, substs_b);
+                // Extract `TailField<T>` and `TailField<U>` from `Struct<T>` and `Struct<U>`,
+                // normalizing in the process, since `type_of` returns something directly from
+                // astconv (which means it's un-normalized).
+                let source_tail = normalize_with_depth_to(
+                    self,
+                    obligation.param_env,
+                    obligation.cause.clone(),
+                    obligation.recursion_depth + 1,
+                    tail_field_ty.subst(tcx, substs_a),
+                    &mut nested,
+                );
+                let target_tail = normalize_with_depth_to(
+                    self,
+                    obligation.param_env,
+                    obligation.cause.clone(),
+                    obligation.recursion_depth + 1,
+                    tail_field_ty.subst(tcx, substs_b),
+                    &mut nested,
+                );
 
                 // Check that the source struct with the target's
                 // unsizing parameters is equal to the target.
diff --git a/compiler/rustc_typeck/src/check/closure.rs b/compiler/rustc_typeck/src/check/closure.rs
index 55cbaf71e7c..9b943b160f3 100644
--- a/compiler/rustc_typeck/src/check/closure.rs
+++ b/compiler/rustc_typeck/src/check/closure.rs
@@ -30,7 +30,12 @@ struct ExpectedSig<'tcx> {
 }
 
 struct ClosureSignatures<'tcx> {
+    /// The signature users of the closure see.
     bound_sig: ty::PolyFnSig<'tcx>,
+    /// The signature within the function body.
+    /// This mostly differs in the sense that lifetimes are now early bound and any
+    /// opaque types from the signature expectation are overriden in case there are
+    /// explicit hidden types written by the user in the closure signature.
     liberated_sig: ty::FnSig<'tcx>,
 }
 
@@ -444,18 +449,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         // Along the way, it also writes out entries for types that the user
         // wrote into our typeck results, which are then later used by the privacy
         // check.
-        match self.check_supplied_sig_against_expectation(
+        match self.merge_supplied_sig_with_expectation(
             hir_id,
             expr_def_id,
             decl,
             body,
-            &closure_sigs,
+            closure_sigs,
         ) {
             Ok(infer_ok) => self.register_infer_ok_obligations(infer_ok),
-            Err(_) => return self.sig_of_closure_no_expectation(hir_id, expr_def_id, decl, body),
+            Err(_) => self.sig_of_closure_no_expectation(hir_id, expr_def_id, decl, body),
         }
-
-        closure_sigs
     }
 
     fn sig_of_closure_with_mismatched_number_of_arguments(
@@ -497,21 +500,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     /// Enforce the user's types against the expectation. See
     /// `sig_of_closure_with_expectation` for details on the overall
     /// strategy.
-    fn check_supplied_sig_against_expectation(
+    #[instrument(level = "debug", skip(self, hir_id, expr_def_id, decl, body, expected_sigs))]
+    fn merge_supplied_sig_with_expectation(
         &self,
         hir_id: hir::HirId,
         expr_def_id: DefId,
         decl: &hir::FnDecl<'_>,
         body: &hir::Body<'_>,
-        expected_sigs: &ClosureSignatures<'tcx>,
-    ) -> InferResult<'tcx, ()> {
+        mut expected_sigs: ClosureSignatures<'tcx>,
+    ) -> InferResult<'tcx, ClosureSignatures<'tcx>> {
         // Get the signature S that the user gave.
         //
         // (See comment on `sig_of_closure_with_expectation` for the
         // meaning of these letters.)
         let supplied_sig = self.supplied_sig_of_closure(hir_id, expr_def_id, decl, body);
 
-        debug!("check_supplied_sig_against_expectation: supplied_sig={:?}", supplied_sig);
+        debug!(?supplied_sig);
 
         // FIXME(#45727): As discussed in [this comment][c1], naively
         // forcing equality here actually results in suboptimal error
@@ -529,23 +533,27 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         // [c2]: https://github.com/rust-lang/rust/pull/45072#issuecomment-341096796
         self.commit_if_ok(|_| {
             let mut all_obligations = vec![];
+            let inputs: Vec<_> = iter::zip(
+                decl.inputs,
+                supplied_sig.inputs().skip_binder(), // binder moved to (*) below
+            )
+            .map(|(hir_ty, &supplied_ty)| {
+                // Instantiate (this part of..) S to S', i.e., with fresh variables.
+                self.replace_bound_vars_with_fresh_vars(
+                    hir_ty.span,
+                    LateBoundRegionConversionTime::FnCall,
+                    // (*) binder moved to here
+                    supplied_sig.inputs().rebind(supplied_ty),
+                )
+            })
+            .collect();
 
             // The liberated version of this signature should be a subtype
             // of the liberated form of the expectation.
             for ((hir_ty, &supplied_ty), expected_ty) in iter::zip(
-                iter::zip(
-                    decl.inputs,
-                    supplied_sig.inputs().skip_binder(), // binder moved to (*) below
-                ),
+                iter::zip(decl.inputs, &inputs),
                 expected_sigs.liberated_sig.inputs(), // `liberated_sig` is E'.
             ) {
-                // Instantiate (this part of..) S to S', i.e., with fresh variables.
-                let supplied_ty = self.replace_bound_vars_with_fresh_vars(
-                    hir_ty.span,
-                    LateBoundRegionConversionTime::FnCall,
-                    supplied_sig.inputs().rebind(supplied_ty),
-                ); // recreated from (*) above
-
                 // Check that E' = S'.
                 let cause = self.misc(hir_ty.span);
                 let InferOk { value: (), obligations } =
@@ -564,7 +572,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 .eq(expected_sigs.liberated_sig.output(), supplied_output_ty)?;
             all_obligations.extend(obligations);
 
-            Ok(InferOk { value: (), obligations: all_obligations })
+            let inputs = inputs.into_iter().map(|ty| self.resolve_vars_if_possible(ty));
+
+            expected_sigs.liberated_sig = self.tcx.mk_fn_sig(
+                inputs,
+                supplied_output_ty,
+                expected_sigs.liberated_sig.c_variadic,
+                hir::Unsafety::Normal,
+                Abi::RustCall,
+            );
+
+            Ok(InferOk { value: expected_sigs, obligations: all_obligations })
         })
     }
 
diff --git a/compiler/rustc_typeck/src/check/region.rs b/compiler/rustc_typeck/src/check/region.rs
index b779713482e..b89db79bef8 100644
--- a/compiler/rustc_typeck/src/check/region.rs
+++ b/compiler/rustc_typeck/src/check/region.rs
@@ -126,6 +126,29 @@ fn resolve_block<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, blk: &'tcx h
 
         for (i, statement) in blk.stmts.iter().enumerate() {
             match statement.kind {
+                hir::StmtKind::Local(hir::Local { els: Some(els), .. }) => {
+                    // Let-else has a special lexical structure for variables.
+                    // First we take a checkpoint of the current scope context here.
+                    let mut prev_cx = visitor.cx;
+
+                    visitor.enter_scope(Scope {
+                        id: blk.hir_id.local_id,
+                        data: ScopeData::Remainder(FirstStatementIndex::new(i)),
+                    });
+                    visitor.cx.var_parent = visitor.cx.parent;
+                    visitor.visit_stmt(statement);
+                    // We need to back out temporarily to the last enclosing scope
+                    // for the `else` block, so that even the temporaries receiving
+                    // extended lifetime will be dropped inside this block.
+                    // We are visiting the `else` block in this order so that
+                    // the sequence of visits agree with the order in the default
+                    // `hir::intravisit` visitor.
+                    mem::swap(&mut prev_cx, &mut visitor.cx);
+                    visitor.terminating_scopes.insert(els.hir_id.local_id);
+                    visitor.visit_block(els);
+                    // From now on, we continue normally.
+                    visitor.cx = prev_cx;
+                }
                 hir::StmtKind::Local(..) | hir::StmtKind::Item(..) => {
                     // Each declaration introduces a subscope for bindings
                     // introduced by the declaration; this subscope covers a
@@ -138,10 +161,10 @@ fn resolve_block<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, blk: &'tcx h
                         data: ScopeData::Remainder(FirstStatementIndex::new(i)),
                     });
                     visitor.cx.var_parent = visitor.cx.parent;
+                    visitor.visit_stmt(statement)
                 }
-                hir::StmtKind::Expr(..) | hir::StmtKind::Semi(..) => {}
+                hir::StmtKind::Expr(..) | hir::StmtKind::Semi(..) => visitor.visit_stmt(statement),
             }
-            visitor.visit_stmt(statement)
         }
         walk_list!(visitor, visit_expr, &blk.expr);
     }
@@ -460,7 +483,6 @@ fn resolve_local<'tcx>(
     visitor: &mut RegionResolutionVisitor<'tcx>,
     pat: Option<&'tcx hir::Pat<'tcx>>,
     init: Option<&'tcx hir::Expr<'tcx>>,
-    els: Option<&'tcx hir::Block<'tcx>>,
 ) {
     debug!("resolve_local(pat={:?}, init={:?})", pat, init);
 
@@ -547,9 +569,6 @@ fn resolve_local<'tcx>(
     if let Some(pat) = pat {
         visitor.visit_pat(pat);
     }
-    if let Some(els) = els {
-        visitor.visit_block(els);
-    }
 
     /// Returns `true` if `pat` match the `P&` non-terminal.
     ///
@@ -766,7 +785,7 @@ impl<'tcx> Visitor<'tcx> for RegionResolutionVisitor<'tcx> {
             // (i.e., `'static`), which means that after `g` returns, it drops,
             // and all the associated destruction scope rules apply.
             self.cx.var_parent = None;
-            resolve_local(self, None, Some(&body.value), None);
+            resolve_local(self, None, Some(&body.value));
         }
 
         if body.generator_kind.is_some() {
@@ -793,7 +812,7 @@ impl<'tcx> Visitor<'tcx> for RegionResolutionVisitor<'tcx> {
         resolve_expr(self, ex);
     }
     fn visit_local(&mut self, l: &'tcx Local<'tcx>) {
-        resolve_local(self, Some(&l.pat), l.init, l.els)
+        resolve_local(self, Some(&l.pat), l.init)
     }
 }
 
diff --git a/library/core/src/ops/function.rs b/library/core/src/ops/function.rs
index c5a194b7d0a..8fdf22cf6f2 100644
--- a/library/core/src/ops/function.rs
+++ b/library/core/src/ops/function.rs
@@ -250,9 +250,10 @@ pub trait FnOnce<Args> {
 
 mod impls {
     #[stable(feature = "rust1", since = "1.0.0")]
-    impl<A, F: ?Sized> Fn<A> for &F
+    #[rustc_const_unstable(feature = "const_fn_trait_ref_impls", issue = "101803")]
+    impl<A, F: ?Sized> const Fn<A> for &F
     where
-        F: Fn<A>,
+        F: ~const Fn<A>,
     {
         extern "rust-call" fn call(&self, args: A) -> F::Output {
             (**self).call(args)
@@ -260,9 +261,10 @@ mod impls {
     }
 
     #[stable(feature = "rust1", since = "1.0.0")]
-    impl<A, F: ?Sized> FnMut<A> for &F
+    #[rustc_const_unstable(feature = "const_fn_trait_ref_impls", issue = "101803")]
+    impl<A, F: ?Sized> const FnMut<A> for &F
     where
-        F: Fn<A>,
+        F: ~const Fn<A>,
     {
         extern "rust-call" fn call_mut(&mut self, args: A) -> F::Output {
             (**self).call(args)
@@ -270,9 +272,10 @@ mod impls {
     }
 
     #[stable(feature = "rust1", since = "1.0.0")]
-    impl<A, F: ?Sized> FnOnce<A> for &F
+    #[rustc_const_unstable(feature = "const_fn_trait_ref_impls", issue = "101803")]
+    impl<A, F: ?Sized> const FnOnce<A> for &F
     where
-        F: Fn<A>,
+        F: ~const Fn<A>,
     {
         type Output = F::Output;
 
@@ -282,9 +285,10 @@ mod impls {
     }
 
     #[stable(feature = "rust1", since = "1.0.0")]
-    impl<A, F: ?Sized> FnMut<A> for &mut F
+    #[rustc_const_unstable(feature = "const_fn_trait_ref_impls", issue = "101803")]
+    impl<A, F: ?Sized> const FnMut<A> for &mut F
     where
-        F: FnMut<A>,
+        F: ~const FnMut<A>,
     {
         extern "rust-call" fn call_mut(&mut self, args: A) -> F::Output {
             (*self).call_mut(args)
@@ -292,9 +296,10 @@ mod impls {
     }
 
     #[stable(feature = "rust1", since = "1.0.0")]
-    impl<A, F: ?Sized> FnOnce<A> for &mut F
+    #[rustc_const_unstable(feature = "const_fn_trait_ref_impls", issue = "101803")]
+    impl<A, F: ?Sized> const FnOnce<A> for &mut F
     where
-        F: FnMut<A>,
+        F: ~const FnMut<A>,
     {
         type Output = F::Output;
         extern "rust-call" fn call_once(self, args: A) -> F::Output {
diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs
index c13e83f6c86..f7ab6bf93fb 100644
--- a/src/bootstrap/compile.rs
+++ b/src/bootstrap/compile.rs
@@ -436,6 +436,43 @@ impl Step for StdLink {
         let libdir = builder.sysroot_libdir(target_compiler, target);
         let hostdir = builder.sysroot_libdir(target_compiler, compiler.host);
         add_to_sysroot(builder, &libdir, &hostdir, &libstd_stamp(builder, compiler, target));
+
+        if compiler.stage == 0 {
+            // special handling for stage0, to make `rustup toolchain link` and `x dist --stage 0`
+            // work for stage0-sysroot
+
+            // copy bin files from stage0/bin to stage0-sysroot/bin
+            let sysroot = builder.out.join(&compiler.host.triple).join("stage0-sysroot");
+
+            let host = compiler.host.triple;
+            let stage0_bin_dir = builder.out.join(&host).join("stage0/bin");
+            let sysroot_bin_dir = sysroot.join("bin");
+            t!(fs::create_dir_all(&sysroot_bin_dir));
+            builder.cp_r(&stage0_bin_dir, &sysroot_bin_dir);
+
+            // copy all *.so files from stage0/lib to stage0-sysroot/lib
+            let stage0_lib_dir = builder.out.join(&host).join("stage0/lib");
+            if let Ok(files) = fs::read_dir(&stage0_lib_dir) {
+                for file in files {
+                    let file = t!(file);
+                    let path = file.path();
+                    if path.is_file() && is_dylib(&file.file_name().into_string().unwrap()) {
+                        builder.copy(&path, &sysroot.join("lib").join(path.file_name().unwrap()));
+                    }
+                }
+            }
+
+            // copy codegen-backends from stage0
+            let sysroot_codegen_backends = builder.sysroot_codegen_backends(compiler);
+            t!(fs::create_dir_all(&sysroot_codegen_backends));
+            let stage0_codegen_backends = builder
+                .out
+                .join(&host)
+                .join("stage0/lib/rustlib")
+                .join(&host)
+                .join("codegen-backends");
+            builder.cp_r(&stage0_codegen_backends, &sysroot_codegen_backends);
+        }
     }
 }
 
diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs
index f61c9583085..9d286ddd6d1 100644
--- a/src/bootstrap/test.rs
+++ b/src/bootstrap/test.rs
@@ -1341,6 +1341,8 @@ note: if you're sure you want to do this, please open an issue as to why. In the
             let json_compiler = compiler.with_stage(0);
             cmd.arg("--jsondocck-path")
                 .arg(builder.ensure(tool::JsonDocCk { compiler: json_compiler, target }));
+            cmd.arg("--jsondoclint-path")
+                .arg(builder.ensure(tool::JsonDocLint { compiler: json_compiler, target }));
         }
 
         if mode == "run-make" {
diff --git a/src/bootstrap/tool.rs b/src/bootstrap/tool.rs
index c3b04a9bbce..7d4ed24b648 100644
--- a/src/bootstrap/tool.rs
+++ b/src/bootstrap/tool.rs
@@ -376,6 +376,7 @@ bootstrap_tool!(
     ExpandYamlAnchors, "src/tools/expand-yaml-anchors", "expand-yaml-anchors";
     LintDocs, "src/tools/lint-docs", "lint-docs";
     JsonDocCk, "src/tools/jsondocck", "jsondocck";
+    JsonDocLint, "src/tools/jsondoclint", "jsondoclint";
     HtmlChecker, "src/tools/html-checker", "html-checker";
     BumpStage0, "src/tools/bump-stage0", "bump-stage0";
     ReplaceVersionPlaceholder, "src/tools/replace-version-placeholder", "replace-version-placeholder";
diff --git a/src/etc/check_missing_items.py b/src/etc/check_missing_items.py
deleted file mode 100644
index 0026c4cbdca..00000000000
--- a/src/etc/check_missing_items.py
+++ /dev/null
@@ -1,202 +0,0 @@
-#!/usr/bin/env python
-
-# This test ensures that every ID in the produced json actually resolves to an item either in
-# `index` or `paths`. It DOES NOT check that the structure of the produced json is actually in
-# any way correct, for example an empty map would pass.
-
-# FIXME: Better error output
-
-import sys
-import json
-
-crate = json.load(open(sys.argv[1], encoding="utf-8"))
-
-
-def get_local_item(item_id):
-    if item_id in crate["index"]:
-        return crate["index"][item_id]
-    print("Missing local ID:", item_id)
-    sys.exit(1)
-
-
-# local IDs have to be in `index`, external ones can sometimes be in `index` but otherwise have
-# to be in `paths`
-def valid_id(item_id):
-    return item_id in crate["index"] or item_id[0] != "0" and item_id in crate["paths"]
-
-
-def check_generics(generics):
-    for param in generics["params"]:
-        check_generic_param(param)
-    for where_predicate in generics["where_predicates"]:
-        if "bound_predicate" in where_predicate:
-            pred = where_predicate["bound_predicate"]
-            check_type(pred["type"])
-            for bound in pred["bounds"]:
-                check_generic_bound(bound)
-        elif "region_predicate" in where_predicate:
-            pred = where_predicate["region_predicate"]
-            for bound in pred["bounds"]:
-                check_generic_bound(bound)
-        elif "eq_predicate" in where_predicate:
-            pred = where_predicate["eq_predicate"]
-            check_type(pred["rhs"])
-            check_type(pred["lhs"])
-
-
-def check_generic_param(param):
-    if "type" in param["kind"]:
-        ty = param["kind"]["type"]
-        if ty["default"]:
-            check_type(ty["default"])
-        for bound in ty["bounds"]:
-            check_generic_bound(bound)
-    elif "const" in param["kind"]:
-        check_type(param["kind"]["const"])
-
-
-def check_generic_bound(bound):
-    if "trait_bound" in bound:
-        for param in bound["trait_bound"]["generic_params"]:
-            check_generic_param(param)
-        check_path(bound["trait_bound"]["trait"])
-
-
-def check_decl(decl):
-    for (_name, ty) in decl["inputs"]:
-        check_type(ty)
-    if decl["output"]:
-        check_type(decl["output"])
-
-def check_path(path):
-    args = path["args"]
-    if args:
-        if "angle_bracketed" in args:
-            for arg in args["angle_bracketed"]["args"]:
-                if "type" in arg:
-                    check_type(arg["type"])
-                elif "const" in arg:
-                    check_type(arg["const"]["type"])
-            for binding in args["angle_bracketed"]["bindings"]:
-                if "equality" in binding["binding"]:
-                    term = binding["binding"]["equality"]
-                    if "type" in term: check_type(term["type"])
-                    elif "const" in term: check_type(term["const"])
-                elif "constraint" in binding["binding"]:
-                    for bound in binding["binding"]["constraint"]:
-                        check_generic_bound(bound)
-        elif "parenthesized" in args:
-            for input_ty in args["parenthesized"]["inputs"]:
-                check_type(input_ty)
-            if args["parenthesized"]["output"]:
-                check_type(args["parenthesized"]["output"])
-
-    if path["id"] in crate["index"]:
-        work_list.add(path["id"])
-    elif path["id"] not in crate["paths"]:
-        print("Id not in index or paths:", path["id"])
-        sys.exit(1)
-
-def check_type(ty):
-    if ty["kind"] == "resolved_path":
-        check_path(ty["inner"])
-    elif ty["kind"] == "tuple":
-        for ty in ty["inner"]:
-            check_type(ty)
-    elif ty["kind"] == "slice":
-        check_type(ty["inner"])
-    elif ty["kind"] == "impl_trait":
-        for bound in ty["inner"]:
-            check_generic_bound(bound)
-    elif ty["kind"] in ("raw_pointer", "borrowed_ref", "array"):
-        check_type(ty["inner"]["type"])
-    elif ty["kind"] == "function_pointer":
-        for param in ty["inner"]["generic_params"]:
-            check_generic_param(param)
-        check_decl(ty["inner"]["decl"])
-    elif ty["kind"] == "qualified_path":
-        check_type(ty["inner"]["self_type"])
-        check_path(ty["inner"]["trait"])
-
-
-work_list = set([crate["root"]])
-visited = work_list.copy()
-
-while work_list:
-    current = work_list.pop()
-    visited.add(current)
-    item = get_local_item(current)
-    # check intradoc links
-    for (_name, link) in item["links"].items():
-        if not valid_id(link):
-            print("Intra-doc link contains invalid ID:", link)
-
-    # check all fields that reference types such as generics as well as nested items
-    # (modules, structs, traits, and enums)
-    if item["kind"] == "module":
-        work_list |= set(item["inner"]["items"]) - visited
-    elif item["kind"] == "struct":
-        check_generics(item["inner"]["generics"])
-        work_list |= set(item["inner"]["impls"]) - visited
-        if "tuple" in item["inner"]["kind"]:
-            work_list |= set(filter(None, item["inner"]["kind"]["tuple"])) - visited
-        elif "plain" in item["inner"]["kind"]:
-            work_list |= set(item["inner"]["kind"]["plain"]["fields"]) - visited
-    elif item["kind"] == "struct_field":
-        check_type(item["inner"])
-    elif item["kind"] == "enum":
-        check_generics(item["inner"]["generics"])
-        work_list |= (
-            set(item["inner"]["variants"]) | set(item["inner"]["impls"])
-        ) - visited
-    elif item["kind"] == "variant":
-        if item["inner"]["variant_kind"] == "tuple":
-            for field_id in filter(None, item["inner"]["variant_inner"]):
-                work_list.add(field_id)
-        elif item["inner"]["variant_kind"] == "struct":
-            work_list |= set(item["inner"]["variant_inner"]["fields"]) - visited
-    elif item["kind"] in ("function", "method"):
-        check_generics(item["inner"]["generics"])
-        check_decl(item["inner"]["decl"])
-    elif item["kind"] in ("static", "constant", "assoc_const"):
-        check_type(item["inner"]["type"])
-    elif item["kind"] == "typedef":
-        check_type(item["inner"]["type"])
-        check_generics(item["inner"]["generics"])
-    elif item["kind"] == "opaque_ty":
-        check_generics(item["inner"]["generics"])
-        for bound in item["inner"]["bounds"]:
-            check_generic_bound(bound)
-    elif item["kind"] == "trait_alias":
-        check_generics(item["inner"]["params"])
-        for bound in item["inner"]["bounds"]:
-            check_generic_bound(bound)
-    elif item["kind"] == "trait":
-        check_generics(item["inner"]["generics"])
-        for bound in item["inner"]["bounds"]:
-            check_generic_bound(bound)
-        work_list |= (
-            set(item["inner"]["items"]) | set(item["inner"]["implementations"])
-        ) - visited
-    elif item["kind"] == "impl":
-        check_generics(item["inner"]["generics"])
-        if item["inner"]["trait"]:
-            check_path(item["inner"]["trait"])
-        if item["inner"]["blanket_impl"]:
-            check_type(item["inner"]["blanket_impl"])
-        check_type(item["inner"]["for"])
-        for assoc_item in item["inner"]["items"]:
-            if not valid_id(assoc_item):
-                print("Impl block referenced a missing ID:", assoc_item)
-                sys.exit(1)
-    elif item["kind"] == "assoc_type":
-        for bound in item["inner"]["bounds"]:
-            check_generic_bound(bound)
-        if item["inner"]["default"]:
-            check_type(item["inner"]["default"])
-    elif item["kind"] == "import":
-        if item["inner"]["id"]:
-            inner_id = item["inner"]["id"]
-            assert valid_id(inner_id)
-            if inner_id in crate["index"] and inner_id not in visited:
-                work_list.add(inner_id)
diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css
index 8bfaaf21c8e..b0dcd36d6b3 100644
--- a/src/librustdoc/html/static/css/rustdoc.css
+++ b/src/librustdoc/html/static/css/rustdoc.css
@@ -222,7 +222,6 @@ details.rustdoc-toggle.non-exhaustive > summary::before,
 	font-family: "Fira Sans", Arial, NanumBarunGothic, sans-serif;
 }
 
-h1, h2, h3, h4,
 a#toggle-all-docs,
 a.anchor,
 .small-section-header a,
diff --git a/src/rustdoc-json-types/lib.rs b/src/rustdoc-json-types/lib.rs
index 13bafa506e4..be1ff286efd 100644
--- a/src/rustdoc-json-types/lib.rs
+++ b/src/rustdoc-json-types/lib.rs
@@ -542,12 +542,12 @@ pub enum Term {
 #[serde(rename_all = "snake_case")]
 #[serde(tag = "kind", content = "inner")]
 pub enum Type {
-    /// Structs, enums, and traits
+    /// Structs and enums
     ResolvedPath(Path),
     DynTrait(DynTrait),
     /// Parameterized types
     Generic(String),
-    /// Fixed-size numeric types (plus int/usize/float), char, arrays, slices, and tuples
+    /// Built in numberic (i*, u*, f*) types, bool, and char
     Primitive(String),
     /// `extern "ABI" fn`
     FunctionPointer(Box<FunctionPointer>),
diff --git a/src/test/mir-opt/retag.main-{closure#0}.SimplifyCfg-elaborate-drops.after.mir b/src/test/mir-opt/retag.main-{closure#0}.SimplifyCfg-elaborate-drops.after.mir
index 44b1a267b34..96fc7e6493a 100644
--- a/src/test/mir-opt/retag.main-{closure#0}.SimplifyCfg-elaborate-drops.after.mir
+++ b/src/test/mir-opt/retag.main-{closure#0}.SimplifyCfg-elaborate-drops.after.mir
@@ -14,7 +14,7 @@ fn main::{closure#0}(_1: &[closure@main::{closure#0}], _2: &i32) -> &i32 {
         StorageLive(_3);                 // scope 0 at $DIR/retag.rs:+1:13: +1:15
         _3 = _2;                         // scope 0 at $DIR/retag.rs:+1:18: +1:19
         Retag(_3);                       // scope 0 at $DIR/retag.rs:+1:18: +1:19
-        _0 = _2;                         // scope 1 at $DIR/retag.rs:+2:9: +2:10
+        _0 = &(*_2);                     // scope 1 at $DIR/retag.rs:+2:9: +2:10
         Retag(_0);                       // scope 1 at $DIR/retag.rs:+2:9: +2:10
         StorageDead(_3);                 // scope 0 at $DIR/retag.rs:+3:5: +3:6
         return;                          // scope 0 at $DIR/retag.rs:+3:6: +3:6
diff --git a/src/test/run-make/raw-dylib-alt-calling-convention/extern.c b/src/test/run-make/raw-dylib-alt-calling-convention/extern.c
index 0c4d12af9b2..344d4a6bf5a 100644
--- a/src/test/run-make/raw-dylib-alt-calling-convention/extern.c
+++ b/src/test/run-make/raw-dylib-alt-calling-convention/extern.c
@@ -70,6 +70,11 @@ __declspec(dllexport) void __stdcall stdcall_fn_9(uint8_t x, double y) {
     fflush(stdout);
 }
 
+__declspec(dllexport) void __stdcall stdcall_fn_10(int i) {
+    printf("stdcall_fn_10(%d)\n", i);
+    fflush(stdout);
+}
+
 __declspec(dllexport) void __fastcall fastcall_fn_1(int i) {
     printf("fastcall_fn_1(%d)\n", i);
     fflush(stdout);
@@ -122,6 +127,11 @@ __declspec(dllexport) void __fastcall fastcall_fn_9(uint8_t x, double y) {
     fflush(stdout);
 }
 
+__declspec(dllexport) void __fastcall fastcall_fn_10(int i) {
+    printf("fastcall_fn_10(%d)\n", i);
+    fflush(stdout);
+}
+
 // GCC doesn't support vectorcall: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=89485
 #ifdef _MSC_VER
 __declspec(dllexport) void __vectorcall vectorcall_fn_1(int i) {
@@ -175,4 +185,9 @@ __declspec(dllexport) void __vectorcall vectorcall_fn_9(uint8_t x, double y) {
     printf("vectorcall_fn_9(%d, %.1f)\n", x, y);
     fflush(stdout);
 }
+
+__declspec(dllexport) void __vectorcall vectorcall_fn_10(int i) {
+    printf("vectorcall_fn_10(%d)\n", i);
+    fflush(stdout);
+}
 #endif
diff --git a/src/test/run-make/raw-dylib-alt-calling-convention/lib.rs b/src/test/run-make/raw-dylib-alt-calling-convention/lib.rs
index fe74fbfd264..22f222c12c3 100644
--- a/src/test/run-make/raw-dylib-alt-calling-convention/lib.rs
+++ b/src/test/run-make/raw-dylib-alt-calling-convention/lib.rs
@@ -32,6 +32,8 @@ extern "stdcall" {
     fn stdcall_fn_7(a: S2, b: i32);
     fn stdcall_fn_8(a: S3, b: S3);
     fn stdcall_fn_9(x: u8, y: f64);
+    #[link_name = "stdcall_fn_10"]
+    fn stdcall_fn_10_renamed(i: i32);
 }
 
 #[link(name = "extern", kind = "raw-dylib")]
@@ -45,6 +47,8 @@ extern "fastcall" {
     fn fastcall_fn_7(a: S2, b: i32);
     fn fastcall_fn_8(a: S3, b: S3);
     fn fastcall_fn_9(x: u8, y: f64);
+    #[link_name = "fastcall_fn_10"]
+    fn fastcall_fn_10_renamed(i: i32);
 }
 
 #[cfg(target_env = "msvc")]
@@ -59,6 +63,8 @@ extern "vectorcall" {
     fn vectorcall_fn_7(a: S2, b: i32);
     fn vectorcall_fn_8(a: S3, b: S3);
     fn vectorcall_fn_9(x: u8, y: f64);
+    #[link_name = "vectorcall_fn_10"]
+    fn vectorcall_fn_10_renamed(i: i32);
 }
 
 pub fn library_function(run_msvc_only: bool) {
@@ -73,6 +79,7 @@ pub fn library_function(run_msvc_only: bool) {
             stdcall_fn_7(S2 { x: 15, y: 16 }, 3);
             stdcall_fn_8(S3 { x: [1, 2, 3, 4, 5] }, S3 { x: [6, 7, 8, 9, 10] });
             stdcall_fn_9(1, 3.0);
+            stdcall_fn_10_renamed(19);
 
             fastcall_fn_1(14);
             fastcall_fn_2(16, 3.5);
@@ -81,6 +88,7 @@ pub fn library_function(run_msvc_only: bool) {
             fastcall_fn_6(Some(&S { x: 10, y: 12 }));
             fastcall_fn_8(S3 { x: [1, 2, 3, 4, 5] }, S3 { x: [6, 7, 8, 9, 10] });
             fastcall_fn_9(1, 3.0);
+            fastcall_fn_10_renamed(19);
         } else {
             // FIXME: 91167
             // rustc generates incorrect code for the calls to fastcall_fn_5 and fastcall_fn_7
@@ -100,6 +108,7 @@ pub fn library_function(run_msvc_only: bool) {
                 vectorcall_fn_7(S2 { x: 15, y: 16 }, 3);
                 vectorcall_fn_8(S3 { x: [1, 2, 3, 4, 5] }, S3 { x: [6, 7, 8, 9, 10] });
                 vectorcall_fn_9(1, 3.0);
+                vectorcall_fn_10_renamed(19);
             }
         }
     }
diff --git a/src/test/run-make/raw-dylib-alt-calling-convention/output.msvc.txt b/src/test/run-make/raw-dylib-alt-calling-convention/output.msvc.txt
index 9ddd1b11016..a216835c4b6 100644
--- a/src/test/run-make/raw-dylib-alt-calling-convention/output.msvc.txt
+++ b/src/test/run-make/raw-dylib-alt-calling-convention/output.msvc.txt
@@ -9,3 +9,4 @@ vectorcall_fn_6(S { x: 10, y: 12 })
 vectorcall_fn_7(S2 { x: 15, y: 16 }, 3)
 vectorcall_fn_8(S3 { x: [1, 2, 3, 4, 5] }, S3 { x: [6, 7, 8, 9, 10] })
 vectorcall_fn_9(1, 3.0)
+vectorcall_fn_10(19)
diff --git a/src/test/run-make/raw-dylib-alt-calling-convention/output.txt b/src/test/run-make/raw-dylib-alt-calling-convention/output.txt
index 348bad63ed0..7622d31618b 100644
--- a/src/test/run-make/raw-dylib-alt-calling-convention/output.txt
+++ b/src/test/run-make/raw-dylib-alt-calling-convention/output.txt
@@ -7,6 +7,7 @@ stdcall_fn_6(S { x: 10, y: 12 })
 stdcall_fn_7(S2 { x: 15, y: 16 }, 3)
 stdcall_fn_8(S3 { x: [1, 2, 3, 4, 5] }, S3 { x: [6, 7, 8, 9, 10] })
 stdcall_fn_9(1, 3.0)
+stdcall_fn_10(19)
 fastcall_fn_1(14)
 fastcall_fn_2(16, 3.5)
 fastcall_fn_3(3.5)
@@ -14,3 +15,4 @@ fastcall_fn_4(1, 2, 3.0)
 fastcall_fn_6(S { x: 10, y: 12 })
 fastcall_fn_8(S3 { x: [1, 2, 3, 4, 5] }, S3 { x: [6, 7, 8, 9, 10] })
 fastcall_fn_9(1, 3.0)
+fastcall_fn_10(19)
diff --git a/src/test/run-make/raw-dylib-c/extern_1.c b/src/test/run-make/raw-dylib-c/extern_1.c
index ab1dc3a4105..5d695547d0f 100644
--- a/src/test/run-make/raw-dylib-c/extern_1.c
+++ b/src/test/run-make/raw-dylib-c/extern_1.c
@@ -21,3 +21,8 @@ __declspec(dllexport) void extern_fn_with_long_name() {
     printf("extern_fn_with_long_name; got the rename\n");
     fflush(stdout);
 }
+
+__declspec(dllexport) void extern_fn_4() {
+    printf("extern_fn_4\n");
+    fflush(stdout);
+}
diff --git a/src/test/run-make/raw-dylib-c/lib.rs b/src/test/run-make/raw-dylib-c/lib.rs
index 74e0d3813d9..005ffcdda5c 100644
--- a/src/test/run-make/raw-dylib-c/lib.rs
+++ b/src/test/run-make/raw-dylib-c/lib.rs
@@ -16,12 +16,15 @@ pub fn library_function() {
         fn extern_fn_2();
         fn print_extern_variable();
         static mut extern_variable: i32;
+        #[link_name = "extern_fn_4"]
+        fn extern_fn_4_renamed();
     }
 
     unsafe {
         extern_fn_1();
         extern_fn_2();
         extern_fn_3();
+        extern_fn_4_renamed();
         extern_variable = 42;
         print_extern_variable();
         extern_variable = -42;
diff --git a/src/test/run-make/raw-dylib-c/output.txt b/src/test/run-make/raw-dylib-c/output.txt
index cd9fe47bee4..cc970cef7bc 100644
--- a/src/test/run-make/raw-dylib-c/output.txt
+++ b/src/test/run-make/raw-dylib-c/output.txt
@@ -1,5 +1,6 @@
 extern_fn_1
 extern_fn_2; didn't get the rename
 extern_fn_3
+extern_fn_4
 extern_variable value: 42
 extern_variable value: -42
diff --git a/src/test/run-make/raw-dylib-import-name-type/driver.rs b/src/test/run-make/raw-dylib-import-name-type/driver.rs
index 74e9a89fbdf..a38849fc813 100644
--- a/src/test/run-make/raw-dylib-import-name-type/driver.rs
+++ b/src/test/run-make/raw-dylib-import-name-type/driver.rs
@@ -1,8 +1,11 @@
 #![feature(raw_dylib)]
+#![feature(abi_vectorcall)]
 
 #[link(name = "extern", kind = "raw-dylib", import_name_type = "undecorated")]
 extern "C" {
     fn cdecl_fn_undecorated(i: i32);
+    #[link_name = "cdecl_fn_undecorated2"]
+    fn cdecl_fn_undecorated_renamed(i: i32);
     static mut extern_variable_undecorated: i32;
 }
 
@@ -21,6 +24,8 @@ extern "C" {
 #[link(name = "extern", kind = "raw-dylib", import_name_type = "undecorated")]
 extern "stdcall" {
     fn stdcall_fn_undecorated(i: i32);
+    #[link_name = "stdcall_fn_undecorated2"]
+    fn stdcall_fn_undecorated_renamed(i: i32);
 }
 
 #[link(name = "extern", kind = "raw-dylib", import_name_type = "noprefix")]
@@ -36,6 +41,8 @@ extern "stdcall" {
 #[link(name = "extern", kind = "raw-dylib", import_name_type = "undecorated")]
 extern "fastcall" {
     fn fastcall_fn_undecorated(i: i32);
+    #[link_name = "fastcall_fn_undecorated2"]
+    fn fastcall_fn_undecorated_renamed(i: i32);
 }
 
 #[link(name = "extern", kind = "raw-dylib", import_name_type = "noprefix")]
@@ -48,6 +55,26 @@ extern "fastcall" {
     fn fastcall_fn_decorated(i: i32);
 }
 
+#[cfg(target_env = "msvc")]
+#[link(name = "extern", kind = "raw-dylib", import_name_type = "undecorated")]
+extern "vectorcall" {
+    fn vectorcall_fn_undecorated(i: i32);
+    #[link_name = "vectorcall_fn_undecorated2"]
+    fn vectorcall_fn_undecorated_renamed(i: i32);
+}
+
+#[cfg(target_env = "msvc")]
+#[link(name = "extern", kind = "raw-dylib", import_name_type = "noprefix")]
+extern "vectorcall" {
+    fn vectorcall_fn_noprefix(i: i32);
+}
+
+#[cfg(target_env = "msvc")]
+#[link(name = "extern", kind = "raw-dylib", import_name_type = "decorated")]
+extern "vectorcall" {
+    fn vectorcall_fn_decorated(i: i32);
+}
+
 #[link(name = "extern", kind = "raw-dylib")]
 extern {
     fn print_extern_variable_undecorated();
@@ -58,14 +85,17 @@ extern {
 pub fn main() {
     unsafe {
         cdecl_fn_undecorated(1);
+        cdecl_fn_undecorated_renamed(10);
         cdecl_fn_noprefix(2);
         cdecl_fn_decorated(3);
 
         stdcall_fn_undecorated(4);
+        stdcall_fn_undecorated_renamed(14);
         stdcall_fn_noprefix(5);
         stdcall_fn_decorated(6);
 
         fastcall_fn_undecorated(7);
+        fastcall_fn_undecorated_renamed(17);
         fastcall_fn_noprefix(8);
         fastcall_fn_decorated(9);
 
@@ -75,5 +105,21 @@ pub fn main() {
         print_extern_variable_noprefix();
         extern_variable_decorated = 44;
         print_extern_variable_decorated();
+
+        // GCC doesn't support vectorcall: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=89485
+        #[cfg(target_env = "msvc")]
+        {
+            vectorcall_fn_undecorated(10);
+            vectorcall_fn_undecorated_renamed(20);
+            vectorcall_fn_noprefix(11);
+            vectorcall_fn_decorated(12);
+        }
+        #[cfg(not(target_env = "msvc"))]
+        {
+            println!("vectorcall_fn_undecorated(10)");
+            println!("vectorcall_fn_undecorated2(20)");
+            println!("vectorcall_fn_noprefix(11)");
+            println!("vectorcall_fn_decorated(12)");
+        }
     }
 }
diff --git a/src/test/run-make/raw-dylib-import-name-type/extern.c b/src/test/run-make/raw-dylib-import-name-type/extern.c
index 1102158e249..195126d5129 100644
--- a/src/test/run-make/raw-dylib-import-name-type/extern.c
+++ b/src/test/run-make/raw-dylib-import-name-type/extern.c
@@ -6,6 +6,11 @@ void _cdecl cdecl_fn_undecorated(int i) {
     fflush(stdout);
 }
 
+void _cdecl cdecl_fn_undecorated2(int i) {
+    printf("cdecl_fn_undecorated2(%d)\n", i);
+    fflush(stdout);
+}
+
 void _cdecl cdecl_fn_noprefix(int i) {
     printf("cdecl_fn_noprefix(%d)\n", i);
     fflush(stdout);
@@ -21,6 +26,11 @@ void __stdcall stdcall_fn_undecorated(int i) {
     fflush(stdout);
 }
 
+void __stdcall stdcall_fn_undecorated2(int i) {
+    printf("stdcall_fn_undecorated2(%d)\n", i);
+    fflush(stdout);
+}
+
 void __stdcall stdcall_fn_noprefix(int i) {
     printf("stdcall_fn_noprefix(%d)\n", i);
     fflush(stdout);
@@ -36,6 +46,11 @@ void __fastcall fastcall_fn_undecorated(int i) {
     fflush(stdout);
 }
 
+void __fastcall fastcall_fn_undecorated2(int i) {
+    printf("fastcall_fn_undecorated2(%d)\n", i);
+    fflush(stdout);
+}
+
 void __fastcall fastcall_fn_noprefix(int i) {
     printf("fastcall_fn_noprefix(%d)\n", i);
     fflush(stdout);
@@ -63,3 +78,26 @@ __declspec(dllexport) void print_extern_variable_decorated() {
     printf("extern_variable_decorated value: %d\n", extern_variable_decorated);
     fflush(stdout);
 }
+
+// GCC doesn't support vectorcall: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=89485
+#ifdef _MSC_VER
+void __vectorcall vectorcall_fn_undecorated(int i) {
+    printf("vectorcall_fn_undecorated(%d)\n", i);
+    fflush(stdout);
+}
+
+void __vectorcall vectorcall_fn_undecorated2(int i) {
+    printf("vectorcall_fn_undecorated2(%d)\n", i);
+    fflush(stdout);
+}
+
+void __vectorcall vectorcall_fn_noprefix(int i) {
+    printf("vectorcall_fn_noprefix(%d)\n", i);
+    fflush(stdout);
+}
+
+void __vectorcall vectorcall_fn_decorated(int i) {
+    printf("vectorcall_fn_decorated(%d)\n", i);
+    fflush(stdout);
+}
+#endif
diff --git a/src/test/run-make/raw-dylib-import-name-type/extern.gnu.def b/src/test/run-make/raw-dylib-import-name-type/extern.gnu.def
index f06ce67e030..a523c959a47 100644
--- a/src/test/run-make/raw-dylib-import-name-type/extern.gnu.def
+++ b/src/test/run-make/raw-dylib-import-name-type/extern.gnu.def
@@ -1,11 +1,14 @@
 LIBRARY extern
 EXPORTS
     cdecl_fn_undecorated
+    cdecl_fn_undecorated2
     cdecl_fn_noprefix
     cdecl_fn_decorated
     stdcall_fn_undecorated
+    stdcall_fn_undecorated2
     stdcall_fn_noprefix@4
     fastcall_fn_undecorated
+    fastcall_fn_undecorated2
     @fastcall_fn_decorated@4
 
     ;ld doesn't handle fully-decorated stdcall, or no-prefix fastcall
diff --git a/src/test/run-make/raw-dylib-import-name-type/extern.msvc.def b/src/test/run-make/raw-dylib-import-name-type/extern.msvc.def
index 9dc333707cb..dbff32d4c90 100644
--- a/src/test/run-make/raw-dylib-import-name-type/extern.msvc.def
+++ b/src/test/run-make/raw-dylib-import-name-type/extern.msvc.def
@@ -1,12 +1,19 @@
 LIBRARY extern
 EXPORTS
     cdecl_fn_undecorated
+    cdecl_fn_undecorated2
     cdecl_fn_noprefix
     cdecl_fn_decorated
     stdcall_fn_undecorated
+    stdcall_fn_undecorated2
     _stdcall_fn_decorated@4
     fastcall_fn_undecorated
+    fastcall_fn_undecorated2
     @fastcall_fn_decorated@4
+    vectorcall_fn_undecorated
+    vectorcall_fn_undecorated2
+    vectorcall_fn_decorated@@4
+    vectorcall_fn_noprefix@@4
 
     ;MSVC doesn't seem to recognize the "no prefix" syntax.
     stdcall_fn_noprefix@4=_stdcall_fn_noprefix@4
diff --git a/src/test/run-make/raw-dylib-import-name-type/output.txt b/src/test/run-make/raw-dylib-import-name-type/output.txt
index 855b20a8645..707faf403ae 100644
--- a/src/test/run-make/raw-dylib-import-name-type/output.txt
+++ b/src/test/run-make/raw-dylib-import-name-type/output.txt
@@ -1,12 +1,19 @@
 cdecl_fn_undecorated(1)
+cdecl_fn_undecorated2(10)
 cdecl_fn_noprefix(2)
 cdecl_fn_decorated(3)
 stdcall_fn_undecorated(4)
+stdcall_fn_undecorated2(14)
 stdcall_fn_noprefix(5)
 stdcall_fn_decorated(6)
 fastcall_fn_undecorated(7)
+fastcall_fn_undecorated2(17)
 fastcall_fn_noprefix(8)
 fastcall_fn_decorated(9)
 extern_variable_undecorated value: 42
 extern_variable_noprefix value: 43
 extern_variable_decorated value: 44
+vectorcall_fn_undecorated(10)
+vectorcall_fn_undecorated2(20)
+vectorcall_fn_noprefix(11)
+vectorcall_fn_decorated(12)
diff --git a/src/test/rustdoc-json/type/extern.rs b/src/test/rustdoc-json/type/extern.rs
new file mode 100644
index 00000000000..d287d5ebec5
--- /dev/null
+++ b/src/test/rustdoc-json/type/extern.rs
@@ -0,0 +1,10 @@
+#![feature(extern_types)]
+
+extern {
+    /// No inner information
+    pub type Foo;
+}
+
+// @is "$.index[*][?(@.docs=='No inner information')].name" '"Foo"'
+// @is "$.index[*][?(@.docs=='No inner information')].kind" '"foreign_type"'
+// @!has "$.index[*][?(@.docs=='No inner information')].inner"
diff --git a/src/test/ui/async-await/async-await-let-else.no-drop-tracking.stderr b/src/test/ui/async-await/async-await-let-else.no-drop-tracking.stderr
index 435cc845870..7f93563e288 100644
--- a/src/test/ui/async-await/async-await-let-else.no-drop-tracking.stderr
+++ b/src/test/ui/async-await/async-await-let-else.no-drop-tracking.stderr
@@ -35,7 +35,7 @@ LL |         bar2(Rc::new(())).await
    |              |
    |              has type `Rc<()>` which is not `Send`
 LL |     };
-   |      - `Rc::new(())` is later dropped here
+   |     - `Rc::new(())` is later dropped here
 note: required by a bound in `is_send`
   --> $DIR/async-await-let-else.rs:19:15
    |
diff --git a/src/test/ui/closure-expected-type/expect-fn-supply-fn.stderr b/src/test/ui/closure-expected-type/expect-fn-supply-fn.stderr
index 26f47eb684d..284fc1c21f5 100644
--- a/src/test/ui/closure-expected-type/expect-fn-supply-fn.stderr
+++ b/src/test/ui/closure-expected-type/expect-fn-supply-fn.stderr
@@ -25,8 +25,8 @@ error[E0308]: mismatched types
 LL |     with_closure_expecting_fn_with_free_region(|x: fn(&u32), y| {});
    |                                                 ^ one type is more general than the other
    |
-   = note: expected fn pointer `for<'r> fn(&'r u32)`
-              found fn pointer `fn(&u32)`
+   = note: expected fn pointer `fn(&u32)`
+              found fn pointer `for<'r> fn(&'r u32)`
 
 error[E0308]: mismatched types
   --> $DIR/expect-fn-supply-fn.rs:39:50
@@ -34,8 +34,8 @@ error[E0308]: mismatched types
 LL |     with_closure_expecting_fn_with_bound_region(|x: fn(&'x u32), y| {});
    |                                                  ^ one type is more general than the other
    |
-   = note: expected fn pointer `fn(&'x u32)`
-              found fn pointer `for<'r> fn(&'r u32)`
+   = note: expected fn pointer `for<'r> fn(&'r u32)`
+              found fn pointer `fn(&u32)`
 
 error[E0308]: mismatched types
   --> $DIR/expect-fn-supply-fn.rs:48:50
@@ -43,8 +43,8 @@ error[E0308]: mismatched types
 LL |     with_closure_expecting_fn_with_bound_region(|x: Foo<'_>, y| {
    |                                                  ^ one type is more general than the other
    |
-   = note: expected fn pointer `fn(&u32)`
-              found fn pointer `for<'r> fn(&'r u32)`
+   = note: expected fn pointer `for<'r> fn(&'r u32)`
+              found fn pointer `fn(&u32)`
 
 error: aborting due to 5 previous errors
 
diff --git a/src/test/ui/closure-expected-type/expect-two-infer-vars-supply-ty-with-bound-region.stderr b/src/test/ui/closure-expected-type/expect-two-infer-vars-supply-ty-with-bound-region.stderr
index db7586bee49..d5432755cfe 100644
--- a/src/test/ui/closure-expected-type/expect-two-infer-vars-supply-ty-with-bound-region.stderr
+++ b/src/test/ui/closure-expected-type/expect-two-infer-vars-supply-ty-with-bound-region.stderr
@@ -6,7 +6,7 @@ LL |     with_closure(|x: u32, y| {});
    |
 help: consider giving this closure parameter an explicit type
    |
-LL |     with_closure(|x: u32, y: B| {});
+LL |     with_closure(|x: u32, y: _| {});
    |                            +++
 
 error: aborting due to previous error
diff --git a/src/test/ui/let-else/issue-99975.rs b/src/test/ui/let-else/issue-99975.rs
new file mode 100644
index 00000000000..80f63556194
--- /dev/null
+++ b/src/test/ui/let-else/issue-99975.rs
@@ -0,0 +1,20 @@
+// run-pass
+// compile-flags: -C opt-level=3 -Zvalidate-mir
+
+#![feature(let_else)]
+
+fn return_result() -> Option<String> {
+    Some("ok".to_string())
+}
+
+fn start() -> String {
+    let Some(content) = return_result() else {
+        return "none".to_string()
+    };
+
+    content
+}
+
+fn main() {
+    start();
+}
diff --git a/src/test/ui/let-else/let-else-temporary-lifetime.rs b/src/test/ui/let-else/let-else-temporary-lifetime.rs
index 07fcc16e7bb..8542c3496b0 100644
--- a/src/test/ui/let-else/let-else-temporary-lifetime.rs
+++ b/src/test/ui/let-else/let-else-temporary-lifetime.rs
@@ -1,4 +1,5 @@
 // run-pass
+// compile-flags: -Zvalidate-mir
 #![feature(let_else)]
 
 use std::fmt::Display;
diff --git a/src/test/ui/type-alias-impl-trait/closure_args.rs b/src/test/ui/type-alias-impl-trait/closure_args.rs
new file mode 100644
index 00000000000..c5e7af81d3d
--- /dev/null
+++ b/src/test/ui/type-alias-impl-trait/closure_args.rs
@@ -0,0 +1,16 @@
+// check-pass
+
+// regression test for https://github.com/rust-lang/rust/issues/100800
+
+#![feature(type_alias_impl_trait)]
+
+trait Anything {}
+impl<T> Anything for T {}
+type Input = impl Anything;
+fn run<F: FnOnce(Input) -> ()>(f: F, i: Input) {
+    f(i);
+}
+
+fn main() {
+    run(|x: u32| {println!("{x}");}, 0);
+}
diff --git a/src/test/ui/type-alias-impl-trait/closure_args2.rs b/src/test/ui/type-alias-impl-trait/closure_args2.rs
new file mode 100644
index 00000000000..82386c280a8
--- /dev/null
+++ b/src/test/ui/type-alias-impl-trait/closure_args2.rs
@@ -0,0 +1,23 @@
+// run-pass
+
+#![feature(type_alias_impl_trait)]
+
+trait Foo {
+    // This was reachable in https://github.com/rust-lang/rust/issues/100800
+    fn foo(&self) { unreachable!() }
+}
+impl<T> Foo for T {}
+
+struct B;
+impl B {
+    fn foo(&self) {}
+}
+
+type Input = impl Foo;
+fn run1<F: FnOnce(Input)>(f: F, i: Input) {f(i)}
+fn run2<F: FnOnce(B)>(f: F, i: B) {f(i)}
+
+fn main() {
+    run1(|x: B| {x.foo()}, B);
+    run2(|x: B| {x.foo()}, B);
+}
diff --git a/src/test/ui/type-alias-impl-trait/issue-60371.stderr b/src/test/ui/type-alias-impl-trait/issue-60371.stderr
index 082b0f0c309..d0c04371bd7 100644
--- a/src/test/ui/type-alias-impl-trait/issue-60371.stderr
+++ b/src/test/ui/type-alias-impl-trait/issue-60371.stderr
@@ -11,7 +11,7 @@ error[E0277]: the trait bound `(): Bug` is not satisfied
   --> $DIR/issue-60371.rs:10:40
    |
 LL |     const FUN: fn() -> Self::Item = || ();
-   |                                        ^ the trait `Bug` is not implemented for `()`
+   |                                        ^^ the trait `Bug` is not implemented for `()`
    |
    = help: the trait `Bug` is implemented for `&()`
 
diff --git a/src/test/ui/unsized/issue-75899-but-gats.rs b/src/test/ui/unsized/issue-75899-but-gats.rs
new file mode 100644
index 00000000000..5716817f43d
--- /dev/null
+++ b/src/test/ui/unsized/issue-75899-but-gats.rs
@@ -0,0 +1,21 @@
+// check-pass
+
+use std::fmt::Debug;
+use std::marker::PhantomData;
+
+trait Foo {
+    type Gat<'a>: ?Sized where Self: 'a;
+}
+
+struct Bar<'a, T: Foo + 'a>(T::Gat<'a>);
+
+struct Baz<T: ?Sized>(PhantomData<T>);
+
+impl<T: ?Sized> Foo for Baz<T> {
+    type Gat<'a> = T where Self: 'a;
+}
+
+fn main() {
+    let x = Bar::<'_, Baz<()>>(());
+    let y: &Bar<'_, Baz<dyn Debug>> = &x;
+}
diff --git a/src/test/ui/unsized/issue-75899.rs b/src/test/ui/unsized/issue-75899.rs
new file mode 100644
index 00000000000..abff17e11b5
--- /dev/null
+++ b/src/test/ui/unsized/issue-75899.rs
@@ -0,0 +1,18 @@
+// check-pass
+
+trait Trait {}
+impl<T> Trait for T {}
+
+trait Noop {
+    type Assoc: ?Sized;
+}
+impl<T: ?Sized> Noop for T {
+    type Assoc = T;
+}
+
+struct NoopNewtype<T: ?Sized + Noop>(T::Assoc);
+fn coerce_newtype<T: Trait>(x: &NoopNewtype<T>) -> &NoopNewtype<dyn Trait + '_> {
+    x
+}
+
+fn main() {}
diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs
index 6f17b9e1be9..64df76e2772 100644
--- a/src/tools/compiletest/src/common.rs
+++ b/src/tools/compiletest/src/common.rs
@@ -203,6 +203,9 @@ pub struct Config {
     /// The jsondocck executable.
     pub jsondocck_path: Option<String>,
 
+    /// The jsondoclint executable.
+    pub jsondoclint_path: Option<String>,
+
     /// The LLVM `FileCheck` binary path.
     pub llvm_filecheck: Option<PathBuf>,
 
diff --git a/src/tools/compiletest/src/main.rs b/src/tools/compiletest/src/main.rs
index 0e2cc52a645..38c7b87fc0d 100644
--- a/src/tools/compiletest/src/main.rs
+++ b/src/tools/compiletest/src/main.rs
@@ -64,6 +64,7 @@ pub fn parse_config(args: Vec<String>) -> Config {
         .optopt("", "rust-demangler-path", "path to rust-demangler to use in tests", "PATH")
         .reqopt("", "python", "path to python to use for doc tests", "PATH")
         .optopt("", "jsondocck-path", "path to jsondocck to use for doc tests", "PATH")
+        .optopt("", "jsondoclint-path", "path to jsondoclint to use for doc tests", "PATH")
         .optopt("", "valgrind-path", "path to Valgrind executable for Valgrind tests", "PROGRAM")
         .optflag("", "force-valgrind", "fail if Valgrind tests cannot be run under Valgrind")
         .optopt("", "run-clang-based-tests-with", "path to Clang executable", "PATH")
@@ -226,6 +227,7 @@ pub fn parse_config(args: Vec<String>) -> Config {
         rust_demangler_path: matches.opt_str("rust-demangler-path").map(PathBuf::from),
         python: matches.opt_str("python").unwrap(),
         jsondocck_path: matches.opt_str("jsondocck-path"),
+        jsondoclint_path: matches.opt_str("jsondoclint-path"),
         valgrind_path: matches.opt_str("valgrind-path"),
         force_valgrind: matches.opt_present("force-valgrind"),
         run_clang_based_tests_with: matches.opt_str("run-clang-based-tests-with"),
diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs
index e2afa5ef590..8f289876f73 100644
--- a/src/tools/compiletest/src/runtest.rs
+++ b/src/tools/compiletest/src/runtest.rs
@@ -2563,14 +2563,13 @@ impl<'test> TestCx<'test> {
 
         let mut json_out = out_dir.join(self.testpaths.file.file_stem().unwrap());
         json_out.set_extension("json");
+
         let res = self.cmd2procres(
-            Command::new(&self.config.python)
-                .arg(root.join("src/etc/check_missing_items.py"))
-                .arg(&json_out),
+            Command::new(self.config.jsondoclint_path.as_ref().unwrap()).arg(&json_out),
         );
 
         if !res.status.success() {
-            self.fatal_proc_rec("check_missing_items failed!", &res);
+            self.fatal_proc_rec("jsondoclint failed!", &res);
         }
     }
 
diff --git a/src/tools/jsondoclint/Cargo.toml b/src/tools/jsondoclint/Cargo.toml
new file mode 100644
index 00000000000..84a6c7f96c4
--- /dev/null
+++ b/src/tools/jsondoclint/Cargo.toml
@@ -0,0 +1,12 @@
+[package]
+name = "jsondoclint"
+version = "0.1.0"
+edition = "2021"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
+anyhow = "1.0.62"
+fs-err = "2.8.1"
+rustdoc-json-types = { version = "0.1.0", path = "../../rustdoc-json-types" }
+serde_json = "1.0.85"
diff --git a/src/tools/jsondoclint/src/item_kind.rs b/src/tools/jsondoclint/src/item_kind.rs
new file mode 100644
index 00000000000..ad8e96a0bd8
--- /dev/null
+++ b/src/tools/jsondoclint/src/item_kind.rs
@@ -0,0 +1,184 @@
+use rustdoc_json_types::{Item, ItemEnum, ItemKind, ItemSummary};
+
+/// A univeral way to represent an [`ItemEnum`] or [`ItemKind`]
+#[derive(Debug)]
+pub(crate) enum Kind {
+    Module,
+    ExternCrate,
+    Import,
+    Struct,
+    StructField,
+    Union,
+    Enum,
+    Variant,
+    Function,
+    Typedef,
+    OpaqueTy,
+    Constant,
+    Trait,
+    TraitAlias,
+    Method,
+    Impl,
+    Static,
+    ForeignType,
+    Macro,
+    ProcAttribute,
+    ProcDerive,
+    AssocConst,
+    AssocType,
+    Primitive,
+    Keyword,
+    // Not in ItemKind
+    ProcMacro,
+}
+
+impl Kind {
+    pub fn can_appear_in_mod(self) -> bool {
+        use Kind::*;
+        match self {
+            Module => true,
+            ExternCrate => true,
+            Import => true,
+            Union => true,
+            Struct => true,
+            Enum => true,
+            Function => true,
+            Trait => true,
+            TraitAlias => true,
+            Impl => true,
+            Typedef => true,
+            Constant => true,
+            Static => true,
+            Macro => true,
+            ProcMacro => true,
+            Primitive => true,
+            ForeignType => true,
+
+            // FIXME(adotinthevoid): I'm not sure if these are corrent
+            Keyword => false,
+            OpaqueTy => false,
+            ProcAttribute => false,
+            ProcDerive => false,
+
+            // Only in traits
+            AssocConst => false,
+            AssocType => false,
+            Method => false,
+
+            StructField => false, // Only in structs or variants
+            Variant => false,     // Only in enums
+        }
+    }
+
+    pub fn can_appear_in_trait(self) -> bool {
+        match self {
+            Kind::AssocConst => true,
+            Kind::AssocType => true,
+            Kind::Method => true,
+
+            Kind::Module => false,
+            Kind::ExternCrate => false,
+            Kind::Import => false,
+            Kind::Struct => false,
+            Kind::StructField => false,
+            Kind::Union => false,
+            Kind::Enum => false,
+            Kind::Variant => false,
+            Kind::Function => false,
+            Kind::Typedef => false,
+            Kind::OpaqueTy => false,
+            Kind::Constant => false,
+            Kind::Trait => false,
+            Kind::TraitAlias => false,
+            Kind::Impl => false,
+            Kind::Static => false,
+            Kind::ForeignType => false,
+            Kind::Macro => false,
+            Kind::ProcAttribute => false,
+            Kind::ProcDerive => false,
+            Kind::Primitive => false,
+            Kind::Keyword => false,
+            Kind::ProcMacro => false,
+        }
+    }
+
+    pub fn is_struct_field(self) -> bool {
+        matches!(self, Kind::StructField)
+    }
+    pub fn is_module(self) -> bool {
+        matches!(self, Kind::Module)
+    }
+    pub fn is_impl(self) -> bool {
+        matches!(self, Kind::Impl)
+    }
+    pub fn is_variant(self) -> bool {
+        matches!(self, Kind::Variant)
+    }
+    pub fn is_trait(self) -> bool {
+        matches!(self, Kind::Trait)
+    }
+    pub fn is_struct_enum_union(self) -> bool {
+        matches!(self, Kind::Struct | Kind::Enum | Kind::Union)
+    }
+
+    pub fn from_item(i: &Item) -> Self {
+        use Kind::*;
+        match i.inner {
+            ItemEnum::Module(_) => Module,
+            ItemEnum::Import(_) => Import,
+            ItemEnum::Union(_) => Union,
+            ItemEnum::Struct(_) => Struct,
+            ItemEnum::StructField(_) => StructField,
+            ItemEnum::Enum(_) => Enum,
+            ItemEnum::Variant(_) => Variant,
+            ItemEnum::Function(_) => Function,
+            ItemEnum::Trait(_) => Trait,
+            ItemEnum::TraitAlias(_) => TraitAlias,
+            ItemEnum::Method(_) => Method,
+            ItemEnum::Impl(_) => Impl,
+            ItemEnum::Typedef(_) => Typedef,
+            ItemEnum::OpaqueTy(_) => OpaqueTy,
+            ItemEnum::Constant(_) => Constant,
+            ItemEnum::Static(_) => Static,
+            ItemEnum::Macro(_) => Macro,
+            ItemEnum::ProcMacro(_) => ProcMacro,
+            // https://github.com/rust-lang/rust/issues/100961
+            ItemEnum::PrimitiveType(_) => Primitive,
+            ItemEnum::ForeignType => ForeignType,
+            ItemEnum::ExternCrate { .. } => ExternCrate,
+            ItemEnum::AssocConst { .. } => AssocConst,
+            ItemEnum::AssocType { .. } => AssocType,
+        }
+    }
+
+    pub fn from_summary(s: &ItemSummary) -> Self {
+        use Kind::*;
+        match s.kind {
+            ItemKind::AssocConst => AssocConst,
+            ItemKind::AssocType => AssocType,
+            ItemKind::Constant => Constant,
+            ItemKind::Enum => Enum,
+            ItemKind::ExternCrate => ExternCrate,
+            ItemKind::ForeignType => ForeignType,
+            ItemKind::Function => Function,
+            ItemKind::Impl => Impl,
+            ItemKind::Import => Import,
+            ItemKind::Keyword => Keyword,
+            ItemKind::Macro => Macro,
+            ItemKind::Method => Method,
+            ItemKind::Module => Module,
+            ItemKind::OpaqueTy => OpaqueTy,
+            ItemKind::Primitive => Primitive,
+            ItemKind::ProcAttribute => ProcAttribute,
+            ItemKind::ProcDerive => ProcDerive,
+            ItemKind::Static => Static,
+            ItemKind::Struct => Struct,
+            ItemKind::StructField => StructField,
+            ItemKind::Trait => Trait,
+            ItemKind::TraitAlias => TraitAlias,
+            ItemKind::Typedef => Typedef,
+            ItemKind::Union => Union,
+            ItemKind::Variant => Variant,
+        }
+    }
+}
diff --git a/src/tools/jsondoclint/src/json_find.rs b/src/tools/jsondoclint/src/json_find.rs
new file mode 100644
index 00000000000..95ea8866609
--- /dev/null
+++ b/src/tools/jsondoclint/src/json_find.rs
@@ -0,0 +1,74 @@
+use std::fmt::Write;
+
+use serde_json::Value;
+
+#[derive(Debug, Clone)]
+pub enum SelectorPart {
+    Field(String),
+    Index(usize),
+}
+
+pub type Selector = Vec<SelectorPart>;
+
+pub fn to_jsonpath(sel: &Selector) -> String {
+    let mut s = String::from("$");
+    for part in sel {
+        match part {
+            SelectorPart::Field(name) => {
+                if is_jsonpath_safe(name) {
+                    write!(&mut s, ".{}", name).unwrap();
+                } else {
+                    // This is probably wrong in edge cases, but all Id's are
+                    // just ascii alphanumerics, `-` `_`, and `:`
+                    write!(&mut s, "[{name:?}]").unwrap();
+                }
+            }
+            SelectorPart::Index(idx) => write!(&mut s, "[{idx}]").unwrap(),
+        }
+    }
+    s
+}
+
+fn is_jsonpath_safe(s: &str) -> bool {
+    s.chars().all(|c| c.is_ascii_alphanumeric() || c == '_')
+}
+
+pub fn find_selector(haystack: &Value, needle: &Value) -> Vec<Selector> {
+    let mut result = Vec::new();
+    let mut sel = Selector::new();
+    find_selector_recursive(haystack, needle, &mut result, &mut sel);
+    result
+}
+
+fn find_selector_recursive(
+    haystack: &Value,
+    needle: &Value,
+    result: &mut Vec<Selector>,
+    pos: &mut Selector,
+) {
+    if needle == haystack {
+        result.push(pos.clone());
+        // Haystack cant both contain needle and be needle
+    } else {
+        match haystack {
+            Value::Null => {}
+            Value::Bool(_) => {}
+            Value::Number(_) => {}
+            Value::String(_) => {}
+            Value::Array(arr) => {
+                for (idx, subhaystack) in arr.iter().enumerate() {
+                    pos.push(SelectorPart::Index(idx));
+                    find_selector_recursive(subhaystack, needle, result, pos);
+                    pos.pop().unwrap();
+                }
+            }
+            Value::Object(obj) => {
+                for (key, subhaystack) in obj {
+                    pos.push(SelectorPart::Field(key.clone()));
+                    find_selector_recursive(subhaystack, needle, result, pos);
+                    pos.pop().unwrap();
+                }
+            }
+        }
+    }
+}
diff --git a/src/tools/jsondoclint/src/main.rs b/src/tools/jsondoclint/src/main.rs
new file mode 100644
index 00000000000..70d7a82a576
--- /dev/null
+++ b/src/tools/jsondoclint/src/main.rs
@@ -0,0 +1,64 @@
+use std::env;
+
+use anyhow::{anyhow, bail, Result};
+use fs_err as fs;
+use rustdoc_json_types::{Crate, Id, FORMAT_VERSION};
+use serde_json::Value;
+
+pub(crate) mod item_kind;
+mod json_find;
+mod validator;
+
+#[derive(Debug)]
+struct Error {
+    kind: ErrorKind,
+    id: Id,
+}
+
+#[derive(Debug)]
+enum ErrorKind {
+    NotFound,
+    Custom(String),
+}
+
+fn main() -> Result<()> {
+    let path = env::args().nth(1).ok_or_else(|| anyhow!("no path given"))?;
+    let contents = fs::read_to_string(&path)?;
+    let krate: Crate = serde_json::from_str(&contents)?;
+    assert_eq!(krate.format_version, FORMAT_VERSION);
+
+    let mut validator = validator::Validator::new(&krate);
+    validator.check_crate();
+
+    if !validator.errs.is_empty() {
+        for err in validator.errs {
+            match err.kind {
+                ErrorKind::NotFound => {
+                    let krate_json: Value = serde_json::from_str(&contents)?;
+
+                    let sels =
+                        json_find::find_selector(&krate_json, &Value::String(err.id.0.clone()));
+                    match &sels[..] {
+                        [] => unreachable!(
+                            "id must be in crate, or it wouldn't be reported as not found"
+                        ),
+                        [sel] => eprintln!(
+                            "{} not in index or paths, but refered to at '{}'",
+                            err.id.0,
+                            json_find::to_jsonpath(&sel)
+                        ),
+                        [sel, ..] => eprintln!(
+                            "{} not in index or paths, but refered to at '{}' and more",
+                            err.id.0,
+                            json_find::to_jsonpath(&sel)
+                        ),
+                    }
+                }
+                ErrorKind::Custom(msg) => eprintln!("{}: {}", err.id.0, msg),
+            }
+        }
+        bail!("Errors validating json {path}");
+    }
+
+    Ok(())
+}
diff --git a/src/tools/jsondoclint/src/validator.rs b/src/tools/jsondoclint/src/validator.rs
new file mode 100644
index 00000000000..a0e77127dc2
--- /dev/null
+++ b/src/tools/jsondoclint/src/validator.rs
@@ -0,0 +1,442 @@
+use std::collections::HashSet;
+use std::hash::Hash;
+
+use rustdoc_json_types::{
+    Constant, Crate, DynTrait, Enum, FnDecl, Function, FunctionPointer, GenericArg, GenericArgs,
+    GenericBound, GenericParamDef, Generics, Id, Impl, Import, ItemEnum, Method, Module, OpaqueTy,
+    Path, ProcMacro, Static, Struct, StructKind, Term, Trait, TraitAlias, Type, TypeBinding,
+    TypeBindingKind, Typedef, Union, Variant, WherePredicate,
+};
+
+use crate::{item_kind::Kind, Error, ErrorKind};
+
+/// The Validator walks over the JSON tree, and ensures it is well formed.
+/// It is made of several parts.
+///
+/// - `check_*`: These take a type from [`rustdoc_json_types`], and check that
+///              it is well formed. This involves calling `check_*` functions on
+///              fields of that item, and `add_*` functions on [`Id`]s.
+/// - `add_*`: These add an [`Id`] to the worklist, after validating it to check if
+///            the `Id` is a kind expected in this suituation.
+#[derive(Debug)]
+pub struct Validator<'a> {
+    pub(crate) errs: Vec<Error>,
+    krate: &'a Crate,
+    /// Worklist of Ids to check.
+    todo: HashSet<&'a Id>,
+    /// Ids that have already been visited, so don't need to be checked again.
+    seen_ids: HashSet<&'a Id>,
+    /// Ids that have already been reported missing.
+    missing_ids: HashSet<&'a Id>,
+}
+
+enum PathKind {
+    Trait,
+    StructEnumUnion,
+}
+
+impl<'a> Validator<'a> {
+    pub fn new(krate: &'a Crate) -> Self {
+        Self {
+            krate,
+            errs: Vec::new(),
+            seen_ids: HashSet::new(),
+            todo: HashSet::new(),
+            missing_ids: HashSet::new(),
+        }
+    }
+
+    pub fn check_crate(&mut self) {
+        let root = &self.krate.root;
+        self.add_mod_id(root);
+        while let Some(id) = set_remove(&mut self.todo) {
+            self.seen_ids.insert(id);
+            self.check_item(id);
+        }
+    }
+
+    fn check_item(&mut self, id: &'a Id) {
+        if let Some(item) = &self.krate.index.get(id) {
+            match &item.inner {
+                ItemEnum::Import(x) => self.check_import(x),
+                ItemEnum::Union(x) => self.check_union(x),
+                ItemEnum::Struct(x) => self.check_struct(x),
+                ItemEnum::StructField(x) => self.check_struct_field(x),
+                ItemEnum::Enum(x) => self.check_enum(x),
+                ItemEnum::Variant(x) => self.check_variant(x, id),
+                ItemEnum::Function(x) => self.check_function(x),
+                ItemEnum::Trait(x) => self.check_trait(x),
+                ItemEnum::TraitAlias(x) => self.check_trait_alias(x),
+                ItemEnum::Method(x) => self.check_method(x),
+                ItemEnum::Impl(x) => self.check_impl(x),
+                ItemEnum::Typedef(x) => self.check_typedef(x),
+                ItemEnum::OpaqueTy(x) => self.check_opaque_ty(x),
+                ItemEnum::Constant(x) => self.check_constant(x),
+                ItemEnum::Static(x) => self.check_static(x),
+                ItemEnum::ForeignType => {} // nop
+                ItemEnum::Macro(x) => self.check_macro(x),
+                ItemEnum::ProcMacro(x) => self.check_proc_macro(x),
+                ItemEnum::PrimitiveType(x) => self.check_primitive_type(x),
+                ItemEnum::Module(x) => self.check_module(x),
+                // FIXME: Why don't these have their own structs?
+                ItemEnum::ExternCrate { .. } => {}
+                ItemEnum::AssocConst { type_, default: _ } => self.check_type(type_),
+                ItemEnum::AssocType { generics, bounds, default } => {
+                    self.check_generics(generics);
+                    bounds.iter().for_each(|b| self.check_generic_bound(b));
+                    if let Some(ty) = default {
+                        self.check_type(ty);
+                    }
+                }
+            }
+        } else {
+            assert!(self.krate.paths.contains_key(id));
+        }
+    }
+
+    // Core checkers
+    fn check_module(&mut self, module: &'a Module) {
+        module.items.iter().for_each(|i| self.add_mod_item_id(i));
+    }
+
+    fn check_import(&mut self, x: &'a Import) {
+        if x.glob {
+            self.add_mod_id(x.id.as_ref().unwrap());
+        } else if let Some(id) = &x.id {
+            self.add_mod_item_id(id);
+        }
+    }
+
+    fn check_union(&mut self, x: &'a Union) {
+        self.check_generics(&x.generics);
+        x.fields.iter().for_each(|i| self.add_field_id(i));
+        x.impls.iter().for_each(|i| self.add_impl_id(i));
+    }
+
+    fn check_struct(&mut self, x: &'a Struct) {
+        self.check_generics(&x.generics);
+        match &x.kind {
+            StructKind::Unit => {}
+            StructKind::Tuple(fields) => fields.iter().flatten().for_each(|f| self.add_field_id(f)),
+            StructKind::Plain { fields, fields_stripped: _ } => {
+                fields.iter().for_each(|f| self.add_field_id(f))
+            }
+        }
+        x.impls.iter().for_each(|i| self.add_impl_id(i));
+    }
+
+    fn check_struct_field(&mut self, x: &'a Type) {
+        self.check_type(x);
+    }
+
+    fn check_enum(&mut self, x: &'a Enum) {
+        self.check_generics(&x.generics);
+        x.variants.iter().for_each(|i| self.add_variant_id(i));
+        x.impls.iter().for_each(|i| self.add_impl_id(i));
+    }
+
+    fn check_variant(&mut self, x: &'a Variant, id: &'a Id) {
+        match x {
+            Variant::Plain(discr) => {
+                if let Some(discr) = discr {
+                    if let (Err(_), Err(_)) =
+                        (discr.value.parse::<i128>(), discr.value.parse::<u128>())
+                    {
+                        self.fail(
+                            id,
+                            ErrorKind::Custom(format!(
+                                "Failed to parse discriminant value `{}`",
+                                discr.value
+                            )),
+                        );
+                    }
+                }
+            }
+            Variant::Tuple(tys) => tys.iter().flatten().for_each(|t| self.add_field_id(t)),
+            Variant::Struct { fields, fields_stripped: _ } => {
+                fields.iter().for_each(|f| self.add_field_id(f))
+            }
+        }
+    }
+
+    fn check_function(&mut self, x: &'a Function) {
+        self.check_generics(&x.generics);
+        self.check_fn_decl(&x.decl);
+    }
+
+    fn check_trait(&mut self, x: &'a Trait) {
+        self.check_generics(&x.generics);
+        x.items.iter().for_each(|i| self.add_trait_item_id(i));
+        x.bounds.iter().for_each(|i| self.check_generic_bound(i));
+        x.implementations.iter().for_each(|i| self.add_impl_id(i));
+    }
+
+    fn check_trait_alias(&mut self, x: &'a TraitAlias) {
+        self.check_generics(&x.generics);
+        x.params.iter().for_each(|i| self.check_generic_bound(i));
+    }
+
+    fn check_method(&mut self, x: &'a Method) {
+        self.check_fn_decl(&x.decl);
+        self.check_generics(&x.generics);
+    }
+
+    fn check_impl(&mut self, x: &'a Impl) {
+        self.check_generics(&x.generics);
+        if let Some(path) = &x.trait_ {
+            self.check_path(path, PathKind::Trait);
+        }
+        self.check_type(&x.for_);
+        x.items.iter().for_each(|i| self.add_trait_item_id(i));
+        if let Some(blanket_impl) = &x.blanket_impl {
+            self.check_type(blanket_impl)
+        }
+    }
+
+    fn check_typedef(&mut self, x: &'a Typedef) {
+        self.check_generics(&x.generics);
+        self.check_type(&x.type_);
+    }
+
+    fn check_opaque_ty(&mut self, x: &'a OpaqueTy) {
+        x.bounds.iter().for_each(|b| self.check_generic_bound(b));
+        self.check_generics(&x.generics);
+    }
+
+    fn check_constant(&mut self, x: &'a Constant) {
+        self.check_type(&x.type_);
+    }
+
+    fn check_static(&mut self, x: &'a Static) {
+        self.check_type(&x.type_);
+    }
+
+    fn check_macro(&mut self, _: &'a str) {
+        // nop
+    }
+
+    fn check_proc_macro(&mut self, _: &'a ProcMacro) {
+        // nop
+    }
+
+    fn check_primitive_type(&mut self, _: &'a str) {
+        // nop
+    }
+
+    fn check_generics(&mut self, x: &'a Generics) {
+        x.params.iter().for_each(|p| self.check_generic_param_def(p));
+        x.where_predicates.iter().for_each(|w| self.check_where_predicate(w));
+    }
+
+    fn check_type(&mut self, x: &'a Type) {
+        match x {
+            Type::ResolvedPath(path) => self.check_path(path, PathKind::StructEnumUnion),
+            Type::DynTrait(dyn_trait) => self.check_dyn_trait(dyn_trait),
+            Type::Generic(_) => {}
+            Type::Primitive(_) => {}
+            Type::FunctionPointer(fp) => self.check_function_pointer(&**fp),
+            Type::Tuple(tys) => tys.iter().for_each(|ty| self.check_type(ty)),
+            Type::Slice(inner) => self.check_type(&**inner),
+            Type::Array { type_, len: _ } => self.check_type(&**type_),
+            Type::ImplTrait(bounds) => bounds.iter().for_each(|b| self.check_generic_bound(b)),
+            Type::Infer => {}
+            Type::RawPointer { mutable: _, type_ } => self.check_type(&**type_),
+            Type::BorrowedRef { lifetime: _, mutable: _, type_ } => self.check_type(&**type_),
+            Type::QualifiedPath { name: _, args, self_type, trait_ } => {
+                self.check_generic_args(&**args);
+                self.check_type(&**self_type);
+                self.check_path(trait_, PathKind::Trait);
+            }
+        }
+    }
+
+    fn check_fn_decl(&mut self, x: &'a FnDecl) {
+        x.inputs.iter().for_each(|(_name, ty)| self.check_type(ty));
+        if let Some(output) = &x.output {
+            self.check_type(output);
+        }
+    }
+
+    fn check_generic_bound(&mut self, x: &'a GenericBound) {
+        match x {
+            GenericBound::TraitBound { trait_, generic_params, modifier: _ } => {
+                self.check_path(trait_, PathKind::Trait);
+                generic_params.iter().for_each(|gpd| self.check_generic_param_def(gpd));
+            }
+            GenericBound::Outlives(_) => {}
+        }
+    }
+
+    fn check_path(&mut self, x: &'a Path, kind: PathKind) {
+        match kind {
+            PathKind::Trait => self.add_trait_id(&x.id),
+            PathKind::StructEnumUnion => self.add_struct_enum_union_id(&x.id),
+        }
+        if let Some(args) = &x.args {
+            self.check_generic_args(&**args);
+        }
+    }
+
+    fn check_generic_args(&mut self, x: &'a GenericArgs) {
+        match x {
+            GenericArgs::AngleBracketed { args, bindings } => {
+                args.iter().for_each(|arg| self.check_generic_arg(arg));
+                bindings.iter().for_each(|bind| self.check_type_binding(bind));
+            }
+            GenericArgs::Parenthesized { inputs, output } => {
+                inputs.iter().for_each(|ty| self.check_type(ty));
+                if let Some(o) = output {
+                    self.check_type(o);
+                }
+            }
+        }
+    }
+
+    fn check_generic_param_def(&mut self, gpd: &'a GenericParamDef) {
+        match &gpd.kind {
+            rustdoc_json_types::GenericParamDefKind::Lifetime { outlives: _ } => {}
+            rustdoc_json_types::GenericParamDefKind::Type { bounds, default, synthetic: _ } => {
+                bounds.iter().for_each(|b| self.check_generic_bound(b));
+                if let Some(ty) = default {
+                    self.check_type(ty);
+                }
+            }
+            rustdoc_json_types::GenericParamDefKind::Const { type_, default: _ } => {
+                self.check_type(type_)
+            }
+        }
+    }
+
+    fn check_generic_arg(&mut self, arg: &'a GenericArg) {
+        match arg {
+            GenericArg::Lifetime(_) => {}
+            GenericArg::Type(ty) => self.check_type(ty),
+            GenericArg::Const(c) => self.check_constant(c),
+            GenericArg::Infer => {}
+        }
+    }
+
+    fn check_type_binding(&mut self, bind: &'a TypeBinding) {
+        self.check_generic_args(&bind.args);
+        match &bind.binding {
+            TypeBindingKind::Equality(term) => self.check_term(term),
+            TypeBindingKind::Constraint(bounds) => {
+                bounds.iter().for_each(|b| self.check_generic_bound(b))
+            }
+        }
+    }
+
+    fn check_term(&mut self, term: &'a Term) {
+        match term {
+            Term::Type(ty) => self.check_type(ty),
+            Term::Constant(con) => self.check_constant(con),
+        }
+    }
+
+    fn check_where_predicate(&mut self, w: &'a WherePredicate) {
+        match w {
+            WherePredicate::BoundPredicate { type_, bounds, generic_params } => {
+                self.check_type(type_);
+                bounds.iter().for_each(|b| self.check_generic_bound(b));
+                generic_params.iter().for_each(|gpd| self.check_generic_param_def(gpd));
+            }
+            WherePredicate::RegionPredicate { lifetime: _, bounds } => {
+                bounds.iter().for_each(|b| self.check_generic_bound(b));
+            }
+            WherePredicate::EqPredicate { lhs, rhs } => {
+                self.check_type(lhs);
+                self.check_term(rhs);
+            }
+        }
+    }
+
+    fn check_dyn_trait(&mut self, dyn_trait: &'a DynTrait) {
+        for pt in &dyn_trait.traits {
+            self.check_path(&pt.trait_, PathKind::Trait);
+            pt.generic_params.iter().for_each(|gpd| self.check_generic_param_def(gpd));
+        }
+    }
+
+    fn check_function_pointer(&mut self, fp: &'a FunctionPointer) {
+        self.check_fn_decl(&fp.decl);
+        fp.generic_params.iter().for_each(|gpd| self.check_generic_param_def(gpd));
+    }
+
+    fn add_id_checked(&mut self, id: &'a Id, valid: fn(Kind) -> bool, expected: &str) {
+        if let Some(kind) = self.kind_of(id) {
+            if valid(kind) {
+                if !self.seen_ids.contains(id) {
+                    self.todo.insert(id);
+                }
+            } else {
+                self.fail_expecting(id, expected);
+            }
+        } else {
+            if !self.missing_ids.contains(id) {
+                self.missing_ids.insert(id);
+                self.fail(id, ErrorKind::NotFound)
+            }
+        }
+    }
+
+    fn add_field_id(&mut self, id: &'a Id) {
+        self.add_id_checked(id, Kind::is_struct_field, "StructField");
+    }
+
+    fn add_mod_id(&mut self, id: &'a Id) {
+        self.add_id_checked(id, Kind::is_module, "Module");
+    }
+    fn add_impl_id(&mut self, id: &'a Id) {
+        self.add_id_checked(id, Kind::is_impl, "Impl");
+    }
+
+    fn add_variant_id(&mut self, id: &'a Id) {
+        self.add_id_checked(id, Kind::is_variant, "Variant");
+    }
+
+    fn add_trait_id(&mut self, id: &'a Id) {
+        self.add_id_checked(id, Kind::is_trait, "Trait");
+    }
+
+    fn add_struct_enum_union_id(&mut self, id: &'a Id) {
+        self.add_id_checked(id, Kind::is_struct_enum_union, "Struct or Enum or Union");
+    }
+
+    /// Add an Id that appeared in a trait
+    fn add_trait_item_id(&mut self, id: &'a Id) {
+        self.add_id_checked(id, Kind::can_appear_in_trait, "Trait inner item");
+    }
+
+    /// Add an Id that appeared in a mod
+    fn add_mod_item_id(&mut self, id: &'a Id) {
+        self.add_id_checked(id, Kind::can_appear_in_mod, "Module inner item")
+    }
+
+    fn fail_expecting(&mut self, id: &Id, expected: &str) {
+        let kind = self.kind_of(id).unwrap(); // We know it has a kind, as it's wrong.
+        self.fail(id, ErrorKind::Custom(format!("Expected {expected} but found {kind:?}")));
+    }
+
+    fn fail(&mut self, id: &Id, kind: ErrorKind) {
+        self.errs.push(Error { id: id.clone(), kind });
+    }
+
+    fn kind_of(&mut self, id: &Id) -> Option<Kind> {
+        if let Some(item) = self.krate.index.get(id) {
+            Some(Kind::from_item(item))
+        } else if let Some(summary) = self.krate.paths.get(id) {
+            Some(Kind::from_summary(summary))
+        } else {
+            None
+        }
+    }
+}
+
+fn set_remove<T: Hash + Eq + Clone>(set: &mut HashSet<T>) -> Option<T> {
+    if let Some(id) = set.iter().next() {
+        let id = id.clone();
+        set.take(&id)
+    } else {
+        None
+    }
+}
diff --git a/triagebot.toml b/triagebot.toml
index 4b2dcc246e4..12a55fda7ef 100644
--- a/triagebot.toml
+++ b/triagebot.toml
@@ -130,8 +130,8 @@ trigger_files = [
 
     # Internal tooling
     "src/etc/htmldocck.py",
-    "src/etc/check_missing_items.py",
     "src/tools/jsondocck",
+    "src/tools/jsondoclint",
     "src/tools/rustdoc-gui",
     "src/tools/rustdoc-js",
     "src/tools/rustdoc-themes",
@@ -142,11 +142,11 @@ exclude_labels = [
 
 [autolabel."A-rustdoc-json"]
 trigger_files = [
-    "src/etc/check_missing_items.py",
     "src/librustdoc/json/",
     "src/rustdoc-json-types",
     "src/test/rustdoc-json",
     "src/tools/jsondocck",
+    "src/tools/jsondoclint",
 ]
 
 [autolabel."T-compiler"]