about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock21
-rw-r--r--compiler/rustc_ast/src/ast.rs15
-rw-r--r--compiler/rustc_builtin_macros/src/format.rs2
-rw-r--r--compiler/rustc_data_structures/src/sorted_map.rs9
-rw-r--r--compiler/rustc_error_messages/locales/en-US/metadata.ftl5
-rw-r--r--compiler/rustc_hir/src/hir.rs16
-rw-r--r--compiler/rustc_hir/src/hir_id.rs21
-rw-r--r--compiler/rustc_metadata/src/dependency_format.rs9
-rw-r--r--compiler/rustc_metadata/src/errors.rs8
-rw-r--r--compiler/rustc_middle/src/mir/visit.rs8
-rw-r--r--compiler/rustc_mir_transform/src/inline.rs42
-rw-r--r--compiler/rustc_query_impl/src/lib.rs1
-rw-r--r--compiler/rustc_query_impl/src/plumbing.rs40
-rw-r--r--compiler/rustc_query_system/src/query/config.rs53
-rw-r--r--compiler/rustc_query_system/src/query/mod.rs2
-rw-r--r--compiler/rustc_query_system/src/query/plumbing.rs113
-rw-r--r--compiler/rustc_ty_utils/src/abi.rs6
-rw-r--r--library/core/src/lib.rs3
-rw-r--r--library/core/src/str/iter.rs185
-rw-r--r--library/core/src/task/wake.rs5
-rw-r--r--library/core/tests/task.rs8
-rw-r--r--library/std/src/path.rs33
-rw-r--r--src/bootstrap/bootstrap.py3
-rw-r--r--src/bootstrap/check.rs17
-rw-r--r--src/bootstrap/compile.rs49
-rw-r--r--src/ci/docker/host-x86_64/mingw-check-tidy/Dockerfile1
-rwxr-xr-xsrc/ci/run.sh4
m---------src/doc/book0
m---------src/doc/nomicon0
m---------src/doc/rust-by-example0
m---------src/doc/rustc-dev-guide0
-rw-r--r--src/librustdoc/clean/mod.rs46
-rw-r--r--src/librustdoc/clean/types.rs25
-rw-r--r--src/librustdoc/fold.rs26
-rw-r--r--src/librustdoc/html/render/print_item.rs48
-rw-r--r--src/librustdoc/json/conversions.rs17
-rw-r--r--src/librustdoc/passes/stripper.rs5
-rw-r--r--src/librustdoc/visit.rs8
-rw-r--r--src/rustdoc-json-types/lib.rs17
-rw-r--r--src/test/codegen/function-arguments.rs2
-rw-r--r--src/test/codegen/issue-103840.rs9
-rw-r--r--src/test/mir-opt/inline/cycle.g.Inline.diff23
-rw-r--r--src/test/mir-opt/inline/cycle.main.Inline.diff23
-rw-r--r--src/test/mir-opt/inline/exponential_runtime.main.Inline.diff53
-rw-r--r--src/test/mir-opt/inline/inline_cycle.one.Inline.diff11
-rw-r--r--src/test/mir-opt/inline/inline_cycle.two.Inline.diff7
-rw-r--r--src/test/mir-opt/inline/inline_cycle_generic.main.Inline.diff9
-rw-r--r--src/test/mir-opt/inline/inline_diverging.h.Inline.diff43
-rw-r--r--src/test/mir-opt/separate_const_switch.identity.SeparateConstSwitch.diff35
-rw-r--r--src/test/mir-opt/simple_option_map_e2e.ezmap.PreCodegen.after.mir52
-rw-r--r--src/test/mir-opt/simple_option_map_e2e.rs19
-rw-r--r--src/test/run-make-fulldeps/save-analysis/foo.rs5
-rw-r--r--src/test/rustdoc-json/enums/discriminant/basic.rs12
-rw-r--r--src/test/rustdoc-json/enums/discriminant/expr.rs36
-rw-r--r--src/test/rustdoc-json/enums/discriminant/limits.rs32
-rw-r--r--src/test/rustdoc-json/enums/discriminant/num_underscore_and_suffix.rs16
-rw-r--r--src/test/rustdoc-json/enums/discriminant/only_some_have_discriminant.rs8
-rw-r--r--src/test/rustdoc-json/enums/discriminant/struct.rs15
-rw-r--r--src/test/rustdoc-json/enums/discriminant/tuple.rs15
-rw-r--r--src/test/rustdoc-json/enums/field_hidden.rs4
-rw-r--r--src/test/rustdoc-json/enums/kind.rs17
-rw-r--r--src/test/rustdoc-json/enums/struct_field_hidden.rs9
-rw-r--r--src/test/rustdoc-json/enums/tuple_fields_hidden.rs69
-rw-r--r--src/test/rustdoc-json/enums/variant_struct.rs9
-rw-r--r--src/test/rustdoc-json/enums/variant_tuple_struct.rs4
-rw-r--r--src/test/rustdoc-ui/issue-105334.rs2
-rw-r--r--src/test/rustdoc-ui/issue-105334.stderr9
-rw-r--r--src/test/rustdoc-ui/issue-105737.rs4
-rw-r--r--src/test/rustdoc-ui/issue-105737.stderr12
-rw-r--r--src/test/rustdoc-ui/issue-105742.rs40
-rw-r--r--src/test/rustdoc-ui/issue-105742.stderr385
-rw-r--r--src/test/rustdoc-ui/issue-106226.rs3
-rw-r--r--src/test/rustdoc-ui/issue-106226.stderr9
-rw-r--r--src/test/rustdoc-ui/issue-96287.rs17
-rw-r--r--src/test/rustdoc-ui/issue-96287.stderr15
-rw-r--r--src/test/ui-fulldeps/deriving-encodable-decodable-box.rs5
-rw-r--r--src/test/ui-fulldeps/deriving-encodable-decodable-cell-refcell.rs5
-rw-r--r--src/test/ui-fulldeps/deriving-global.rs5
-rw-r--r--src/test/ui-fulldeps/deriving-hygiene.rs5
-rw-r--r--src/test/ui-fulldeps/dropck_tarena_sound_drop.rs5
-rw-r--r--src/test/ui-fulldeps/empty-struct-braces-derive.rs5
-rw-r--r--src/test/ui-fulldeps/issue-14021.rs5
-rw-r--r--src/test/ui-fulldeps/missing-rustc-driver-error.rs11
-rw-r--r--src/test/ui-fulldeps/missing-rustc-driver-error.stderr24
-rw-r--r--src/test/ui-fulldeps/mod_dir_path_canonicalized.rs5
-rw-r--r--src/test/ui-fulldeps/pprust-expr-roundtrip.rs5
-rw-r--r--src/test/ui-fulldeps/regions-mock-tcx.rs5
-rw-r--r--src/test/ui-fulldeps/rustc_encodable_hygiene.rs5
-rw-r--r--src/test/ui/borrowck/borrowck-drop-from-guard.rs9
-rw-r--r--src/test/ui/borrowck/borrowck-drop-from-guard.stderr21
-rw-r--r--src/test/ui/borrowck/borrowck-mutate-in-guard.rs19
-rw-r--r--src/test/ui/borrowck/borrowck-mutate-in-guard.stderr23
-rw-r--r--src/test/ui/borrowck/issue-31287-drop-in-guard.rs9
-rw-r--r--src/test/ui/borrowck/issue-31287-drop-in-guard.stderr20
-rw-r--r--src/test/ui/fmt/ifmt-bad-arg.stderr2
-rw-r--r--src/test/ui/fmt/issue-89173.rs2
-rw-r--r--src/test/ui/fmt/issue-89173.stderr2
-rw-r--r--src/test/ui/issues/issue-29723.rs8
-rw-r--r--src/test/ui/issues/issue-29723.stderr20
-rw-r--r--src/test/ui/macros/format-foreign.stderr10
-rw-r--r--src/test/ui/macros/format-unused-lables.stderr2
-rw-r--r--src/test/ui/macros/issue-92267.stderr2
-rw-r--r--src/test/ui/nll/issue-24535-allow-mutable-borrow-in-match-guard.rs8
-rw-r--r--src/test/ui/nll/issue-27282-move-match-input-into-guard.rs14
-rw-r--r--src/test/ui/nll/issue-27282-move-match-input-into-guard.stderr17
-rw-r--r--src/test/ui/nll/issue-27282-move-ref-mut-into-guard.rs10
-rw-r--r--src/test/ui/nll/issue-27282-move-ref-mut-into-guard.stderr14
-rw-r--r--src/test/ui/nll/issue-27282-mutation-in-guard.rs13
-rw-r--r--src/test/ui/nll/issue-27282-mutation-in-guard.stderr14
-rw-r--r--src/test/ui/nll/issue-27282-reborrow-ref-mut-in-guard.rs14
-rw-r--r--src/test/ui/nll/issue-27282-reborrow-ref-mut-in-guard.stderr14
-rw-r--r--src/test/ui/nll/match-cfg-fake-edges.rs28
-rw-r--r--src/test/ui/nll/match-cfg-fake-edges.stderr40
-rw-r--r--src/test/ui/nll/match-guards-always-borrow.rs27
-rw-r--r--src/test/ui/nll/match-guards-always-borrow.stderr14
-rw-r--r--src/test/ui/nll/match-guards-partially-borrow.rs193
-rw-r--r--src/test/ui/nll/match-guards-partially-borrow.stderr103
-rw-r--r--src/test/ui/rfc-0107-bind-by-move-pattern-guards/rfc-reject-double-move-across-arms.rs15
-rw-r--r--src/test/ui/rfc-0107-bind-by-move-pattern-guards/rfc-reject-double-move-across-arms.stderr12
-rw-r--r--src/test/ui/rfc-0107-bind-by-move-pattern-guards/rfc-reject-double-move-in-first-arm.rs16
-rw-r--r--src/test/ui/rfc-0107-bind-by-move-pattern-guards/rfc-reject-double-move-in-first-arm.stderr12
-rw-r--r--src/test/ui/thir-tree.stdout7
-rw-r--r--src/tools/jsondoclint/src/validator.rs36
-rw-r--r--src/tools/miri/src/lib.rs5
-rw-r--r--src/tools/rustfmt/src/lib.rs5
-rw-r--r--src/tools/tidy/Cargo.toml1
-rw-r--r--src/tools/tidy/src/lib.rs1
-rw-r--r--src/tools/tidy/src/main.rs4
-rw-r--r--src/tools/tidy/src/x_version.rs65
-rw-r--r--src/tools/x/src/main.rs8
130 files changed, 2214 insertions, 639 deletions
diff --git a/Cargo.lock b/Cargo.lock
index f99e58e59b8..4cb64882cb7 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -4805,18 +4805,18 @@ checksum = "1ef965a420fe14fdac7dd018862966a4c14094f900e1650bbc71ddd7d580c8af"
 
 [[package]]
 name = "semver"
-version = "1.0.12"
+version = "1.0.14"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a2333e6df6d6598f2b1974829f853c2b4c5f4a6e503c10af918081aa6f8564e1"
+checksum = "e25dfac463d778e353db5be2449d1cce89bd6fd23c9f1ea21310ce6e5a1b29c4"
 dependencies = [
  "serde",
 ]
 
 [[package]]
 name = "serde"
-version = "1.0.147"
+version = "1.0.152"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d193d69bae983fc11a79df82342761dfbf28a99fc8d203dca4c3c1b590948965"
+checksum = "bb7d1f0d3021d347a83e556fc4683dea2ea09d87bccdf88ff5c12545d89d5efb"
 dependencies = [
  "serde_derive",
 ]
@@ -4833,9 +4833,9 @@ dependencies = [
 
 [[package]]
 name = "serde_derive"
-version = "1.0.147"
+version = "1.0.152"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4f1d362ca8fc9c3e3a7484440752472d68a6caa98f1ab81d99b5dfe517cec852"
+checksum = "af487d118eecd09402d70a5d72551860e788df87b464af30e5ea6a38c75c541e"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -4853,9 +4853,9 @@ dependencies = [
 
 [[package]]
 name = "serde_json"
-version = "1.0.85"
+version = "1.0.91"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e55a28e3aaef9d5ce0506d0a14dbba8054ddc7e499ef522dd8b26859ec9d4a44"
+checksum = "877c235533714907a8c2464236f5c4b2a17262ef1bd71f38f35ea592c8da6883"
 dependencies = [
  "indexmap",
  "itoa",
@@ -5133,9 +5133,9 @@ dependencies = [
 
 [[package]]
 name = "syn"
-version = "1.0.102"
+version = "1.0.107"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3fcd952facd492f9be3ef0d0b7032a6e442ee9b361d4acc2b1d0c4aaa5f613a1"
+checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -5309,6 +5309,7 @@ dependencies = [
  "lazy_static",
  "miropt-test-tools",
  "regex",
+ "semver",
  "termcolor",
  "walkdir",
 ]
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index 9cc81f39167..c1b26ca0925 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -2743,8 +2743,19 @@ impl Item {
 /// `extern` qualifier on a function item or function type.
 #[derive(Clone, Copy, Encodable, Decodable, Debug)]
 pub enum Extern {
+    /// No explicit extern keyword was used
+    ///
+    /// E.g. `fn foo() {}`
     None,
+    /// An explicit extern keyword was used, but with implicit ABI
+    ///
+    /// E.g. `extern fn foo() {}`
+    ///
+    /// This is just `extern "C"` (see `rustc_target::spec::abi::Abi::FALLBACK`)
     Implicit(Span),
+    /// An explicit extern keyword was used with an explicit ABI
+    ///
+    /// E.g. `extern "C" fn foo() {}`
     Explicit(StrLit, Span),
 }
 
@@ -2763,9 +2774,13 @@ impl Extern {
 /// included in this struct (e.g., `async unsafe fn` or `const extern "C" fn`).
 #[derive(Clone, Copy, Encodable, Decodable, Debug)]
 pub struct FnHeader {
+    /// The `unsafe` keyword, if any
     pub unsafety: Unsafe,
+    /// The `async` keyword, if any
     pub asyncness: Async,
+    /// The `const` keyword, if any
     pub constness: Const,
+    /// The `extern` keyword and corresponding ABI string, if any
     pub ext: Extern,
 }
 
diff --git a/compiler/rustc_builtin_macros/src/format.rs b/compiler/rustc_builtin_macros/src/format.rs
index 63bc0d552c1..b2b7b9d75bd 100644
--- a/compiler/rustc_builtin_macros/src/format.rs
+++ b/compiler/rustc_builtin_macros/src/format.rs
@@ -638,7 +638,7 @@ fn report_missing_placeholders(
                 if show_doc_note {
                     diag.note(concat!(
                         stringify!($kind),
-                        " formatting not supported; see the documentation for `std::fmt`",
+                        " formatting is not supported; see the documentation for `std::fmt`",
                     ));
                 }
                 if suggestions.len() > 0 {
diff --git a/compiler/rustc_data_structures/src/sorted_map.rs b/compiler/rustc_data_structures/src/sorted_map.rs
index 05f059c89d5..c63caa06818 100644
--- a/compiler/rustc_data_structures/src/sorted_map.rs
+++ b/compiler/rustc_data_structures/src/sorted_map.rs
@@ -1,6 +1,7 @@
 use crate::stable_hasher::{HashStable, StableHasher, StableOrd};
 use std::borrow::Borrow;
 use std::cmp::Ordering;
+use std::fmt::Debug;
 use std::mem;
 use std::ops::{Bound, Index, IndexMut, RangeBounds};
 
@@ -16,7 +17,7 @@ pub use index_map::SortedIndexMultiMap;
 /// stores data in a more compact way. It also supports accessing contiguous
 /// ranges of elements as a slice, and slices of already sorted elements can be
 /// inserted efficiently.
-#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Encodable, Decodable)]
+#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Encodable, Decodable)]
 pub struct SortedMap<K, V> {
     data: Vec<(K, V)>,
 }
@@ -314,5 +315,11 @@ impl<K: HashStable<CTX> + StableOrd, V: HashStable<CTX>, CTX> HashStable<CTX> fo
     }
 }
 
+impl<K: Debug, V: Debug> Debug for SortedMap<K, V> {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        f.debug_map().entries(self.data.iter().map(|(a, b)| (a, b))).finish()
+    }
+}
+
 #[cfg(test)]
 mod tests;
diff --git a/compiler/rustc_error_messages/locales/en-US/metadata.ftl b/compiler/rustc_error_messages/locales/en-US/metadata.ftl
index b42b228bde9..79b8b417257 100644
--- a/compiler/rustc_error_messages/locales/en-US/metadata.ftl
+++ b/compiler/rustc_error_messages/locales/en-US/metadata.ftl
@@ -4,6 +4,11 @@ metadata_rlib_required =
 metadata_lib_required =
     crate `{$crate_name}` required to be available in {$kind} format, but was not found in this form
 
+metadata_rustc_lib_required =
+    crate `{$crate_name}` required to be available in {$kind} format, but was not found in this form
+    .note = only .rmeta files are distributed for `rustc_private` crates other than `rustc_driver`
+    .help = try adding `extern crate rustc_driver;` at the top level of this crate
+
 metadata_crate_dep_multiple =
     cannot satisfy dependencies so `{$crate_name}` only shows up once
     .help = having upstream crates all available in one format will likely make this go away
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index e923ec26a48..034f06bb889 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -854,7 +854,11 @@ impl fmt::Debug for OwnerNodes<'_> {
                 &self
                     .nodes
                     .iter_enumerated()
-                    .map(|(id, parented_node)| (id, parented_node.as_ref().map(|node| node.parent)))
+                    .map(|(id, parented_node)| {
+                        let parented_node = parented_node.as_ref().map(|node| node.parent);
+
+                        debug_fn(move |f| write!(f, "({id:?}, {parented_node:?})"))
+                    })
                     .collect::<Vec<_>>(),
             )
             .field("bodies", &self.bodies)
@@ -3615,3 +3619,13 @@ mod size_asserts {
     static_assert_size!(TyKind<'_>, 32);
     // tidy-alphabetical-end
 }
+
+fn debug_fn(f: impl Fn(&mut fmt::Formatter<'_>) -> fmt::Result) -> impl fmt::Debug {
+    struct DebugFn<F>(F);
+    impl<F: Fn(&mut fmt::Formatter<'_>) -> fmt::Result> fmt::Debug for DebugFn<F> {
+        fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+            (self.0)(fmt)
+        }
+    }
+    DebugFn(f)
+}
diff --git a/compiler/rustc_hir/src/hir_id.rs b/compiler/rustc_hir/src/hir_id.rs
index 03bcaa69468..5d05adfb556 100644
--- a/compiler/rustc_hir/src/hir_id.rs
+++ b/compiler/rustc_hir/src/hir_id.rs
@@ -1,14 +1,21 @@
 use crate::def_id::{DefId, DefIndex, LocalDefId, CRATE_DEF_ID};
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher, StableOrd, ToStableHashKey};
 use rustc_span::{def_id::DefPathHash, HashStableContext};
-use std::fmt;
+use std::fmt::{self, Debug};
 
-#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
+#[derive(Copy, Clone, PartialEq, Eq, Hash)]
 #[derive(Encodable, Decodable)]
 pub struct OwnerId {
     pub def_id: LocalDefId,
 }
 
+impl Debug for OwnerId {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        // Example: DefId(0:1 ~ aa[7697]::{use#0})
+        Debug::fmt(&self.def_id, f)
+    }
+}
+
 impl From<OwnerId> for HirId {
     fn from(owner: OwnerId) -> HirId {
         HirId { owner, local_id: ItemLocalId::from_u32(0) }
@@ -60,7 +67,7 @@ impl<CTX: HashStableContext> ToStableHashKey<CTX> for OwnerId {
 /// the `local_id` part of the `HirId` changing, which is a very useful property in
 /// incremental compilation where we have to persist things through changes to
 /// the code base.
-#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
+#[derive(Copy, Clone, PartialEq, Eq, Hash)]
 #[derive(Encodable, Decodable, HashStable_Generic)]
 #[rustc_pass_by_value]
 pub struct HirId {
@@ -68,6 +75,14 @@ pub struct HirId {
     pub local_id: ItemLocalId,
 }
 
+impl Debug for HirId {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        // Example: HirId(DefId(0:1 ~ aa[7697]::{use#0}).10)
+        // Don't use debug_tuple to always keep this on one line.
+        write!(f, "HirId({:?}.{:?})", self.owner, self.local_id)
+    }
+}
+
 impl HirId {
     /// Signal local id which should never be used.
     pub const INVALID: HirId =
diff --git a/compiler/rustc_metadata/src/dependency_format.rs b/compiler/rustc_metadata/src/dependency_format.rs
index 6112ec9e4e9..cee4ba56a9d 100644
--- a/compiler/rustc_metadata/src/dependency_format.rs
+++ b/compiler/rustc_metadata/src/dependency_format.rs
@@ -54,7 +54,7 @@
 use crate::creader::CStore;
 use crate::errors::{
     BadPanicStrategy, CrateDepMultiple, IncompatiblePanicInDropStrategy, LibRequired,
-    RequiredPanicStrategy, RlibRequired, TwoPanicRuntimes,
+    RequiredPanicStrategy, RlibRequired, RustcLibRequired, TwoPanicRuntimes,
 };
 
 use rustc_data_structures::fx::FxHashMap;
@@ -224,7 +224,12 @@ fn calculate_type(tcx: TyCtxt<'_>, ty: CrateType) -> DependencyList {
                     Linkage::Static => "rlib",
                     _ => "dylib",
                 };
-                sess.emit_err(LibRequired { crate_name: tcx.crate_name(cnum), kind: kind });
+                let crate_name = tcx.crate_name(cnum);
+                if crate_name.as_str().starts_with("rustc_") {
+                    sess.emit_err(RustcLibRequired { crate_name, kind });
+                } else {
+                    sess.emit_err(LibRequired { crate_name, kind });
+                }
             }
         }
     }
diff --git a/compiler/rustc_metadata/src/errors.rs b/compiler/rustc_metadata/src/errors.rs
index 1e08e95c01f..02c03114eb6 100644
--- a/compiler/rustc_metadata/src/errors.rs
+++ b/compiler/rustc_metadata/src/errors.rs
@@ -25,6 +25,14 @@ pub struct LibRequired<'a> {
 }
 
 #[derive(Diagnostic)]
+#[diag(metadata_rustc_lib_required)]
+#[help]
+pub struct RustcLibRequired<'a> {
+    pub crate_name: Symbol,
+    pub kind: &'a str,
+}
+
+#[derive(Diagnostic)]
 #[diag(metadata_crate_dep_multiple)]
 #[help]
 pub struct CrateDepMultiple {
diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs
index 2ee3f551529..1a264d2d5af 100644
--- a/compiler/rustc_middle/src/mir/visit.rs
+++ b/compiler/rustc_middle/src/mir/visit.rs
@@ -3,15 +3,15 @@
 //! ## Overview
 //!
 //! There are two visitors, one for immutable and one for mutable references,
-//! but both are generated by the following macro. The code is written according
-//! to the following conventions:
+//! but both are generated by the `make_mir_visitor` macro.
+//! The code is written according to the following conventions:
 //!
 //! - introduce a `visit_foo` and a `super_foo` method for every MIR type
 //! - `visit_foo`, by default, calls `super_foo`
 //! - `super_foo`, by default, destructures the `foo` and calls `visit_foo`
 //!
-//! This allows you as a user to override `visit_foo` for types are
-//! interested in, and invoke (within that method) call
+//! This allows you to override `visit_foo` for types you are
+//! interested in, and invoke (within that method call)
 //! `self.super_foo` to get the default behavior. Just as in an OO
 //! language, you should never call `super` methods ordinarily except
 //! in that circumstance.
diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs
index 8bdd965deb2..4219e6280eb 100644
--- a/compiler/rustc_mir_transform/src/inline.rs
+++ b/compiler/rustc_mir_transform/src/inline.rs
@@ -1,6 +1,7 @@
 //! Inlining pass for MIR functions
 use crate::deref_separator::deref_finder;
 use rustc_attr::InlineAttr;
+use rustc_hir::def_id::DefId;
 use rustc_index::bit_set::BitSet;
 use rustc_index::vec::Idx;
 use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs};
@@ -27,6 +28,8 @@ const RESUME_PENALTY: usize = 45;
 
 const UNKNOWN_SIZE_COST: usize = 10;
 
+const TOP_DOWN_DEPTH_LIMIT: usize = 5;
+
 pub struct Inline;
 
 #[derive(Copy, Clone, Debug)]
@@ -86,8 +89,13 @@ fn inline<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) -> bool {
 
     let param_env = tcx.param_env_reveal_all_normalized(def_id);
 
-    let mut this =
-        Inliner { tcx, param_env, codegen_fn_attrs: tcx.codegen_fn_attrs(def_id), changed: false };
+    let mut this = Inliner {
+        tcx,
+        param_env,
+        codegen_fn_attrs: tcx.codegen_fn_attrs(def_id),
+        history: Vec::new(),
+        changed: false,
+    };
     let blocks = BasicBlock::new(0)..body.basic_blocks.next_index();
     this.process_blocks(body, blocks);
     this.changed
@@ -98,12 +106,26 @@ struct Inliner<'tcx> {
     param_env: ParamEnv<'tcx>,
     /// Caller codegen attributes.
     codegen_fn_attrs: &'tcx CodegenFnAttrs,
+    /// Stack of inlined instances.
+    /// We only check the `DefId` and not the substs because we want to
+    /// avoid inlining cases of polymorphic recursion.
+    /// The number of `DefId`s is finite, so checking history is enough
+    /// to ensure that we do not loop endlessly while inlining.
+    history: Vec<DefId>,
     /// Indicates that the caller body has been modified.
     changed: bool,
 }
 
 impl<'tcx> Inliner<'tcx> {
     fn process_blocks(&mut self, caller_body: &mut Body<'tcx>, blocks: Range<BasicBlock>) {
+        // How many callsites in this body are we allowed to inline? We need to limit this in order
+        // to prevent super-linear growth in MIR size
+        let inline_limit = match self.history.len() {
+            0 => usize::MAX,
+            1..=TOP_DOWN_DEPTH_LIMIT => 1,
+            _ => return,
+        };
+        let mut inlined_count = 0;
         for bb in blocks {
             let bb_data = &caller_body[bb];
             if bb_data.is_cleanup {
@@ -122,12 +144,16 @@ impl<'tcx> Inliner<'tcx> {
                     debug!("not-inlined {} [{}]", callsite.callee, reason);
                     continue;
                 }
-                Ok(_) => {
+                Ok(new_blocks) => {
                     debug!("inlined {}", callsite.callee);
                     self.changed = true;
-                    // We could process the blocks returned by `try_inlining` here. However, that
-                    // leads to exponential compile times due to the top-down nature of this kind
-                    // of inlining.
+                    inlined_count += 1;
+                    if inlined_count == inline_limit {
+                        return;
+                    }
+                    self.history.push(callsite.callee.def_id());
+                    self.process_blocks(caller_body, new_blocks);
+                    self.history.pop();
                 }
             }
         }
@@ -301,6 +327,10 @@ impl<'tcx> Inliner<'tcx> {
                     return None;
                 }
 
+                if self.history.contains(&callee.def_id()) {
+                    return None;
+                }
+
                 let fn_sig = self.tcx.bound_fn_sig(def_id).subst(self.tcx, substs);
                 let source_info = SourceInfo { span: fn_span, ..terminator.source_info };
 
diff --git a/compiler/rustc_query_impl/src/lib.rs b/compiler/rustc_query_impl/src/lib.rs
index d426a2b6b78..2d243e13cc2 100644
--- a/compiler/rustc_query_impl/src/lib.rs
+++ b/compiler/rustc_query_impl/src/lib.rs
@@ -34,7 +34,6 @@ use rustc_query_system::query::*;
 pub use rustc_query_system::query::{deadlock, QueryContext};
 
 pub use rustc_query_system::query::QueryConfig;
-pub(crate) use rustc_query_system::query::QueryVTable;
 
 mod on_disk_cache;
 pub use on_disk_cache::OnDiskCache;
diff --git a/compiler/rustc_query_impl/src/plumbing.rs b/compiler/rustc_query_impl/src/plumbing.rs
index 9ffcc5672cc..535445e70bc 100644
--- a/compiler/rustc_query_impl/src/plumbing.rs
+++ b/compiler/rustc_query_impl/src/plumbing.rs
@@ -493,28 +493,32 @@ macro_rules! define_queries {
                 &tcx.query_caches.$name
             }
 
+            fn execute_query(tcx: TyCtxt<'tcx>, key: Self::Key) -> Self::Stored {
+                tcx.$name(key)
+            }
+
             #[inline]
-            fn make_vtable(tcx: QueryCtxt<'tcx>, key: &Self::Key) ->
-                QueryVTable<QueryCtxt<'tcx>, Self::Key, Self::Value>
-            {
-                let compute = get_provider!([$($modifiers)*][tcx, $name, key]);
-                let cache_on_disk = Self::cache_on_disk(tcx.tcx, key);
-                QueryVTable {
-                    anon: is_anon!([$($modifiers)*]),
-                    eval_always: is_eval_always!([$($modifiers)*]),
-                    depth_limit: depth_limit!([$($modifiers)*]),
-                    feedable: feedable!([$($modifiers)*]),
-                    dep_kind: dep_graph::DepKind::$name,
-                    hash_result: hash_result!([$($modifiers)*]),
-                    handle_cycle_error: handle_cycle_error!([$($modifiers)*]),
-                    compute,
-                    try_load_from_disk: if cache_on_disk { should_ever_cache_on_disk!([$($modifiers)*]) } else { None },
-                }
+            // key is only sometimes used
+            #[allow(unused_variables)]
+            fn compute(qcx: QueryCtxt<'tcx>, key: &Self::Key) -> fn(TyCtxt<'tcx>, Self::Key) -> Self::Value {
+                get_provider!([$($modifiers)*][qcx, $name, key])
             }
 
-            fn execute_query(tcx: TyCtxt<'tcx>, k: Self::Key) -> Self::Stored {
-                tcx.$name(k)
+            #[inline]
+            fn try_load_from_disk(qcx: QueryCtxt<'tcx>, key: &Self::Key) -> rustc_query_system::query::TryLoadFromDisk<QueryCtxt<'tcx>, Self> {
+                let cache_on_disk = Self::cache_on_disk(qcx.tcx, key);
+                if cache_on_disk { should_ever_cache_on_disk!([$($modifiers)*]) } else { None }
             }
+
+            const ANON: bool = is_anon!([$($modifiers)*]);
+            const EVAL_ALWAYS: bool = is_eval_always!([$($modifiers)*]);
+            const DEPTH_LIMIT: bool = depth_limit!([$($modifiers)*]);
+            const FEEDABLE: bool = feedable!([$($modifiers)*]);
+
+            const DEP_KIND: rustc_middle::dep_graph::DepKind = dep_graph::DepKind::$name;
+            const HANDLE_CYCLE_ERROR: rustc_query_system::HandleCycleError = handle_cycle_error!([$($modifiers)*]);
+
+            const HASH_RESULT: rustc_query_system::query::HashResult<QueryCtxt<'tcx>, Self> = hash_result!([$($modifiers)*]);
         })*
 
         #[allow(nonstandard_style)]
diff --git a/compiler/rustc_query_system/src/query/config.rs b/compiler/rustc_query_system/src/query/config.rs
index 24c960765df..8c0330e438d 100644
--- a/compiler/rustc_query_system/src/query/config.rs
+++ b/compiler/rustc_query_system/src/query/config.rs
@@ -1,7 +1,6 @@
 //! Query configuration and description traits.
 
-use crate::dep_graph::DepNode;
-use crate::dep_graph::SerializedDepNodeIndex;
+use crate::dep_graph::{DepNode, DepNodeParams, SerializedDepNodeIndex};
 use crate::error::HandleCycleError;
 use crate::ich::StableHashingContext;
 use crate::query::caches::QueryCache;
@@ -11,10 +10,16 @@ use rustc_data_structures::fingerprint::Fingerprint;
 use std::fmt::Debug;
 use std::hash::Hash;
 
+pub type HashResult<Qcx, Q> =
+    Option<fn(&mut StableHashingContext<'_>, &<Q as QueryConfig<Qcx>>::Value) -> Fingerprint>;
+
+pub type TryLoadFromDisk<Qcx, Q> =
+    Option<fn(Qcx, SerializedDepNodeIndex) -> Option<<Q as QueryConfig<Qcx>>::Value>>;
+
 pub trait QueryConfig<Qcx: QueryContext> {
     const NAME: &'static str;
 
-    type Key: Eq + Hash + Clone + Debug;
+    type Key: DepNodeParams<Qcx::DepContext> + Eq + Hash + Clone + Debug;
     type Value: Debug;
     type Stored: Debug + Clone + std::borrow::Borrow<Self::Value>;
 
@@ -30,39 +35,27 @@ pub trait QueryConfig<Qcx: QueryContext> {
     where
         Qcx: 'a;
 
-    // Don't use this method to compute query results, instead use the methods on TyCtxt
-    fn make_vtable(tcx: Qcx, key: &Self::Key) -> QueryVTable<Qcx, Self::Key, Self::Value>;
-
     fn cache_on_disk(tcx: Qcx::DepContext, key: &Self::Key) -> bool;
 
     // Don't use this method to compute query results, instead use the methods on TyCtxt
     fn execute_query(tcx: Qcx::DepContext, k: Self::Key) -> Self::Stored;
-}
 
-#[derive(Copy, Clone)]
-pub struct QueryVTable<Qcx: QueryContext, K, V> {
-    pub anon: bool,
-    pub dep_kind: Qcx::DepKind,
-    pub eval_always: bool,
-    pub depth_limit: bool,
-    pub feedable: bool,
-
-    pub compute: fn(Qcx::DepContext, K) -> V,
-    pub hash_result: Option<fn(&mut StableHashingContext<'_>, &V) -> Fingerprint>,
-    pub handle_cycle_error: HandleCycleError,
-    // NOTE: this is also `None` if `cache_on_disk()` returns false, not just if it's unsupported by the query
-    pub try_load_from_disk: Option<fn(Qcx, SerializedDepNodeIndex) -> Option<V>>,
-}
+    fn compute(tcx: Qcx, key: &Self::Key) -> fn(Qcx::DepContext, Self::Key) -> Self::Value;
 
-impl<Qcx: QueryContext, K, V> QueryVTable<Qcx, K, V> {
-    pub(crate) fn to_dep_node(&self, tcx: Qcx::DepContext, key: &K) -> DepNode<Qcx::DepKind>
-    where
-        K: crate::dep_graph::DepNodeParams<Qcx::DepContext>,
-    {
-        DepNode::construct(tcx, self.dep_kind, key)
-    }
+    fn try_load_from_disk(qcx: Qcx, idx: &Self::Key) -> TryLoadFromDisk<Qcx, Self>;
+
+    const ANON: bool;
+    const EVAL_ALWAYS: bool;
+    const DEPTH_LIMIT: bool;
+    const FEEDABLE: bool;
+
+    const DEP_KIND: Qcx::DepKind;
+    const HANDLE_CYCLE_ERROR: HandleCycleError;
+
+    const HASH_RESULT: HashResult<Qcx, Self>;
 
-    pub(crate) fn compute(&self, tcx: Qcx::DepContext, key: K) -> V {
-        (self.compute)(tcx, key)
+    // Just here for convernience and checking that the key matches the kind, don't override this.
+    fn construct_dep_node(tcx: Qcx::DepContext, key: &Self::Key) -> DepNode<Qcx::DepKind> {
+        DepNode::construct(tcx, Self::DEP_KIND, key)
     }
 }
diff --git a/compiler/rustc_query_system/src/query/mod.rs b/compiler/rustc_query_system/src/query/mod.rs
index ce9179ea832..d308af19207 100644
--- a/compiler/rustc_query_system/src/query/mod.rs
+++ b/compiler/rustc_query_system/src/query/mod.rs
@@ -12,7 +12,7 @@ pub use self::caches::{
 };
 
 mod config;
-pub use self::config::{QueryConfig, QueryVTable};
+pub use self::config::{HashResult, QueryConfig, TryLoadFromDisk};
 
 use crate::dep_graph::DepKind;
 use crate::dep_graph::{DepNodeIndex, HasDepContext, SerializedDepNodeIndex};
diff --git a/compiler/rustc_query_system/src/query/plumbing.rs b/compiler/rustc_query_system/src/query/plumbing.rs
index 53844dab9db..da1ac6a5fb2 100644
--- a/compiler/rustc_query_system/src/query/plumbing.rs
+++ b/compiler/rustc_query_system/src/query/plumbing.rs
@@ -2,10 +2,9 @@
 //! generate the actual methods on tcx which find and execute the provider,
 //! manage the caches, and so forth.
 
-use crate::dep_graph::{DepContext, DepKind, DepNode, DepNodeIndex, DepNodeParams};
+use crate::dep_graph::{DepContext, DepKind, DepNode, DepNodeIndex};
 use crate::ich::StableHashingContext;
 use crate::query::caches::QueryCache;
-use crate::query::config::QueryVTable;
 use crate::query::job::{report_cycle, QueryInfo, QueryJob, QueryJobId, QueryJobInfo};
 use crate::query::{QueryContext, QueryMap, QuerySideEffects, QueryStackFrame};
 use crate::values::Value;
@@ -361,36 +360,34 @@ where
     })
 }
 
-fn try_execute_query<Qcx, C>(
+fn try_execute_query<Q, Qcx>(
     qcx: Qcx,
-    state: &QueryState<C::Key, Qcx::DepKind>,
-    cache: &C,
+    state: &QueryState<Q::Key, Qcx::DepKind>,
+    cache: &Q::Cache,
     span: Span,
-    key: C::Key,
+    key: Q::Key,
     dep_node: Option<DepNode<Qcx::DepKind>>,
-    query: &QueryVTable<Qcx, C::Key, C::Value>,
-) -> (C::Stored, Option<DepNodeIndex>)
+) -> (Q::Stored, Option<DepNodeIndex>)
 where
-    C: QueryCache,
-    C::Key: Clone + DepNodeParams<Qcx::DepContext>,
-    C::Value: Value<Qcx::DepContext, Qcx::DepKind>,
-    C::Stored: Debug + std::borrow::Borrow<C::Value>,
+    Q: QueryConfig<Qcx>,
     Qcx: QueryContext,
 {
-    match JobOwner::<'_, C::Key, Qcx::DepKind>::try_start(&qcx, state, span, key.clone()) {
+    match JobOwner::<'_, Q::Key, Qcx::DepKind>::try_start(&qcx, state, span, key.clone()) {
         TryGetJob::NotYetStarted(job) => {
-            let (result, dep_node_index) = execute_job(qcx, key.clone(), dep_node, query, job.id);
-            if query.feedable {
+            let (result, dep_node_index) =
+                execute_job::<Q, Qcx>(qcx, key.clone(), dep_node, job.id);
+            if Q::FEEDABLE {
                 // We may have put a value inside the cache from inside the execution.
                 // Verify that it has the same hash as what we have now, to ensure consistency.
                 let _ = cache.lookup(&key, |cached_result, _| {
-                    let hasher = query.hash_result.expect("feedable forbids no_hash");
+                    let hasher = Q::HASH_RESULT.expect("feedable forbids no_hash");
+
                     let old_hash = qcx.dep_context().with_stable_hashing_context(|mut hcx| hasher(&mut hcx, cached_result.borrow()));
                     let new_hash = qcx.dep_context().with_stable_hashing_context(|mut hcx| hasher(&mut hcx, &result));
                     debug_assert_eq!(
                         old_hash, new_hash,
                         "Computed query value for {:?}({:?}) is inconsistent with fed value,\ncomputed={:#?}\nfed={:#?}",
-                        query.dep_kind, key, result, cached_result,
+                        Q::DEP_KIND, key, result, cached_result,
                     );
                 });
             }
@@ -398,7 +395,7 @@ where
             (result, Some(dep_node_index))
         }
         TryGetJob::Cycle(error) => {
-            let result = mk_cycle(qcx, error, query.handle_cycle_error, cache);
+            let result = mk_cycle(qcx, error, Q::HANDLE_CYCLE_ERROR, cache);
             (result, None)
         }
         #[cfg(parallel_compiler)]
@@ -417,16 +414,14 @@ where
     }
 }
 
-fn execute_job<Qcx, K, V>(
+fn execute_job<Q, Qcx>(
     qcx: Qcx,
-    key: K,
+    key: Q::Key,
     mut dep_node_opt: Option<DepNode<Qcx::DepKind>>,
-    query: &QueryVTable<Qcx, K, V>,
     job_id: QueryJobId,
-) -> (V, DepNodeIndex)
+) -> (Q::Value, DepNodeIndex)
 where
-    K: Clone + DepNodeParams<Qcx::DepContext>,
-    V: Debug,
+    Q: QueryConfig<Qcx>,
     Qcx: QueryContext,
 {
     let dep_graph = qcx.dep_context().dep_graph();
@@ -434,23 +429,23 @@ where
     // Fast path for when incr. comp. is off.
     if !dep_graph.is_fully_enabled() {
         let prof_timer = qcx.dep_context().profiler().query_provider();
-        let result = qcx.start_query(job_id, query.depth_limit, None, || {
-            query.compute(*qcx.dep_context(), key)
+        let result = qcx.start_query(job_id, Q::DEPTH_LIMIT, None, || {
+            Q::compute(qcx, &key)(*qcx.dep_context(), key)
         });
         let dep_node_index = dep_graph.next_virtual_depnode_index();
         prof_timer.finish_with_query_invocation_id(dep_node_index.into());
         return (result, dep_node_index);
     }
 
-    if !query.anon && !query.eval_always {
+    if !Q::ANON && !Q::EVAL_ALWAYS {
         // `to_dep_node` is expensive for some `DepKind`s.
         let dep_node =
-            dep_node_opt.get_or_insert_with(|| query.to_dep_node(*qcx.dep_context(), &key));
+            dep_node_opt.get_or_insert_with(|| Q::construct_dep_node(*qcx.dep_context(), &key));
 
         // The diagnostics for this query will be promoted to the current session during
         // `try_mark_green()`, so we can ignore them here.
         if let Some(ret) = qcx.start_query(job_id, false, None, || {
-            try_load_from_disk_and_cache_in_memory(qcx, &key, &dep_node, query)
+            try_load_from_disk_and_cache_in_memory::<Q, Qcx>(qcx, &key, &dep_node)
         }) {
             return ret;
         }
@@ -460,18 +455,19 @@ where
     let diagnostics = Lock::new(ThinVec::new());
 
     let (result, dep_node_index) =
-        qcx.start_query(job_id, query.depth_limit, Some(&diagnostics), || {
-            if query.anon {
-                return dep_graph.with_anon_task(*qcx.dep_context(), query.dep_kind, || {
-                    query.compute(*qcx.dep_context(), key)
+        qcx.start_query(job_id, Q::DEPTH_LIMIT, Some(&diagnostics), || {
+            if Q::ANON {
+                return dep_graph.with_anon_task(*qcx.dep_context(), Q::DEP_KIND, || {
+                    Q::compute(qcx, &key)(*qcx.dep_context(), key)
                 });
             }
 
             // `to_dep_node` is expensive for some `DepKind`s.
             let dep_node =
-                dep_node_opt.unwrap_or_else(|| query.to_dep_node(*qcx.dep_context(), &key));
+                dep_node_opt.unwrap_or_else(|| Q::construct_dep_node(*qcx.dep_context(), &key));
 
-            dep_graph.with_task(dep_node, *qcx.dep_context(), key, query.compute, query.hash_result)
+            let task = Q::compute(qcx, &key);
+            dep_graph.with_task(dep_node, *qcx.dep_context(), key, task, Q::HASH_RESULT)
         });
 
     prof_timer.finish_with_query_invocation_id(dep_node_index.into());
@@ -480,7 +476,7 @@ where
     let side_effects = QuerySideEffects { diagnostics };
 
     if std::intrinsics::unlikely(!side_effects.is_empty()) {
-        if query.anon {
+        if Q::ANON {
             qcx.store_side_effects_for_anon_node(dep_node_index, side_effects);
         } else {
             qcx.store_side_effects(dep_node_index, side_effects);
@@ -490,16 +486,14 @@ where
     (result, dep_node_index)
 }
 
-fn try_load_from_disk_and_cache_in_memory<Qcx, K, V>(
+fn try_load_from_disk_and_cache_in_memory<Q, Qcx>(
     qcx: Qcx,
-    key: &K,
+    key: &Q::Key,
     dep_node: &DepNode<Qcx::DepKind>,
-    query: &QueryVTable<Qcx, K, V>,
-) -> Option<(V, DepNodeIndex)>
+) -> Option<(Q::Value, DepNodeIndex)>
 where
-    K: Clone,
+    Q: QueryConfig<Qcx>,
     Qcx: QueryContext,
-    V: Debug,
 {
     // Note this function can be called concurrently from the same query
     // We must ensure that this is handled correctly.
@@ -511,7 +505,7 @@ where
 
     // First we try to load the result from the on-disk cache.
     // Some things are never cached on disk.
-    if let Some(try_load_from_disk) = query.try_load_from_disk {
+    if let Some(try_load_from_disk) = Q::try_load_from_disk(qcx, &key) {
         let prof_timer = qcx.dep_context().profiler().incr_cache_loading();
 
         // The call to `with_query_deserialization` enforces that no new `DepNodes`
@@ -545,7 +539,7 @@ where
             if std::intrinsics::unlikely(
                 try_verify || qcx.dep_context().sess().opts.unstable_opts.incremental_verify_ich,
             ) {
-                incremental_verify_ich(*qcx.dep_context(), &result, dep_node, query.hash_result);
+                incremental_verify_ich(*qcx.dep_context(), &result, dep_node, Q::HASH_RESULT);
             }
 
             return Some((result, dep_node_index));
@@ -565,7 +559,7 @@ where
     let prof_timer = qcx.dep_context().profiler().query_provider();
 
     // The dep-graph for this computation is already in-place.
-    let result = dep_graph.with_ignore(|| query.compute(*qcx.dep_context(), key.clone()));
+    let result = dep_graph.with_ignore(|| Q::compute(qcx, key)(*qcx.dep_context(), key.clone()));
 
     prof_timer.finish_with_query_invocation_id(dep_node_index.into());
 
@@ -578,7 +572,7 @@ where
     //
     // See issue #82920 for an example of a miscompilation that would get turned into
     // an ICE by this check
-    incremental_verify_ich(*qcx.dep_context(), &result, dep_node, query.hash_result);
+    incremental_verify_ich(*qcx.dep_context(), &result, dep_node, Q::HASH_RESULT);
 
     Some((result, dep_node_index))
 }
@@ -699,23 +693,19 @@ fn incremental_verify_ich_failed(sess: &Session, dep_node: DebugArg<'_>, result:
 ///
 /// Note: The optimization is only available during incr. comp.
 #[inline(never)]
-fn ensure_must_run<Qcx, K, V>(
-    qcx: Qcx,
-    key: &K,
-    query: &QueryVTable<Qcx, K, V>,
-) -> (bool, Option<DepNode<Qcx::DepKind>>)
+fn ensure_must_run<Q, Qcx>(qcx: Qcx, key: &Q::Key) -> (bool, Option<DepNode<Qcx::DepKind>>)
 where
-    K: crate::dep_graph::DepNodeParams<Qcx::DepContext>,
+    Q: QueryConfig<Qcx>,
     Qcx: QueryContext,
 {
-    if query.eval_always {
+    if Q::EVAL_ALWAYS {
         return (true, None);
     }
 
     // Ensuring an anonymous query makes no sense
-    assert!(!query.anon);
+    assert!(!Q::ANON);
 
-    let dep_node = query.to_dep_node(*qcx.dep_context(), key);
+    let dep_node = Q::construct_dep_node(*qcx.dep_context(), key);
 
     let dep_graph = qcx.dep_context().dep_graph();
     match dep_graph.try_mark_green(qcx, &dep_node) {
@@ -746,13 +736,11 @@ pub fn get_query<Q, Qcx, D>(qcx: Qcx, span: Span, key: Q::Key, mode: QueryMode)
 where
     D: DepKind,
     Q: QueryConfig<Qcx>,
-    Q::Key: DepNodeParams<Qcx::DepContext>,
     Q::Value: Value<Qcx::DepContext, D>,
     Qcx: QueryContext,
 {
-    let query = Q::make_vtable(qcx, &key);
     let dep_node = if let QueryMode::Ensure = mode {
-        let (must_run, dep_node) = ensure_must_run(qcx, &key, &query);
+        let (must_run, dep_node) = ensure_must_run::<Q, _>(qcx, &key);
         if !must_run {
             return None;
         }
@@ -761,14 +749,13 @@ where
         None
     };
 
-    let (result, dep_node_index) = try_execute_query(
+    let (result, dep_node_index) = try_execute_query::<Q, Qcx>(
         qcx,
         Q::query_state(qcx),
         Q::query_cache(qcx),
         span,
         key,
         dep_node,
-        &query,
     );
     if let Some(dep_node_index) = dep_node_index {
         qcx.dep_context().dep_graph().read_index(dep_node_index)
@@ -780,7 +767,6 @@ pub fn force_query<Q, Qcx, D>(qcx: Qcx, key: Q::Key, dep_node: DepNode<Qcx::DepK
 where
     D: DepKind,
     Q: QueryConfig<Qcx>,
-    Q::Key: DepNodeParams<Qcx::DepContext>,
     Q::Value: Value<Qcx::DepContext, D>,
     Qcx: QueryContext,
 {
@@ -798,9 +784,8 @@ where
         Err(()) => {}
     }
 
-    let query = Q::make_vtable(qcx, &key);
     let state = Q::query_state(qcx);
-    debug_assert!(!query.anon);
+    debug_assert!(!Q::ANON);
 
-    try_execute_query(qcx, state, cache, DUMMY_SP, key, Some(dep_node), &query);
+    try_execute_query::<Q, _>(qcx, state, cache, DUMMY_SP, key, Some(dep_node));
 }
diff --git a/compiler/rustc_ty_utils/src/abi.rs b/compiler/rustc_ty_utils/src/abi.rs
index d644cbccea1..73d2d278f93 100644
--- a/compiler/rustc_ty_utils/src/abi.rs
+++ b/compiler/rustc_ty_utils/src/abi.rs
@@ -273,9 +273,11 @@ fn adjust_for_rust_scalar<'tcx>(
                 | PointerKind::UniqueBorrowed
                 | PointerKind::UniqueBorrowedPinned => false,
                 PointerKind::UniqueOwned => noalias_for_box,
-                PointerKind::Frozen => !is_return,
+                PointerKind::Frozen => true,
             };
-            if no_alias {
+            // We can never add `noalias` in return position; that LLVM attribute has some very surprising semantics
+            // (see <https://github.com/rust-lang/unsafe-code-guidelines/issues/385#issuecomment-1368055745>).
+            if no_alias && !is_return {
                 attrs.set(ArgAttribute::NoAlias);
             }
 
diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs
index 0e3fef4ead3..9e0d7cab63e 100644
--- a/library/core/src/lib.rs
+++ b/library/core/src/lib.rs
@@ -158,6 +158,7 @@
 #![feature(const_unsafecell_get_mut)]
 #![feature(const_waker)]
 #![feature(core_panic)]
+#![feature(char_indices_offset)]
 #![feature(duration_consts_float)]
 #![feature(maybe_uninit_uninit_array)]
 #![feature(ptr_alignment_type)]
@@ -166,6 +167,8 @@
 #![feature(slice_ptr_get)]
 #![feature(slice_split_at_unchecked)]
 #![feature(str_internals)]
+#![feature(str_split_remainder)]
+#![feature(str_split_inclusive_remainder)]
 #![feature(strict_provenance)]
 #![feature(utf16_extra)]
 #![feature(utf16_extra_const)]
diff --git a/library/core/src/str/iter.rs b/library/core/src/str/iter.rs
index 24083ee6af4..d969475aa48 100644
--- a/library/core/src/str/iter.rs
+++ b/library/core/src/str/iter.rs
@@ -585,16 +585,17 @@ where
 impl<'a, P: Pattern<'a>> SplitInternal<'a, P> {
     #[inline]
     fn get_end(&mut self) -> Option<&'a str> {
-        if !self.finished && (self.allow_trailing_empty || self.end - self.start > 0) {
+        if !self.finished {
             self.finished = true;
-            // SAFETY: `self.start` and `self.end` always lie on unicode boundaries.
-            unsafe {
-                let string = self.matcher.haystack().get_unchecked(self.start..self.end);
-                Some(string)
+
+            if self.allow_trailing_empty || self.end - self.start > 0 {
+                // SAFETY: `self.start` and `self.end` always lie on unicode boundaries.
+                let string = unsafe { self.matcher.haystack().get_unchecked(self.start..self.end) };
+                return Some(string);
             }
-        } else {
-            None
         }
+
+        None
     }
 
     #[inline]
@@ -716,14 +717,14 @@ impl<'a, P: Pattern<'a>> SplitInternal<'a, P> {
     }
 
     #[inline]
-    fn as_str(&self) -> &'a str {
+    fn remainder(&self) -> Option<&'a str> {
         // `Self::get_end` doesn't change `self.start`
         if self.finished {
-            return "";
+            return None;
         }
 
         // SAFETY: `self.start` and `self.end` always lie on unicode boundaries.
-        unsafe { self.matcher.haystack().get_unchecked(self.start..self.end) }
+        Some(unsafe { self.matcher.haystack().get_unchecked(self.start..self.end) })
     }
 }
 
@@ -746,44 +747,48 @@ generate_pattern_iterators! {
 }
 
 impl<'a, P: Pattern<'a>> Split<'a, P> {
-    /// Returns remainder of the split string
+    /// Returns remainder of the split string.
+    ///
+    /// If the iterator is empty, returns `None`.
     ///
     /// # Examples
     ///
     /// ```
-    /// #![feature(str_split_as_str)]
+    /// #![feature(str_split_remainder)]
     /// let mut split = "Mary had a little lamb".split(' ');
-    /// assert_eq!(split.as_str(), "Mary had a little lamb");
+    /// assert_eq!(split.remainder(), Some("Mary had a little lamb"));
     /// split.next();
-    /// assert_eq!(split.as_str(), "had a little lamb");
+    /// assert_eq!(split.remainder(), Some("had a little lamb"));
     /// split.by_ref().for_each(drop);
-    /// assert_eq!(split.as_str(), "");
+    /// assert_eq!(split.remainder(), None);
     /// ```
     #[inline]
-    #[unstable(feature = "str_split_as_str", issue = "77998")]
-    pub fn as_str(&self) -> &'a str {
-        self.0.as_str()
+    #[unstable(feature = "str_split_remainder", issue = "77998")]
+    pub fn remainder(&self) -> Option<&'a str> {
+        self.0.remainder()
     }
 }
 
 impl<'a, P: Pattern<'a>> RSplit<'a, P> {
-    /// Returns remainder of the split string
+    /// Returns remainder of the split string.
+    ///
+    /// If the iterator is empty, returns `None`.
     ///
     /// # Examples
     ///
     /// ```
-    /// #![feature(str_split_as_str)]
+    /// #![feature(str_split_remainder)]
     /// let mut split = "Mary had a little lamb".rsplit(' ');
-    /// assert_eq!(split.as_str(), "Mary had a little lamb");
+    /// assert_eq!(split.remainder(), Some("Mary had a little lamb"));
     /// split.next();
-    /// assert_eq!(split.as_str(), "Mary had a little");
+    /// assert_eq!(split.remainder(), Some("Mary had a little"));
     /// split.by_ref().for_each(drop);
-    /// assert_eq!(split.as_str(), "");
+    /// assert_eq!(split.remainder(), None);
     /// ```
     #[inline]
-    #[unstable(feature = "str_split_as_str", issue = "77998")]
-    pub fn as_str(&self) -> &'a str {
-        self.0.as_str()
+    #[unstable(feature = "str_split_remainder", issue = "77998")]
+    pub fn remainder(&self) -> Option<&'a str> {
+        self.0.remainder()
     }
 }
 
@@ -806,44 +811,48 @@ generate_pattern_iterators! {
 }
 
 impl<'a, P: Pattern<'a>> SplitTerminator<'a, P> {
-    /// Returns remainder of the split string
+    /// Returns remainder of the split string.
+    ///
+    /// If the iterator is empty, returns `None`.
     ///
     /// # Examples
     ///
     /// ```
-    /// #![feature(str_split_as_str)]
+    /// #![feature(str_split_remainder)]
     /// let mut split = "A..B..".split_terminator('.');
-    /// assert_eq!(split.as_str(), "A..B..");
+    /// assert_eq!(split.remainder(), Some("A..B.."));
     /// split.next();
-    /// assert_eq!(split.as_str(), ".B..");
+    /// assert_eq!(split.remainder(), Some(".B.."));
     /// split.by_ref().for_each(drop);
-    /// assert_eq!(split.as_str(), "");
+    /// assert_eq!(split.remainder(), None);
     /// ```
     #[inline]
-    #[unstable(feature = "str_split_as_str", issue = "77998")]
-    pub fn as_str(&self) -> &'a str {
-        self.0.as_str()
+    #[unstable(feature = "str_split_remainder", issue = "77998")]
+    pub fn remainder(&self) -> Option<&'a str> {
+        self.0.remainder()
     }
 }
 
 impl<'a, P: Pattern<'a>> RSplitTerminator<'a, P> {
-    /// Returns remainder of the split string
+    /// Returns remainder of the split string.
+    ///
+    /// If the iterator is empty, returns `None`.
     ///
     /// # Examples
     ///
     /// ```
-    /// #![feature(str_split_as_str)]
+    /// #![feature(str_split_remainder)]
     /// let mut split = "A..B..".rsplit_terminator('.');
-    /// assert_eq!(split.as_str(), "A..B..");
+    /// assert_eq!(split.remainder(), Some("A..B.."));
     /// split.next();
-    /// assert_eq!(split.as_str(), "A..B");
+    /// assert_eq!(split.remainder(), Some("A..B"));
     /// split.by_ref().for_each(drop);
-    /// assert_eq!(split.as_str(), "");
+    /// assert_eq!(split.remainder(), None);
     /// ```
     #[inline]
-    #[unstable(feature = "str_split_as_str", issue = "77998")]
-    pub fn as_str(&self) -> &'a str {
-        self.0.as_str()
+    #[unstable(feature = "str_split_remainder", issue = "77998")]
+    pub fn remainder(&self) -> Option<&'a str> {
+        self.0.remainder()
     }
 }
 
@@ -905,8 +914,8 @@ impl<'a, P: Pattern<'a>> SplitNInternal<'a, P> {
     }
 
     #[inline]
-    fn as_str(&self) -> &'a str {
-        self.iter.as_str()
+    fn remainder(&self) -> Option<&'a str> {
+        self.iter.remainder()
     }
 }
 
@@ -929,44 +938,48 @@ generate_pattern_iterators! {
 }
 
 impl<'a, P: Pattern<'a>> SplitN<'a, P> {
-    /// Returns remainder of the split string
+    /// Returns remainder of the split string.
+    ///
+    /// If the iterator is empty, returns `None`.
     ///
     /// # Examples
     ///
     /// ```
-    /// #![feature(str_split_as_str)]
+    /// #![feature(str_split_remainder)]
     /// let mut split = "Mary had a little lamb".splitn(3, ' ');
-    /// assert_eq!(split.as_str(), "Mary had a little lamb");
+    /// assert_eq!(split.remainder(), Some("Mary had a little lamb"));
     /// split.next();
-    /// assert_eq!(split.as_str(), "had a little lamb");
+    /// assert_eq!(split.remainder(), Some("had a little lamb"));
     /// split.by_ref().for_each(drop);
-    /// assert_eq!(split.as_str(), "");
+    /// assert_eq!(split.remainder(), None);
     /// ```
     #[inline]
-    #[unstable(feature = "str_split_as_str", issue = "77998")]
-    pub fn as_str(&self) -> &'a str {
-        self.0.as_str()
+    #[unstable(feature = "str_split_remainder", issue = "77998")]
+    pub fn remainder(&self) -> Option<&'a str> {
+        self.0.remainder()
     }
 }
 
 impl<'a, P: Pattern<'a>> RSplitN<'a, P> {
-    /// Returns remainder of the split string
+    /// Returns remainder of the split string.
+    ///
+    /// If the iterator is empty, returns `None`.
     ///
     /// # Examples
     ///
     /// ```
-    /// #![feature(str_split_as_str)]
+    /// #![feature(str_split_remainder)]
     /// let mut split = "Mary had a little lamb".rsplitn(3, ' ');
-    /// assert_eq!(split.as_str(), "Mary had a little lamb");
+    /// assert_eq!(split.remainder(), Some("Mary had a little lamb"));
     /// split.next();
-    /// assert_eq!(split.as_str(), "Mary had a little");
+    /// assert_eq!(split.remainder(), Some("Mary had a little"));
     /// split.by_ref().for_each(drop);
-    /// assert_eq!(split.as_str(), "");
+    /// assert_eq!(split.remainder(), None);
     /// ```
     #[inline]
-    #[unstable(feature = "str_split_as_str", issue = "77998")]
-    pub fn as_str(&self) -> &'a str {
-        self.0.as_str()
+    #[unstable(feature = "str_split_remainder", issue = "77998")]
+    pub fn remainder(&self) -> Option<&'a str> {
+        self.0.remainder()
     }
 }
 
@@ -1239,22 +1252,22 @@ impl<'a> SplitWhitespace<'a> {
     /// # Examples
     ///
     /// ```
-    /// #![feature(str_split_whitespace_as_str)]
+    /// #![feature(str_split_whitespace_remainder)]
     ///
     /// let mut split = "Mary had a little lamb".split_whitespace();
-    /// assert_eq!(split.as_str(), "Mary had a little lamb");
+    /// assert_eq!(split.remainder(), Some("Mary had a little lamb"));
     ///
     /// split.next();
-    /// assert_eq!(split.as_str(), "had a little lamb");
+    /// assert_eq!(split.remainder(), Some("had a little lamb"));
     ///
     /// split.by_ref().for_each(drop);
-    /// assert_eq!(split.as_str(), "");
+    /// assert_eq!(split.remainder(), None);
     /// ```
     #[inline]
     #[must_use]
-    #[unstable(feature = "str_split_whitespace_as_str", issue = "77998")]
-    pub fn as_str(&self) -> &'a str {
-        self.inner.iter.as_str()
+    #[unstable(feature = "str_split_whitespace_remainder", issue = "77998")]
+    pub fn remainder(&self) -> Option<&'a str> {
+        self.inner.iter.remainder()
     }
 }
 
@@ -1290,32 +1303,34 @@ impl<'a> DoubleEndedIterator for SplitAsciiWhitespace<'a> {
 impl FusedIterator for SplitAsciiWhitespace<'_> {}
 
 impl<'a> SplitAsciiWhitespace<'a> {
-    /// Returns remainder of the split string
+    /// Returns remainder of the split string.
+    ///
+    /// If the iterator is empty, returns `None`.
     ///
     /// # Examples
     ///
     /// ```
-    /// #![feature(str_split_whitespace_as_str)]
+    /// #![feature(str_split_whitespace_remainder)]
     ///
     /// let mut split = "Mary had a little lamb".split_ascii_whitespace();
-    /// assert_eq!(split.as_str(), "Mary had a little lamb");
+    /// assert_eq!(split.remainder(), Some("Mary had a little lamb"));
     ///
     /// split.next();
-    /// assert_eq!(split.as_str(), "had a little lamb");
+    /// assert_eq!(split.remainder(), Some("had a little lamb"));
     ///
     /// split.by_ref().for_each(drop);
-    /// assert_eq!(split.as_str(), "");
+    /// assert_eq!(split.remainder(), None);
     /// ```
     #[inline]
     #[must_use]
-    #[unstable(feature = "str_split_whitespace_as_str", issue = "77998")]
-    pub fn as_str(&self) -> &'a str {
+    #[unstable(feature = "str_split_whitespace_remainder", issue = "77998")]
+    pub fn remainder(&self) -> Option<&'a str> {
         if self.inner.iter.iter.finished {
-            return "";
+            return None;
         }
 
         // SAFETY: Slice is created from str.
-        unsafe { crate::str::from_utf8_unchecked(&self.inner.iter.iter.v) }
+        Some(unsafe { crate::str::from_utf8_unchecked(&self.inner.iter.iter.v) })
     }
 }
 
@@ -1358,23 +1373,25 @@ impl<'a, P: Pattern<'a, Searcher: ReverseSearcher<'a>>> DoubleEndedIterator
 impl<'a, P: Pattern<'a>> FusedIterator for SplitInclusive<'a, P> {}
 
 impl<'a, P: Pattern<'a>> SplitInclusive<'a, P> {
-    /// Returns remainder of the split string
+    /// Returns remainder of the split string.
+    ///
+    /// If the iterator is empty, returns `None`.
     ///
     /// # Examples
     ///
     /// ```
-    /// #![feature(str_split_inclusive_as_str)]
+    /// #![feature(str_split_inclusive_remainder)]
     /// let mut split = "Mary had a little lamb".split_inclusive(' ');
-    /// assert_eq!(split.as_str(), "Mary had a little lamb");
+    /// assert_eq!(split.remainder(), Some("Mary had a little lamb"));
     /// split.next();
-    /// assert_eq!(split.as_str(), "had a little lamb");
+    /// assert_eq!(split.remainder(), Some("had a little lamb"));
     /// split.by_ref().for_each(drop);
-    /// assert_eq!(split.as_str(), "");
+    /// assert_eq!(split.remainder(), None);
     /// ```
     #[inline]
-    #[unstable(feature = "str_split_inclusive_as_str", issue = "77998")]
-    pub fn as_str(&self) -> &'a str {
-        self.0.as_str()
+    #[unstable(feature = "str_split_inclusive_remainder", issue = "77998")]
+    pub fn remainder(&self) -> Option<&'a str> {
+        self.0.remainder()
     }
 }
 
diff --git a/library/core/src/task/wake.rs b/library/core/src/task/wake.rs
index 1b7578376b4..a4425fd234a 100644
--- a/library/core/src/task/wake.rs
+++ b/library/core/src/task/wake.rs
@@ -181,6 +181,9 @@ pub struct Context<'a> {
     // are contravariant while return-position lifetimes are
     // covariant).
     _marker: PhantomData<fn(&'a ()) -> &'a ()>,
+    // Ensure `Context` is `!Send` and `!Sync` in order to allow
+    // for future `!Send` and / or `!Sync` fields.
+    _marker2: PhantomData<*mut ()>,
 }
 
 impl<'a> Context<'a> {
@@ -190,7 +193,7 @@ impl<'a> Context<'a> {
     #[must_use]
     #[inline]
     pub const fn from_waker(waker: &'a Waker) -> Self {
-        Context { waker, _marker: PhantomData }
+        Context { waker, _marker: PhantomData, _marker2: PhantomData }
     }
 
     /// Returns a reference to the [`Waker`] for the current task.
diff --git a/library/core/tests/task.rs b/library/core/tests/task.rs
index 56be30e9282..163b34c9648 100644
--- a/library/core/tests/task.rs
+++ b/library/core/tests/task.rs
@@ -1,4 +1,4 @@
-use core::task::{Context, Poll, RawWaker, RawWakerVTable, Waker};
+use core::task::{Poll, RawWaker, RawWakerVTable, Waker};
 
 #[test]
 fn poll_const() {
@@ -21,9 +21,5 @@ fn waker_const() {
 
     static WAKER: Waker = unsafe { Waker::from_raw(VOID_WAKER) };
 
-    static CONTEXT: Context<'static> = Context::from_waker(&WAKER);
-
-    static WAKER_REF: &'static Waker = CONTEXT.waker();
-
-    WAKER_REF.wake_by_ref();
+    WAKER.wake_by_ref();
 }
diff --git a/library/std/src/path.rs b/library/std/src/path.rs
index ef8a14be73d..19d8f1edaf4 100644
--- a/library/std/src/path.rs
+++ b/library/std/src/path.rs
@@ -1414,7 +1414,8 @@ impl PathBuf {
         self.push(file_name);
     }
 
-    /// Updates [`self.extension`] to `extension`.
+    /// Updates [`self.extension`] to `Some(extension)` or to `None` if
+    /// `extension` is empty.
     ///
     /// Returns `false` and does nothing if [`self.file_name`] is [`None`],
     /// returns `true` and updates the extension otherwise.
@@ -1422,6 +1423,20 @@ impl PathBuf {
     /// If [`self.extension`] is [`None`], the extension is added; otherwise
     /// it is replaced.
     ///
+    /// If `extension` is the empty string, [`self.extension`] will be [`None`]
+    /// afterwards, not `Some("")`.
+    ///
+    /// # Caveats
+    ///
+    /// The new `extension` may contain dots and will be used in its entirety,
+    /// but only the part after the final dot will be reflected in
+    /// [`self.extension`].
+    ///
+    /// If the file stem contains internal dots and `extension` is empty, part
+    /// of the old file stem will be considered the new [`self.extension`].
+    ///
+    /// See the examples below.
+    ///
     /// [`self.file_name`]: Path::file_name
     /// [`self.extension`]: Path::extension
     ///
@@ -1435,8 +1450,20 @@ impl PathBuf {
     /// p.set_extension("force");
     /// assert_eq!(Path::new("/feel/the.force"), p.as_path());
     ///
-    /// p.set_extension("dark_side");
-    /// assert_eq!(Path::new("/feel/the.dark_side"), p.as_path());
+    /// p.set_extension("dark.side");
+    /// assert_eq!(Path::new("/feel/the.dark.side"), p.as_path());
+    ///
+    /// p.set_extension("cookie");
+    /// assert_eq!(Path::new("/feel/the.dark.cookie"), p.as_path());
+    ///
+    /// p.set_extension("");
+    /// assert_eq!(Path::new("/feel/the.dark"), p.as_path());
+    ///
+    /// p.set_extension("");
+    /// assert_eq!(Path::new("/feel/the"), p.as_path());
+    ///
+    /// p.set_extension("");
+    /// assert_eq!(Path::new("/feel/the"), p.as_path());
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn set_extension<S: AsRef<OsStr>>(&mut self, extension: S) -> bool {
diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py
index 9cf43fc7a21..f3998e98583 100644
--- a/src/bootstrap/bootstrap.py
+++ b/src/bootstrap/bootstrap.py
@@ -934,8 +934,7 @@ def main():
     if len(sys.argv) > 1 and sys.argv[1] == 'help':
         sys.argv = [sys.argv[0], '-h'] + sys.argv[2:]
 
-    help_triggered = (
-        '-h' in sys.argv) or ('--help' in sys.argv) or (len(sys.argv) == 1)
+    help_triggered = len(sys.argv) == 1 or any(x in ["-h", "--help", "--version"] for x in sys.argv)
     try:
         bootstrap(help_triggered)
         if not help_triggered:
diff --git a/src/bootstrap/check.rs b/src/bootstrap/check.rs
index 32e5d414061..b203ecd3844 100644
--- a/src/bootstrap/check.rs
+++ b/src/bootstrap/check.rs
@@ -105,7 +105,7 @@ impl Step for Std {
             "Checking stage{} library artifacts ({} -> {})",
             builder.top_stage, &compiler.host, target
         ));
-        run_cargo(builder, cargo, &libstd_stamp(builder, compiler, target), vec![], true);
+        run_cargo(builder, cargo, &libstd_stamp(builder, compiler, target), vec![], true, false);
 
         // We skip populating the sysroot in non-zero stage because that'll lead
         // to rlib/rmeta conflicts if std gets built during this session.
@@ -155,7 +155,14 @@ impl Step for Std {
             "Checking stage{} library test/bench/example targets ({} -> {})",
             builder.top_stage, &compiler.host, target
         ));
-        run_cargo(builder, cargo, &libstd_test_stamp(builder, compiler, target), vec![], true);
+        run_cargo(
+            builder,
+            cargo,
+            &libstd_test_stamp(builder, compiler, target),
+            vec![],
+            true,
+            false,
+        );
     }
 }
 
@@ -225,7 +232,7 @@ impl Step for Rustc {
             "Checking stage{} compiler artifacts ({} -> {})",
             builder.top_stage, &compiler.host, target
         ));
-        run_cargo(builder, cargo, &librustc_stamp(builder, compiler, target), vec![], true);
+        run_cargo(builder, cargo, &librustc_stamp(builder, compiler, target), vec![], true, false);
 
         let libdir = builder.sysroot_libdir(compiler, target);
         let hostdir = builder.sysroot_libdir(compiler, compiler.host);
@@ -285,6 +292,7 @@ impl Step for CodegenBackend {
             &codegen_backend_stamp(builder, compiler, target, backend),
             vec![],
             true,
+            false,
         );
     }
 }
@@ -343,7 +351,7 @@ impl Step for RustAnalyzer {
             "Checking stage{} {} artifacts ({} -> {})",
             compiler.stage, "rust-analyzer", &compiler.host.triple, target.triple
         ));
-        run_cargo(builder, cargo, &stamp(builder, compiler, target), vec![], true);
+        run_cargo(builder, cargo, &stamp(builder, compiler, target), vec![], true, false);
 
         /// Cargo's output path in a given stage, compiled by a particular
         /// compiler for the specified target.
@@ -417,6 +425,7 @@ macro_rules! tool_check_step {
                     &stamp(builder, compiler, target),
                     vec![],
                     true,
+                    false,
                 );
 
                 /// Cargo's output path in a given stage, compiled by a particular
diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs
index f9a04f2e91d..147ded3a9ee 100644
--- a/src/bootstrap/compile.rs
+++ b/src/bootstrap/compile.rs
@@ -141,7 +141,14 @@ impl Step for Std {
             &compiler.host,
             target,
         ));
-        run_cargo(builder, cargo, &libstd_stamp(builder, compiler, target), target_deps, false);
+        run_cargo(
+            builder,
+            cargo,
+            &libstd_stamp(builder, compiler, target),
+            target_deps,
+            false,
+            false,
+        );
 
         builder.ensure(StdLink::from_std(
             self,
@@ -728,7 +735,14 @@ impl Step for Rustc {
             &compiler.host,
             target,
         ));
-        run_cargo(builder, cargo, &librustc_stamp(builder, compiler, target), vec![], false);
+        run_cargo(
+            builder,
+            cargo,
+            &librustc_stamp(builder, compiler, target),
+            vec![],
+            false,
+            true, // Only ship rustc_driver.so and .rmeta files, not all intermediate .rlib files.
+        );
 
         builder.ensure(RustcLink::from_rustc(
             self,
@@ -984,7 +998,7 @@ impl Step for CodegenBackend {
             "Building stage{} codegen backend {} ({} -> {})",
             compiler.stage, backend, &compiler.host, target
         ));
-        let files = run_cargo(builder, cargo, &tmp_stamp, vec![], false);
+        let files = run_cargo(builder, cargo, &tmp_stamp, vec![], false, false);
         if builder.config.dry_run() {
             return;
         }
@@ -1411,6 +1425,7 @@ pub fn run_cargo(
     stamp: &Path,
     additional_target_deps: Vec<(PathBuf, DependencyType)>,
     is_check: bool,
+    rlib_only_metadata: bool,
 ) -> Vec<PathBuf> {
     if builder.config.dry_run() {
         return Vec::new();
@@ -1444,13 +1459,35 @@ pub fn run_cargo(
         };
         for filename in filenames {
             // Skip files like executables
-            if !(filename.ends_with(".rlib")
-                || filename.ends_with(".lib")
+            let mut keep = false;
+            if filename.ends_with(".lib")
                 || filename.ends_with(".a")
                 || is_debug_info(&filename)
                 || is_dylib(&filename)
-                || (is_check && filename.ends_with(".rmeta")))
             {
+                // Always keep native libraries, rust dylibs and debuginfo
+                keep = true;
+            }
+            if is_check && filename.ends_with(".rmeta") {
+                // During check builds we need to keep crate metadata
+                keep = true;
+            } else if rlib_only_metadata {
+                if filename.contains("jemalloc_sys") || filename.contains("rustc_smir") {
+                    // jemalloc_sys and rustc_smir are not linked into librustc_driver.so,
+                    // so we need to distribute them as rlib to be able to use them.
+                    keep |= filename.ends_with(".rlib");
+                } else {
+                    // Distribute the rest of the rustc crates as rmeta files only to reduce
+                    // the tarball sizes by about 50%. The object files are linked into
+                    // librustc_driver.so, so it is still possible to link against them.
+                    keep |= filename.ends_with(".rmeta");
+                }
+            } else {
+                // In all other cases keep all rlibs
+                keep |= filename.ends_with(".rlib");
+            }
+
+            if !keep {
                 continue;
             }
 
diff --git a/src/ci/docker/host-x86_64/mingw-check-tidy/Dockerfile b/src/ci/docker/host-x86_64/mingw-check-tidy/Dockerfile
index c340294fc73..dc0e591cad6 100644
--- a/src/ci/docker/host-x86_64/mingw-check-tidy/Dockerfile
+++ b/src/ci/docker/host-x86_64/mingw-check-tidy/Dockerfile
@@ -32,5 +32,4 @@ RUN pip3 install --no-deps --no-cache-dir --require-hashes -r /tmp/reuse-require
 COPY host-x86_64/mingw-check/validate-toolstate.sh /scripts/
 COPY host-x86_64/mingw-check/validate-error-codes.sh /scripts/
 
-ENV RUN_CHECK_WITH_PARALLEL_QUERIES 1
 ENV SCRIPT python3 ../x.py test --stage 0 src/tools/tidy tidyselftest
diff --git a/src/ci/run.sh b/src/ci/run.sh
index b6430027750..0db9c993eec 100755
--- a/src/ci/run.sh
+++ b/src/ci/run.sh
@@ -184,11 +184,11 @@ if [ "$RUN_CHECK_WITH_PARALLEL_QUERIES" != "" ]; then
   $SRC/configure --set rust.parallel-compiler
 
   # Save the build metrics before we wipe the directory
-  if [ $HAS_METRICS = 1 ]; then
+  if [ "$HAS_METRICS" = 1 ]; then
     mv build/metrics.json .
   fi
   rm -rf build
-  if [ $HAS_METRICS = 1 ]; then
+  if [ "$HAS_METRICS" = 1 ]; then
     mkdir build
     mv metrics.json build
   fi
diff --git a/src/doc/book b/src/doc/book
-Subproject a60f4316ec923a5ac2ed6a2eba6960edb832d85
+Subproject 2bd5d42c9956369132228da6409f0e68da56c51
diff --git a/src/doc/nomicon b/src/doc/nomicon
-Subproject dd37e21ccee43918ed18a71581bb2af537ffe4f
+Subproject 8ca261268068d80c0969260fff15199bad87b58
diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example
-Subproject 995df09b65c582eb6290ab7ea5d9485983eb4c3
+Subproject 8888f9428fe9a48f31de6bd2cef9b9bf80791ed
diff --git a/src/doc/rustc-dev-guide b/src/doc/rustc-dev-guide
-Subproject 8b42eb5f57d3d8ed2257a22d0e850d9db52afed
+Subproject b3e2a6e6c8a3aae5b5d950c63046f23bae07096
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 8f409965356..025a4379f45 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -1853,7 +1853,7 @@ pub(crate) fn clean_middle_ty<'tcx>(
         ty::Placeholder(..) => panic!("Placeholder"),
         ty::GeneratorWitness(..) => panic!("GeneratorWitness"),
         ty::Infer(..) => panic!("Infer"),
-        ty::Error(_) => panic!("Error"),
+        ty::Error(_) => rustc_errors::FatalError.raise(),
     }
 }
 
@@ -1949,20 +1949,27 @@ pub(crate) fn clean_field_with_def_id(
 }
 
 pub(crate) fn clean_variant_def<'tcx>(variant: &ty::VariantDef, cx: &mut DocContext<'tcx>) -> Item {
+    let discriminant = match variant.discr {
+        ty::VariantDiscr::Explicit(def_id) => Some(Discriminant { expr: None, value: def_id }),
+        ty::VariantDiscr::Relative(_) => None,
+    };
+
     let kind = match variant.ctor_kind() {
-        Some(CtorKind::Const) => Variant::CLike(match variant.discr {
-            ty::VariantDiscr::Explicit(def_id) => Some(Discriminant { expr: None, value: def_id }),
-            ty::VariantDiscr::Relative(_) => None,
-        }),
-        Some(CtorKind::Fn) => Variant::Tuple(
+        Some(CtorKind::Const) => VariantKind::CLike,
+        Some(CtorKind::Fn) => VariantKind::Tuple(
             variant.fields.iter().map(|field| clean_middle_field(field, cx)).collect(),
         ),
-        None => Variant::Struct(VariantStruct {
-            ctor_kind: None,
+        None => VariantKind::Struct(VariantStruct {
             fields: variant.fields.iter().map(|field| clean_middle_field(field, cx)).collect(),
         }),
     };
-    Item::from_def_id_and_parts(variant.def_id, Some(variant.name), VariantItem(kind), cx)
+
+    Item::from_def_id_and_parts(
+        variant.def_id,
+        Some(variant.name),
+        VariantItem(Variant { kind, discriminant }),
+        cx,
+    )
 }
 
 fn clean_variant_data<'tcx>(
@@ -1970,19 +1977,22 @@ fn clean_variant_data<'tcx>(
     disr_expr: &Option<hir::AnonConst>,
     cx: &mut DocContext<'tcx>,
 ) -> Variant {
-    match variant {
-        hir::VariantData::Struct(..) => Variant::Struct(VariantStruct {
-            ctor_kind: None,
+    let discriminant = disr_expr.map(|disr| Discriminant {
+        expr: Some(disr.body),
+        value: cx.tcx.hir().local_def_id(disr.hir_id).to_def_id(),
+    });
+
+    let kind = match variant {
+        hir::VariantData::Struct(..) => VariantKind::Struct(VariantStruct {
             fields: variant.fields().iter().map(|x| clean_field(x, cx)).collect(),
         }),
         hir::VariantData::Tuple(..) => {
-            Variant::Tuple(variant.fields().iter().map(|x| clean_field(x, cx)).collect())
+            VariantKind::Tuple(variant.fields().iter().map(|x| clean_field(x, cx)).collect())
         }
-        hir::VariantData::Unit(..) => Variant::CLike(disr_expr.map(|disr| Discriminant {
-            expr: Some(disr.body),
-            value: cx.tcx.hir().local_def_id(disr.hir_id).to_def_id(),
-        })),
-    }
+        hir::VariantData::Unit(..) => VariantKind::CLike,
+    };
+
+    Variant { discriminant, kind }
 }
 
 fn clean_path<'tcx>(path: &hir::Path<'tcx>, cx: &mut DocContext<'tcx>) -> Path {
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index 62217df8de7..6d55a6794f5 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -807,8 +807,11 @@ impl ItemKind {
         match self {
             StructItem(s) => s.fields.iter(),
             UnionItem(u) => u.fields.iter(),
-            VariantItem(Variant::Struct(v)) => v.fields.iter(),
-            VariantItem(Variant::Tuple(v)) => v.iter(),
+            VariantItem(v) => match &v.kind {
+                VariantKind::CLike => [].iter(),
+                VariantKind::Tuple(t) => t.iter(),
+                VariantKind::Struct(s) => s.fields.iter(),
+            },
             EnumItem(e) => e.variants.iter(),
             TraitItem(t) => t.items.iter(),
             ImplItem(i) => i.items.iter(),
@@ -824,7 +827,6 @@ impl ItemKind {
             | TyMethodItem(_)
             | MethodItem(_, _)
             | StructFieldItem(_)
-            | VariantItem(_)
             | ForeignFunctionItem(_)
             | ForeignStaticItem(_)
             | ForeignTypeItem
@@ -2109,7 +2111,6 @@ impl Union {
 /// only as a variant in an enum.
 #[derive(Clone, Debug)]
 pub(crate) struct VariantStruct {
-    pub(crate) ctor_kind: Option<CtorKind>,
     pub(crate) fields: Vec<Item>,
 }
 
@@ -2136,17 +2137,23 @@ impl Enum {
 }
 
 #[derive(Clone, Debug)]
-pub(crate) enum Variant {
-    CLike(Option<Discriminant>),
+pub(crate) struct Variant {
+    pub kind: VariantKind,
+    pub discriminant: Option<Discriminant>,
+}
+
+#[derive(Clone, Debug)]
+pub(crate) enum VariantKind {
+    CLike,
     Tuple(Vec<Item>),
     Struct(VariantStruct),
 }
 
 impl Variant {
     pub(crate) fn has_stripped_entries(&self) -> Option<bool> {
-        match *self {
-            Self::Struct(ref struct_) => Some(struct_.has_stripped_entries()),
-            Self::CLike(..) | Self::Tuple(_) => None,
+        match &self.kind {
+            VariantKind::Struct(struct_) => Some(struct_.has_stripped_entries()),
+            VariantKind::CLike | VariantKind::Tuple(_) => None,
         }
     }
 }
diff --git a/src/librustdoc/fold.rs b/src/librustdoc/fold.rs
index c6f1f9de51a..656aeefb01a 100644
--- a/src/librustdoc/fold.rs
+++ b/src/librustdoc/fold.rs
@@ -37,17 +37,21 @@ pub(crate) trait DocFolder: Sized {
                 i.items = i.items.into_iter().filter_map(|x| self.fold_item(x)).collect();
                 ImplItem(i)
             }
-            VariantItem(i) => match i {
-                Variant::Struct(mut j) => {
-                    j.fields = j.fields.into_iter().filter_map(|x| self.fold_item(x)).collect();
-                    VariantItem(Variant::Struct(j))
-                }
-                Variant::Tuple(fields) => {
-                    let fields = fields.into_iter().filter_map(|x| self.fold_item(x)).collect();
-                    VariantItem(Variant::Tuple(fields))
-                }
-                Variant::CLike(disr) => VariantItem(Variant::CLike(disr)),
-            },
+            VariantItem(Variant { kind, discriminant }) => {
+                let kind = match kind {
+                    VariantKind::Struct(mut j) => {
+                        j.fields = j.fields.into_iter().filter_map(|x| self.fold_item(x)).collect();
+                        VariantKind::Struct(j)
+                    }
+                    VariantKind::Tuple(fields) => {
+                        let fields = fields.into_iter().filter_map(|x| self.fold_item(x)).collect();
+                        VariantKind::Tuple(fields)
+                    }
+                    VariantKind::CLike => VariantKind::CLike,
+                };
+
+                VariantItem(Variant { kind, discriminant })
+            }
             ExternCrateItem { src: _ }
             | ImportItem(_)
             | FunctionItem(_)
diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs
index a7b57c373e3..c16d6477fc3 100644
--- a/src/librustdoc/html/render/print_item.rs
+++ b/src/librustdoc/html/render/print_item.rs
@@ -1220,25 +1220,16 @@ fn item_enum(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, e: &clean::
                     w.write_str("    ");
                     let name = v.name.unwrap();
                     match *v.kind {
-                        clean::VariantItem(ref var) => match var {
-                            // FIXME(#101337): Show discriminant
-                            clean::Variant::CLike(..) => write!(w, "{}", name),
-                            clean::Variant::Tuple(ref s) => {
+                        // FIXME(#101337): Show discriminant
+                        clean::VariantItem(ref var) => match var.kind {
+                            clean::VariantKind::CLike => write!(w, "{}", name),
+                            clean::VariantKind::Tuple(ref s) => {
                                 write!(w, "{}(", name);
                                 print_tuple_struct_fields(w, cx, s);
                                 w.write_str(")");
                             }
-                            clean::Variant::Struct(ref s) => {
-                                render_struct(
-                                    w,
-                                    v,
-                                    None,
-                                    s.ctor_kind,
-                                    &s.fields,
-                                    "    ",
-                                    false,
-                                    cx,
-                                );
+                            clean::VariantKind::Struct(ref s) => {
+                                render_struct(w, v, None, None, &s.fields, "    ", false, cx);
                             }
                         },
                         _ => unreachable!(),
@@ -1286,25 +1277,28 @@ fn item_enum(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, e: &clean::
                 " rightside",
             );
             write!(w, "<h3 class=\"code-header\">{name}", name = variant.name.unwrap());
-            if let clean::VariantItem(clean::Variant::Tuple(ref s)) = *variant.kind {
+
+            let clean::VariantItem(variant_data) = &*variant.kind else { unreachable!() };
+
+            if let clean::VariantKind::Tuple(ref s) = variant_data.kind {
                 w.write_str("(");
                 print_tuple_struct_fields(w, cx, s);
                 w.write_str(")");
             }
             w.write_str("</h3></section>");
 
-            use crate::clean::Variant;
-
-            let heading_and_fields = match &*variant.kind {
-                clean::VariantItem(Variant::Struct(s)) => Some(("Fields", &s.fields)),
-                // Documentation on tuple variant fields is rare, so to reduce noise we only emit
-                // the section if at least one field is documented.
-                clean::VariantItem(Variant::Tuple(fields))
-                    if fields.iter().any(|f| f.doc_value().is_some()) =>
-                {
-                    Some(("Tuple Fields", fields))
+            let heading_and_fields = match &variant_data.kind {
+                clean::VariantKind::Struct(s) => Some(("Fields", &s.fields)),
+                clean::VariantKind::Tuple(fields) => {
+                    // Documentation on tuple variant fields is rare, so to reduce noise we only emit
+                    // the section if at least one field is documented.
+                    if fields.iter().any(|f| f.doc_value().is_some()) {
+                        Some(("Tuple Fields", fields))
+                    } else {
+                        None
+                    }
                 }
-                _ => None,
+                clean::VariantKind::CLike => None,
             };
 
             if let Some((heading, fields)) = heading_and_fields {
diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs
index d7184053c87..84af194904d 100644
--- a/src/librustdoc/json/conversions.rs
+++ b/src/librustdoc/json/conversions.rs
@@ -646,15 +646,20 @@ impl FromWithTcx<clean::Enum> for Enum {
 
 impl FromWithTcx<clean::Variant> for Variant {
     fn from_tcx(variant: clean::Variant, tcx: TyCtxt<'_>) -> Self {
-        use clean::Variant::*;
-        match variant {
-            CLike(disr) => Variant::Plain(disr.map(|disr| disr.into_tcx(tcx))),
-            Tuple(fields) => Variant::Tuple(ids_keeping_stripped(fields, tcx)),
-            Struct(s) => Variant::Struct {
+        use clean::VariantKind::*;
+
+        let discriminant = variant.discriminant.map(|d| d.into_tcx(tcx));
+
+        let kind = match variant.kind {
+            CLike => VariantKind::Plain,
+            Tuple(fields) => VariantKind::Tuple(ids_keeping_stripped(fields, tcx)),
+            Struct(s) => VariantKind::Struct {
                 fields_stripped: s.has_stripped_entries(),
                 fields: ids(s.fields, tcx),
             },
-        }
+        };
+
+        Variant { kind, discriminant }
     }
 }
 
diff --git a/src/librustdoc/passes/stripper.rs b/src/librustdoc/passes/stripper.rs
index 995fb5dcc1c..bf111133b9f 100644
--- a/src/librustdoc/passes/stripper.rs
+++ b/src/librustdoc/passes/stripper.rs
@@ -132,7 +132,10 @@ impl<'a, 'tcx> DocFolder for Stripper<'a, 'tcx> {
             // implementations of traits are always public.
             clean::ImplItem(ref imp) if imp.trait_.is_some() => true,
             // Variant fields have inherited visibility
-            clean::VariantItem(clean::Variant::Struct(..) | clean::Variant::Tuple(..)) => true,
+            clean::VariantItem(clean::Variant {
+                kind: clean::VariantKind::Struct(..) | clean::VariantKind::Tuple(..),
+                ..
+            }) => true,
             _ => false,
         };
 
diff --git a/src/librustdoc/visit.rs b/src/librustdoc/visit.rs
index d29ceead4f3..390b9436121 100644
--- a/src/librustdoc/visit.rs
+++ b/src/librustdoc/visit.rs
@@ -17,10 +17,10 @@ pub(crate) trait DocVisitor: Sized {
             EnumItem(i) => i.variants.iter().for_each(|x| self.visit_item(x)),
             TraitItem(i) => i.items.iter().for_each(|x| self.visit_item(x)),
             ImplItem(i) => i.items.iter().for_each(|x| self.visit_item(x)),
-            VariantItem(i) => match i {
-                Variant::Struct(j) => j.fields.iter().for_each(|x| self.visit_item(x)),
-                Variant::Tuple(fields) => fields.iter().for_each(|x| self.visit_item(x)),
-                Variant::CLike(_) => {}
+            VariantItem(i) => match &i.kind {
+                VariantKind::Struct(j) => j.fields.iter().for_each(|x| self.visit_item(x)),
+                VariantKind::Tuple(fields) => fields.iter().for_each(|x| self.visit_item(x)),
+                VariantKind::CLike => {}
             },
             ExternCrateItem { src: _ }
             | ImportItem(_)
diff --git a/src/rustdoc-json-types/lib.rs b/src/rustdoc-json-types/lib.rs
index 1ee96b8231c..387d5787dfc 100644
--- a/src/rustdoc-json-types/lib.rs
+++ b/src/rustdoc-json-types/lib.rs
@@ -9,7 +9,7 @@ use std::path::PathBuf;
 use serde::{Deserialize, Serialize};
 
 /// rustdoc format-version.
-pub const FORMAT_VERSION: u32 = 23;
+pub const FORMAT_VERSION: u32 = 24;
 
 /// A `Crate` is the root of the emitted JSON blob. It contains all type/documentation information
 /// about the language items in the local crate, as well as info about external items to allow
@@ -334,10 +334,17 @@ pub struct Enum {
 }
 
 #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
+pub struct Variant {
+    /// Whether the variant is plain, a tuple-like, or struct-like. Contains the fields.
+    pub kind: VariantKind,
+    /// The discriminant, if explicitly specified.
+    pub discriminant: Option<Discriminant>,
+}
+
+#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 #[serde(rename_all = "snake_case")]
-#[serde(tag = "variant_kind", content = "variant_inner")]
-pub enum Variant {
-    /// A variant with no parentheses, and possible discriminant.
+pub enum VariantKind {
+    /// A variant with no parentheses
     ///
     /// ```rust
     /// enum Demo {
@@ -345,7 +352,7 @@ pub enum Variant {
     ///     PlainWithDiscriminant = 1,
     /// }
     /// ```
-    Plain(Option<Discriminant>),
+    Plain,
     /// A variant with unnamed fields.
     ///
     /// Unlike most of json, `#[doc(hidden)]` fields will be given as `None`
diff --git a/src/test/codegen/function-arguments.rs b/src/test/codegen/function-arguments.rs
index 44fee952307..0f9e90f6ba7 100644
--- a/src/test/codegen/function-arguments.rs
+++ b/src/test/codegen/function-arguments.rs
@@ -145,7 +145,7 @@ pub fn raw_struct(_: *const S) {
 
 // `Box` can get deallocated during execution of the function, so it should
 // not get `dereferenceable`.
-// CHECK: noalias noundef nonnull align 4 {{i32\*|ptr}} @_box({{i32\*|ptr}} noalias noundef nonnull align 4 %x)
+// CHECK: noundef nonnull align 4 {{i32\*|ptr}} @_box({{i32\*|ptr}} noalias noundef nonnull align 4 %x)
 #[no_mangle]
 pub fn _box(x: Box<i32>) -> Box<i32> {
   x
diff --git a/src/test/codegen/issue-103840.rs b/src/test/codegen/issue-103840.rs
new file mode 100644
index 00000000000..f19d7031bb3
--- /dev/null
+++ b/src/test/codegen/issue-103840.rs
@@ -0,0 +1,9 @@
+// compile-flags: -O
+#![crate_type = "lib"]
+
+pub fn foo(t: &mut Vec<usize>) {
+    // CHECK-NOT: __rust_dealloc
+    let mut taken = std::mem::take(t);
+    taken.pop();
+    *t = taken;
+}
diff --git a/src/test/mir-opt/inline/cycle.g.Inline.diff b/src/test/mir-opt/inline/cycle.g.Inline.diff
index afe157ccd7f..5f3ee467c88 100644
--- a/src/test/mir-opt/inline/cycle.g.Inline.diff
+++ b/src/test/mir-opt/inline/cycle.g.Inline.diff
@@ -10,6 +10,8 @@
 +         let _3: ();                      // in scope 1 at $DIR/cycle.rs:6:5: 6:8
 +         let mut _4: &fn() {main};        // in scope 1 at $DIR/cycle.rs:6:5: 6:6
 +         let mut _5: ();                  // in scope 1 at $DIR/cycle.rs:6:5: 6:8
++         scope 2 (inlined <fn() {main} as Fn<()>>::call - shim(fn() {main})) { // at $DIR/cycle.rs:6:5: 6:8
++         }
 +     }
   
       bb0: {
@@ -27,10 +29,7 @@
 +         StorageLive(_4);                 // scope 1 at $DIR/cycle.rs:6:5: 6:6
 +         _4 = &_2;                        // scope 1 at $DIR/cycle.rs:6:5: 6:6
 +         StorageLive(_5);                 // scope 1 at $DIR/cycle.rs:6:5: 6:8
-+         _3 = <fn() {main} as Fn<()>>::call(move _4, move _5) -> [return: bb2, unwind: bb3]; // scope 1 at $DIR/cycle.rs:6:5: 6:8
-+                                          // mir::Constant
-+                                          // + span: $DIR/cycle.rs:6:5: 6:6
-+                                          // + literal: Const { ty: for<'a> extern "rust-call" fn(&'a fn() {main}, ()) -> <fn() {main} as FnOnce<()>>::Output {<fn() {main} as Fn<()>>::call}, val: Value(<ZST>) }
++         _3 = move (*_4)() -> [return: bb4, unwind: bb2]; // scope 2 at $SRC_DIR/core/src/ops/function.rs:LL:COL
       }
   
       bb1: {
@@ -40,19 +39,19 @@
           return;                          // scope 0 at $DIR/cycle.rs:+2:2: +2:2
 +     }
 + 
-+     bb2: {
-+         StorageDead(_5);                 // scope 1 at $DIR/cycle.rs:6:7: 6:8
-+         StorageDead(_4);                 // scope 1 at $DIR/cycle.rs:6:7: 6:8
-+         StorageDead(_3);                 // scope 1 at $DIR/cycle.rs:6:8: 6:9
-+         drop(_2) -> bb1;                 // scope 1 at $DIR/cycle.rs:7:1: 7:2
++     bb2 (cleanup): {
++         drop(_2) -> bb3;                 // scope 1 at $DIR/cycle.rs:7:1: 7:2
 +     }
 + 
 +     bb3 (cleanup): {
-+         drop(_2) -> bb4;                 // scope 1 at $DIR/cycle.rs:7:1: 7:2
++         resume;                          // scope 1 at $DIR/cycle.rs:5:1: 7:2
 +     }
 + 
-+     bb4 (cleanup): {
-+         resume;                          // scope 1 at $DIR/cycle.rs:5:1: 7:2
++     bb4: {
++         StorageDead(_5);                 // scope 1 at $DIR/cycle.rs:6:7: 6:8
++         StorageDead(_4);                 // scope 1 at $DIR/cycle.rs:6:7: 6:8
++         StorageDead(_3);                 // scope 1 at $DIR/cycle.rs:6:8: 6:9
++         drop(_2) -> bb1;                 // scope 1 at $DIR/cycle.rs:7:1: 7:2
       }
   }
   
diff --git a/src/test/mir-opt/inline/cycle.main.Inline.diff b/src/test/mir-opt/inline/cycle.main.Inline.diff
index bd89e09ecd1..6b4c63bbd91 100644
--- a/src/test/mir-opt/inline/cycle.main.Inline.diff
+++ b/src/test/mir-opt/inline/cycle.main.Inline.diff
@@ -10,6 +10,8 @@
 +         let _3: ();                      // in scope 1 at $DIR/cycle.rs:6:5: 6:8
 +         let mut _4: &fn() {g};           // in scope 1 at $DIR/cycle.rs:6:5: 6:6
 +         let mut _5: ();                  // in scope 1 at $DIR/cycle.rs:6:5: 6:8
++         scope 2 (inlined <fn() {g} as Fn<()>>::call - shim(fn() {g})) { // at $DIR/cycle.rs:6:5: 6:8
++         }
 +     }
   
       bb0: {
@@ -27,10 +29,7 @@
 +         StorageLive(_4);                 // scope 1 at $DIR/cycle.rs:6:5: 6:6
 +         _4 = &_2;                        // scope 1 at $DIR/cycle.rs:6:5: 6:6
 +         StorageLive(_5);                 // scope 1 at $DIR/cycle.rs:6:5: 6:8
-+         _3 = <fn() {g} as Fn<()>>::call(move _4, move _5) -> [return: bb2, unwind: bb3]; // scope 1 at $DIR/cycle.rs:6:5: 6:8
-+                                          // mir::Constant
-+                                          // + span: $DIR/cycle.rs:6:5: 6:6
-+                                          // + literal: Const { ty: for<'a> extern "rust-call" fn(&'a fn() {g}, ()) -> <fn() {g} as FnOnce<()>>::Output {<fn() {g} as Fn<()>>::call}, val: Value(<ZST>) }
++         _3 = move (*_4)() -> [return: bb4, unwind: bb2]; // scope 2 at $SRC_DIR/core/src/ops/function.rs:LL:COL
       }
   
       bb1: {
@@ -40,19 +39,19 @@
           return;                          // scope 0 at $DIR/cycle.rs:+2:2: +2:2
 +     }
 + 
-+     bb2: {
-+         StorageDead(_5);                 // scope 1 at $DIR/cycle.rs:6:7: 6:8
-+         StorageDead(_4);                 // scope 1 at $DIR/cycle.rs:6:7: 6:8
-+         StorageDead(_3);                 // scope 1 at $DIR/cycle.rs:6:8: 6:9
-+         drop(_2) -> bb1;                 // scope 1 at $DIR/cycle.rs:7:1: 7:2
++     bb2 (cleanup): {
++         drop(_2) -> bb3;                 // scope 1 at $DIR/cycle.rs:7:1: 7:2
 +     }
 + 
 +     bb3 (cleanup): {
-+         drop(_2) -> bb4;                 // scope 1 at $DIR/cycle.rs:7:1: 7:2
++         resume;                          // scope 1 at $DIR/cycle.rs:5:1: 7:2
 +     }
 + 
-+     bb4 (cleanup): {
-+         resume;                          // scope 1 at $DIR/cycle.rs:5:1: 7:2
++     bb4: {
++         StorageDead(_5);                 // scope 1 at $DIR/cycle.rs:6:7: 6:8
++         StorageDead(_4);                 // scope 1 at $DIR/cycle.rs:6:7: 6:8
++         StorageDead(_3);                 // scope 1 at $DIR/cycle.rs:6:8: 6:9
++         drop(_2) -> bb1;                 // scope 1 at $DIR/cycle.rs:7:1: 7:2
       }
   }
   
diff --git a/src/test/mir-opt/inline/exponential_runtime.main.Inline.diff b/src/test/mir-opt/inline/exponential_runtime.main.Inline.diff
index d9fd7b324c7..7fd62be7ab9 100644
--- a/src/test/mir-opt/inline/exponential_runtime.main.Inline.diff
+++ b/src/test/mir-opt/inline/exponential_runtime.main.Inline.diff
@@ -8,43 +8,68 @@
 +         let _2: ();                      // in scope 1 at $DIR/exponential_runtime.rs:73:9: 73:25
 +         let _3: ();                      // in scope 1 at $DIR/exponential_runtime.rs:74:9: 74:25
 +         let _4: ();                      // in scope 1 at $DIR/exponential_runtime.rs:75:9: 75:25
++         scope 2 (inlined <() as F>::call) { // at $DIR/exponential_runtime.rs:73:9: 73:25
++             let _5: ();                  // in scope 2 at $DIR/exponential_runtime.rs:61:9: 61:25
++             let _6: ();                  // in scope 2 at $DIR/exponential_runtime.rs:62:9: 62:25
++             let _7: ();                  // in scope 2 at $DIR/exponential_runtime.rs:63:9: 63:25
++         }
 +     }
   
       bb0: {
           StorageLive(_1);                 // scope 0 at $DIR/exponential_runtime.rs:+1:5: +1:22
 -         _1 = <() as G>::call() -> bb1;   // scope 0 at $DIR/exponential_runtime.rs:+1:5: +1:22
 +         StorageLive(_2);                 // scope 1 at $DIR/exponential_runtime.rs:73:9: 73:25
-+         _2 = <() as F>::call() -> bb1;   // scope 1 at $DIR/exponential_runtime.rs:73:9: 73:25
++         StorageLive(_5);                 // scope 2 at $DIR/exponential_runtime.rs:61:9: 61:25
++         _5 = <() as E>::call() -> bb3;   // scope 2 at $DIR/exponential_runtime.rs:61:9: 61:25
                                            // mir::Constant
 -                                          // + span: $DIR/exponential_runtime.rs:86:5: 86:20
 -                                          // + literal: Const { ty: fn() {<() as G>::call}, val: Value(<ZST>) }
-+                                          // + span: $DIR/exponential_runtime.rs:73:9: 73:23
-+                                          // + literal: Const { ty: fn() {<() as F>::call}, val: Value(<ZST>) }
++                                          // + span: $DIR/exponential_runtime.rs:61:9: 61:23
++                                          // + literal: Const { ty: fn() {<() as E>::call}, val: Value(<ZST>) }
       }
   
       bb1: {
-+         StorageDead(_2);                 // scope 1 at $DIR/exponential_runtime.rs:73:25: 73:26
-+         StorageLive(_3);                 // scope 1 at $DIR/exponential_runtime.rs:74:9: 74:25
-+         _3 = <() as F>::call() -> bb2;   // scope 1 at $DIR/exponential_runtime.rs:74:9: 74:25
-+                                          // mir::Constant
-+                                          // + span: $DIR/exponential_runtime.rs:74:9: 74:23
-+                                          // + literal: Const { ty: fn() {<() as F>::call}, val: Value(<ZST>) }
-+     }
-+ 
-+     bb2: {
 +         StorageDead(_3);                 // scope 1 at $DIR/exponential_runtime.rs:74:25: 74:26
 +         StorageLive(_4);                 // scope 1 at $DIR/exponential_runtime.rs:75:9: 75:25
-+         _4 = <() as F>::call() -> bb3;   // scope 1 at $DIR/exponential_runtime.rs:75:9: 75:25
++         _4 = <() as F>::call() -> bb2;   // scope 1 at $DIR/exponential_runtime.rs:75:9: 75:25
 +                                          // mir::Constant
 +                                          // + span: $DIR/exponential_runtime.rs:75:9: 75:23
 +                                          // + literal: Const { ty: fn() {<() as F>::call}, val: Value(<ZST>) }
 +     }
 + 
-+     bb3: {
++     bb2: {
 +         StorageDead(_4);                 // scope 1 at $DIR/exponential_runtime.rs:75:25: 75:26
           StorageDead(_1);                 // scope 0 at $DIR/exponential_runtime.rs:+1:22: +1:23
           _0 = const ();                   // scope 0 at $DIR/exponential_runtime.rs:+0:11: +2:2
           return;                          // scope 0 at $DIR/exponential_runtime.rs:+2:2: +2:2
++     }
++ 
++     bb3: {
++         StorageDead(_5);                 // scope 2 at $DIR/exponential_runtime.rs:61:25: 61:26
++         StorageLive(_6);                 // scope 2 at $DIR/exponential_runtime.rs:62:9: 62:25
++         _6 = <() as E>::call() -> bb4;   // scope 2 at $DIR/exponential_runtime.rs:62:9: 62:25
++                                          // mir::Constant
++                                          // + span: $DIR/exponential_runtime.rs:62:9: 62:23
++                                          // + literal: Const { ty: fn() {<() as E>::call}, val: Value(<ZST>) }
++     }
++ 
++     bb4: {
++         StorageDead(_6);                 // scope 2 at $DIR/exponential_runtime.rs:62:25: 62:26
++         StorageLive(_7);                 // scope 2 at $DIR/exponential_runtime.rs:63:9: 63:25
++         _7 = <() as E>::call() -> bb5;   // scope 2 at $DIR/exponential_runtime.rs:63:9: 63:25
++                                          // mir::Constant
++                                          // + span: $DIR/exponential_runtime.rs:63:9: 63:23
++                                          // + literal: Const { ty: fn() {<() as E>::call}, val: Value(<ZST>) }
++     }
++ 
++     bb5: {
++         StorageDead(_7);                 // scope 2 at $DIR/exponential_runtime.rs:63:25: 63:26
++         StorageDead(_2);                 // scope 1 at $DIR/exponential_runtime.rs:73:25: 73:26
++         StorageLive(_3);                 // scope 1 at $DIR/exponential_runtime.rs:74:9: 74:25
++         _3 = <() as F>::call() -> bb1;   // scope 1 at $DIR/exponential_runtime.rs:74:9: 74:25
++                                          // mir::Constant
++                                          // + span: $DIR/exponential_runtime.rs:74:9: 74:23
++                                          // + literal: Const { ty: fn() {<() as F>::call}, val: Value(<ZST>) }
       }
   }
   
diff --git a/src/test/mir-opt/inline/inline_cycle.one.Inline.diff b/src/test/mir-opt/inline/inline_cycle.one.Inline.diff
index f54a1a747d4..5510cd7bc8c 100644
--- a/src/test/mir-opt/inline/inline_cycle.one.Inline.diff
+++ b/src/test/mir-opt/inline/inline_cycle.one.Inline.diff
@@ -5,17 +5,20 @@
       let mut _0: ();                      // return place in scope 0 at $DIR/inline_cycle.rs:+0:10: +0:10
       let _1: ();                          // in scope 0 at $DIR/inline_cycle.rs:+1:5: +1:24
 +     scope 1 (inlined <C as Call>::call) { // at $DIR/inline_cycle.rs:14:5: 14:24
++         scope 2 (inlined <A<C> as Call>::call) { // at $DIR/inline_cycle.rs:43:9: 43:23
++             scope 3 (inlined <B<C> as Call>::call) { // at $DIR/inline_cycle.rs:28:9: 28:31
++             }
++         }
 +     }
   
       bb0: {
           StorageLive(_1);                 // scope 0 at $DIR/inline_cycle.rs:+1:5: +1:24
 -         _1 = <C as Call>::call() -> bb1; // scope 0 at $DIR/inline_cycle.rs:+1:5: +1:24
-+         _1 = <A<C> as Call>::call() -> bb1; // scope 1 at $DIR/inline_cycle.rs:43:9: 43:23
++         _1 = <C as Call>::call() -> bb1; // scope 3 at $DIR/inline_cycle.rs:36:9: 36:28
                                            // mir::Constant
 -                                          // + span: $DIR/inline_cycle.rs:14:5: 14:22
--                                          // + literal: Const { ty: fn() {<C as Call>::call}, val: Value(<ZST>) }
-+                                          // + span: $DIR/inline_cycle.rs:43:9: 43:21
-+                                          // + literal: Const { ty: fn() {<A<C> as Call>::call}, val: Value(<ZST>) }
++                                          // + span: $DIR/inline_cycle.rs:36:9: 36:26
+                                           // + literal: Const { ty: fn() {<C as Call>::call}, val: Value(<ZST>) }
       }
   
       bb1: {
diff --git a/src/test/mir-opt/inline/inline_cycle.two.Inline.diff b/src/test/mir-opt/inline/inline_cycle.two.Inline.diff
index a940848c269..64c0065b543 100644
--- a/src/test/mir-opt/inline/inline_cycle.two.Inline.diff
+++ b/src/test/mir-opt/inline/inline_cycle.two.Inline.diff
@@ -9,6 +9,8 @@
 +         debug f => _2;                   // in scope 1 at $DIR/inline_cycle.rs:53:22: 53:23
 +         let _3: ();                      // in scope 1 at $DIR/inline_cycle.rs:54:5: 54:8
 +         let mut _4: ();                  // in scope 1 at $DIR/inline_cycle.rs:54:5: 54:8
++         scope 2 (inlined <fn() {f} as FnOnce<()>>::call_once - shim(fn() {f})) { // at $DIR/inline_cycle.rs:54:5: 54:8
++         }
 +     }
   
       bb0: {
@@ -24,10 +26,7 @@
                                            // + literal: Const { ty: fn() {f}, val: Value(<ZST>) }
 +         StorageLive(_3);                 // scope 1 at $DIR/inline_cycle.rs:54:5: 54:8
 +         StorageLive(_4);                 // scope 1 at $DIR/inline_cycle.rs:54:5: 54:8
-+         _3 = <fn() {f} as FnOnce<()>>::call_once(move _2, move _4) -> bb1; // scope 1 at $DIR/inline_cycle.rs:54:5: 54:8
-+                                          // mir::Constant
-+                                          // + span: $DIR/inline_cycle.rs:54:5: 54:6
-+                                          // + literal: Const { ty: extern "rust-call" fn(fn() {f}, ()) -> <fn() {f} as FnOnce<()>>::Output {<fn() {f} as FnOnce<()>>::call_once}, val: Value(<ZST>) }
++         _3 = move _2() -> bb1;           // scope 2 at $SRC_DIR/core/src/ops/function.rs:LL:COL
       }
   
       bb1: {
diff --git a/src/test/mir-opt/inline/inline_cycle_generic.main.Inline.diff b/src/test/mir-opt/inline/inline_cycle_generic.main.Inline.diff
index 04de3e61e5f..52debab4dd1 100644
--- a/src/test/mir-opt/inline/inline_cycle_generic.main.Inline.diff
+++ b/src/test/mir-opt/inline/inline_cycle_generic.main.Inline.diff
@@ -6,18 +6,21 @@
       let _1: ();                          // in scope 0 at $DIR/inline_cycle_generic.rs:+1:5: +1:24
 +     scope 1 (inlined <C as Call>::call) { // at $DIR/inline_cycle_generic.rs:9:5: 9:24
 +         scope 2 (inlined <B<A> as Call>::call) { // at $DIR/inline_cycle_generic.rs:38:9: 38:31
++             scope 3 (inlined <A as Call>::call) { // at $DIR/inline_cycle_generic.rs:31:9: 31:28
++                 scope 4 (inlined <B<C> as Call>::call) { // at $DIR/inline_cycle_generic.rs:23:9: 23:31
++                 }
++             }
 +         }
 +     }
   
       bb0: {
           StorageLive(_1);                 // scope 0 at $DIR/inline_cycle_generic.rs:+1:5: +1:24
 -         _1 = <C as Call>::call() -> bb1; // scope 0 at $DIR/inline_cycle_generic.rs:+1:5: +1:24
-+         _1 = <A as Call>::call() -> bb1; // scope 2 at $DIR/inline_cycle_generic.rs:31:9: 31:28
++         _1 = <C as Call>::call() -> bb1; // scope 4 at $DIR/inline_cycle_generic.rs:31:9: 31:28
                                            // mir::Constant
 -                                          // + span: $DIR/inline_cycle_generic.rs:9:5: 9:22
--                                          // + literal: Const { ty: fn() {<C as Call>::call}, val: Value(<ZST>) }
 +                                          // + span: $DIR/inline_cycle_generic.rs:31:9: 31:26
-+                                          // + literal: Const { ty: fn() {<A as Call>::call}, val: Value(<ZST>) }
+                                           // + literal: Const { ty: fn() {<C as Call>::call}, val: Value(<ZST>) }
       }
   
       bb1: {
diff --git a/src/test/mir-opt/inline/inline_diverging.h.Inline.diff b/src/test/mir-opt/inline/inline_diverging.h.Inline.diff
index a01bcf1645b..f82fcf4c821 100644
--- a/src/test/mir-opt/inline/inline_diverging.h.Inline.diff
+++ b/src/test/mir-opt/inline/inline_diverging.h.Inline.diff
@@ -20,6 +20,8 @@
 +                 debug b => _9;           // in scope 3 at $DIR/inline_diverging.rs:28:9: 28:10
 +             }
 +         }
++         scope 4 (inlined <fn() -> ! {sleep} as Fn<()>>::call - shim(fn() -> ! {sleep})) { // at $DIR/inline_diverging.rs:27:13: 27:16
++         }
 +     }
   
       bb0: {
@@ -38,25 +40,10 @@
 +         StorageLive(_4);                 // scope 1 at $DIR/inline_diverging.rs:27:13: 27:14
 +         _4 = &_2;                        // scope 1 at $DIR/inline_diverging.rs:27:13: 27:14
 +         StorageLive(_5);                 // scope 1 at $DIR/inline_diverging.rs:27:13: 27:16
-+         _3 = <fn() -> ! {sleep} as Fn<()>>::call(move _4, move _5) -> [return: bb1, unwind: bb5]; // scope 1 at $DIR/inline_diverging.rs:27:13: 27:16
-+                                          // mir::Constant
-+                                          // + span: $DIR/inline_diverging.rs:27:13: 27:14
-+                                          // + literal: Const { ty: for<'a> extern "rust-call" fn(&'a fn() -> ! {sleep}, ()) -> <fn() -> ! {sleep} as FnOnce<()>>::Output {<fn() -> ! {sleep} as Fn<()>>::call}, val: Value(<ZST>) }
++         _3 = move (*_4)() -> [return: bb6, unwind: bb4]; // scope 4 at $SRC_DIR/core/src/ops/function.rs:LL:COL
 +     }
 + 
 +     bb1: {
-+         StorageDead(_5);                 // scope 1 at $DIR/inline_diverging.rs:27:15: 27:16
-+         StorageDead(_4);                 // scope 1 at $DIR/inline_diverging.rs:27:15: 27:16
-+         StorageLive(_6);                 // scope 2 at $DIR/inline_diverging.rs:28:13: 28:14
-+         _6 = &_2;                        // scope 2 at $DIR/inline_diverging.rs:28:13: 28:14
-+         StorageLive(_7);                 // scope 2 at $DIR/inline_diverging.rs:28:13: 28:16
-+         _9 = <fn() -> ! {sleep} as Fn<()>>::call(move _6, move _7) -> [return: bb2, unwind: bb4]; // scope 2 at $DIR/inline_diverging.rs:28:13: 28:16
-+                                          // mir::Constant
-+                                          // + span: $DIR/inline_diverging.rs:28:13: 28:14
-+                                          // + literal: Const { ty: for<'a> extern "rust-call" fn(&'a fn() -> ! {sleep}, ()) -> <fn() -> ! {sleep} as FnOnce<()>>::Output {<fn() -> ! {sleep} as Fn<()>>::call}, val: Value(<ZST>) }
-+     }
-+ 
-+     bb2: {
 +         StorageDead(_7);                 // scope 2 at $DIR/inline_diverging.rs:28:15: 28:16
 +         StorageDead(_6);                 // scope 2 at $DIR/inline_diverging.rs:28:15: 28:16
 +         StorageLive(_8);                 // scope 3 at $DIR/inline_diverging.rs:29:6: 29:7
@@ -66,23 +53,35 @@
 +         (_1.1: !) = move _9;             // scope 3 at $DIR/inline_diverging.rs:29:5: 29:11
 +         StorageDead(_8);                 // scope 3 at $DIR/inline_diverging.rs:29:10: 29:11
 +         StorageDead(_3);                 // scope 1 at $DIR/inline_diverging.rs:30:1: 30:2
-+         drop(_2) -> bb3;                 // scope 1 at $DIR/inline_diverging.rs:30:1: 30:2
++         drop(_2) -> bb2;                 // scope 1 at $DIR/inline_diverging.rs:30:1: 30:2
 +     }
 + 
-+     bb3: {
++     bb2: {
 +         unreachable;                     // scope 0 at $DIR/inline_diverging.rs:30:2: 30:2
 +     }
 + 
++     bb3 (cleanup): {
++         drop(_3) -> bb4;                 // scope 1 at $DIR/inline_diverging.rs:30:1: 30:2
++     }
++ 
 +     bb4 (cleanup): {
-+         drop(_3) -> bb5;                 // scope 1 at $DIR/inline_diverging.rs:30:1: 30:2
++         drop(_2) -> bb5;                 // scope 1 at $DIR/inline_diverging.rs:30:1: 30:2
 +     }
 + 
 +     bb5 (cleanup): {
-+         drop(_2) -> bb6;                 // scope 1 at $DIR/inline_diverging.rs:30:1: 30:2
++         resume;                          // scope 1 at $DIR/inline_diverging.rs:26:1: 30:2
 +     }
 + 
-+     bb6 (cleanup): {
-+         resume;                          // scope 1 at $DIR/inline_diverging.rs:26:1: 30:2
++     bb6: {
++         StorageDead(_5);                 // scope 1 at $DIR/inline_diverging.rs:27:15: 27:16
++         StorageDead(_4);                 // scope 1 at $DIR/inline_diverging.rs:27:15: 27:16
++         StorageLive(_6);                 // scope 2 at $DIR/inline_diverging.rs:28:13: 28:14
++         _6 = &_2;                        // scope 2 at $DIR/inline_diverging.rs:28:13: 28:14
++         StorageLive(_7);                 // scope 2 at $DIR/inline_diverging.rs:28:13: 28:16
++         _9 = <fn() -> ! {sleep} as Fn<()>>::call(move _6, move _7) -> [return: bb1, unwind: bb3]; // scope 2 at $DIR/inline_diverging.rs:28:13: 28:16
++                                          // mir::Constant
++                                          // + span: $DIR/inline_diverging.rs:28:13: 28:14
++                                          // + literal: Const { ty: for<'a> extern "rust-call" fn(&'a fn() -> ! {sleep}, ()) -> <fn() -> ! {sleep} as FnOnce<()>>::Output {<fn() -> ! {sleep} as Fn<()>>::call}, val: Value(<ZST>) }
       }
   }
   
diff --git a/src/test/mir-opt/separate_const_switch.identity.SeparateConstSwitch.diff b/src/test/mir-opt/separate_const_switch.identity.SeparateConstSwitch.diff
index 6ae16bdb5b8..e57544e09e2 100644
--- a/src/test/mir-opt/separate_const_switch.identity.SeparateConstSwitch.diff
+++ b/src/test/mir-opt/separate_const_switch.identity.SeparateConstSwitch.diff
@@ -22,6 +22,9 @@
                   let mut _18: i32;        // in scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
                   scope 9 {
                       debug e => _16;      // in scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
+                      scope 10 (inlined <i32 as From<i32>>::from) { // at $SRC_DIR/core/src/result.rs:LL:COL
+                          debug t => _18;  // in scope 10 at $SRC_DIR/core/src/convert/mod.rs:LL:COL
+                      }
                   }
               }
           }
@@ -92,11 +95,18 @@
           StorageLive(_17);                // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
           StorageLive(_18);                // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
           _18 = move _16;                  // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
--         _17 = <i32 as From<i32>>::from(move _18) -> bb8; // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
-+         _17 = <i32 as From<i32>>::from(move _18) -> bb7; // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
-                                           // mir::Constant
-                                           // + span: $SRC_DIR/core/src/result.rs:LL:COL
-                                           // + literal: Const { ty: fn(i32) -> i32 {<i32 as From<i32>>::from}, val: Value(<ZST>) }
+          _17 = move _18;                  // scope 10 at $SRC_DIR/core/src/convert/mod.rs:LL:COL
+          StorageDead(_18);                // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
+          Deinit(_0);                      // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
+          ((_0 as Err).0: i32) = move _17; // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
+          discriminant(_0) = 1;            // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
+          StorageDead(_17);                // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
+          StorageDead(_16);                // scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
+          StorageDead(_8);                 // scope 2 at $DIR/separate_const_switch.rs:+1:9: +1:10
+          StorageDead(_6);                 // scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10
+          StorageDead(_2);                 // scope 0 at $DIR/separate_const_switch.rs:+1:10: +1:11
+          StorageDead(_3);                 // scope 0 at $DIR/separate_const_switch.rs:+2:1: +2:2
+          return;                          // scope 0 at $DIR/separate_const_switch.rs:+2:2: +2:2
       }
   
 -     bb5: {
@@ -142,20 +152,5 @@
 +         _5 = discriminant(_3);           // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
 +         switchInt(move _5) -> [0: bb1, 1: bb3, otherwise: bb2]; // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
       }
-  
--     bb8: {
-+     bb7: {
-          StorageDead(_18);                // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
-          Deinit(_0);                      // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
-          ((_0 as Err).0: i32) = move _17; // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
-          discriminant(_0) = 1;            // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
-          StorageDead(_17);                // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
-          StorageDead(_16);                // scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
-          StorageDead(_8);                 // scope 2 at $DIR/separate_const_switch.rs:+1:9: +1:10
-          StorageDead(_6);                 // scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10
-          StorageDead(_2);                 // scope 0 at $DIR/separate_const_switch.rs:+1:10: +1:11
-          StorageDead(_3);                 // scope 0 at $DIR/separate_const_switch.rs:+2:1: +2:2
-          return;                          // scope 0 at $DIR/separate_const_switch.rs:+2:2: +2:2
-      }
   }
   
diff --git a/src/test/mir-opt/simple_option_map_e2e.ezmap.PreCodegen.after.mir b/src/test/mir-opt/simple_option_map_e2e.ezmap.PreCodegen.after.mir
new file mode 100644
index 00000000000..916f99049c6
--- /dev/null
+++ b/src/test/mir-opt/simple_option_map_e2e.ezmap.PreCodegen.after.mir
@@ -0,0 +1,52 @@
+// MIR for `ezmap` after PreCodegen
+
+fn ezmap(_1: Option<i32>) -> Option<i32> {
+    debug x => _1;                       // in scope 0 at $DIR/simple_option_map_e2e.rs:+0:14: +0:15
+    let mut _0: std::option::Option<i32>; // return place in scope 0 at $DIR/simple_option_map_e2e.rs:+0:33: +0:44
+    let mut _2: [closure@$DIR/simple_option_map_e2e.rs:14:12: 14:15]; // in scope 0 at $DIR/simple_option_map_e2e.rs:+1:12: +1:21
+    scope 1 (inlined map::<i32, i32, [closure@$DIR/simple_option_map_e2e.rs:14:12: 14:15]>) { // at $DIR/simple_option_map_e2e.rs:14:5: 14:22
+        debug slf => _1;                 // in scope 1 at $DIR/simple_option_map_e2e.rs:2:17: 2:20
+        debug f => _2;                   // in scope 1 at $DIR/simple_option_map_e2e.rs:2:33: 2:34
+        let mut _3: isize;               // in scope 1 at $DIR/simple_option_map_e2e.rs:7:9: 7:16
+        let mut _4: i32;                 // in scope 1 at $DIR/simple_option_map_e2e.rs:7:25: 7:29
+        let mut _5: i32;                 // in scope 1 at $DIR/simple_option_map_e2e.rs:7:25: 7:29
+        scope 2 {
+            debug x => _5;               // in scope 2 at $DIR/simple_option_map_e2e.rs:7:14: 7:15
+            scope 3 (inlined ezmap::{closure#0}) { // at $DIR/simple_option_map_e2e.rs:7:25: 7:29
+                debug n => _5;           // in scope 3 at $DIR/simple_option_map_e2e.rs:+1:13: +1:14
+            }
+        }
+    }
+
+    bb0: {
+        StorageLive(_2);                 // scope 0 at $DIR/simple_option_map_e2e.rs:+1:12: +1:21
+        _3 = discriminant(_1);           // scope 1 at $DIR/simple_option_map_e2e.rs:6:11: 6:14
+        switchInt(move _3) -> [0: bb1, 1: bb3, otherwise: bb2]; // scope 1 at $DIR/simple_option_map_e2e.rs:6:5: 6:14
+    }
+
+    bb1: {
+        Deinit(_0);                      // scope 1 at $DIR/simple_option_map_e2e.rs:8:17: 8:21
+        discriminant(_0) = 0;            // scope 1 at $DIR/simple_option_map_e2e.rs:8:17: 8:21
+        goto -> bb4;                     // scope 1 at $DIR/simple_option_map_e2e.rs:8:17: 8:21
+    }
+
+    bb2: {
+        unreachable;                     // scope 1 at $DIR/simple_option_map_e2e.rs:6:11: 6:14
+    }
+
+    bb3: {
+        _5 = move ((_1 as Some).0: i32); // scope 1 at $DIR/simple_option_map_e2e.rs:7:14: 7:15
+        StorageLive(_4);                 // scope 2 at $DIR/simple_option_map_e2e.rs:7:25: 7:29
+        _4 = Add(move _5, const 1_i32);  // scope 3 at $DIR/simple_option_map_e2e.rs:+1:16: +1:21
+        Deinit(_0);                      // scope 2 at $DIR/simple_option_map_e2e.rs:7:20: 7:30
+        ((_0 as Some).0: i32) = move _4; // scope 2 at $DIR/simple_option_map_e2e.rs:7:20: 7:30
+        discriminant(_0) = 1;            // scope 2 at $DIR/simple_option_map_e2e.rs:7:20: 7:30
+        StorageDead(_4);                 // scope 2 at $DIR/simple_option_map_e2e.rs:7:29: 7:30
+        goto -> bb4;                     // scope 1 at $DIR/simple_option_map_e2e.rs:10:1: 10:2
+    }
+
+    bb4: {
+        StorageDead(_2);                 // scope 0 at $DIR/simple_option_map_e2e.rs:+1:21: +1:22
+        return;                          // scope 0 at $DIR/simple_option_map_e2e.rs:+2:2: +2:2
+    }
+}
diff --git a/src/test/mir-opt/simple_option_map_e2e.rs b/src/test/mir-opt/simple_option_map_e2e.rs
new file mode 100644
index 00000000000..2acd2a227b8
--- /dev/null
+++ b/src/test/mir-opt/simple_option_map_e2e.rs
@@ -0,0 +1,19 @@
+#[inline(always)]
+fn map<T, U, F>(slf: Option<T>, f: F) -> Option<U>
+where
+    F: FnOnce(T) -> U,
+{
+    match slf {
+        Some(x) => Some(f(x)),
+        None => None,
+    }
+}
+
+// EMIT_MIR simple_option_map_e2e.ezmap.PreCodegen.after.mir
+pub fn ezmap(x: Option<i32>) -> Option<i32> {
+    map(x, |n| n + 1)
+}
+
+fn main() {
+    assert_eq!(None, ezmap(None));
+}
diff --git a/src/test/run-make-fulldeps/save-analysis/foo.rs b/src/test/run-make-fulldeps/save-analysis/foo.rs
index 74aaabfbf1b..384589de3b4 100644
--- a/src/test/run-make-fulldeps/save-analysis/foo.rs
+++ b/src/test/run-make-fulldeps/save-analysis/foo.rs
@@ -5,6 +5,11 @@
 extern crate rustc_graphviz;
 // A simple rust project
 
+// Necessary to pull in object code as the rest of the rustc crates are shipped only as rmeta
+// files.
+#[allow(unused_extern_crates)]
+extern crate rustc_driver;
+
 extern crate krate2;
 extern crate krate2 as krate3;
 
diff --git a/src/test/rustdoc-json/enums/discriminant/basic.rs b/src/test/rustdoc-json/enums/discriminant/basic.rs
index 8c221615aa7..06906df3b2c 100644
--- a/src/test/rustdoc-json/enums/discriminant/basic.rs
+++ b/src/test/rustdoc-json/enums/discriminant/basic.rs
@@ -1,12 +1,12 @@
 #[repr(i8)]
 pub enum Ordering {
-    // @is "$.index[*][?(@.name=='Less')].inner.variant_inner.expr" '"-1"'
-    // @is "$.index[*][?(@.name=='Less')].inner.variant_inner.value" '"-1"'
+    // @is "$.index[*][?(@.name=='Less')].inner.discriminant.expr" '"-1"'
+    // @is "$.index[*][?(@.name=='Less')].inner.discriminant.value" '"-1"'
     Less = -1,
-    // @is "$.index[*][?(@.name=='Equal')].inner.variant_inner.expr" '"0"'
-    // @is "$.index[*][?(@.name=='Equal')].inner.variant_inner.value" '"0"'
+    // @is "$.index[*][?(@.name=='Equal')].inner.discriminant.expr" '"0"'
+    // @is "$.index[*][?(@.name=='Equal')].inner.discriminant.value" '"0"'
     Equal = 0,
-    // @is "$.index[*][?(@.name=='Greater')].inner.variant_inner.expr" '"1"'
-    // @is "$.index[*][?(@.name=='Greater')].inner.variant_inner.value" '"1"'
+    // @is "$.index[*][?(@.name=='Greater')].inner.discriminant.expr" '"1"'
+    // @is "$.index[*][?(@.name=='Greater')].inner.discriminant.value" '"1"'
     Greater = 1,
 }
diff --git a/src/test/rustdoc-json/enums/discriminant/expr.rs b/src/test/rustdoc-json/enums/discriminant/expr.rs
index 235b0b47381..e639965e79b 100644
--- a/src/test/rustdoc-json/enums/discriminant/expr.rs
+++ b/src/test/rustdoc-json/enums/discriminant/expr.rs
@@ -1,30 +1,30 @@
 pub enum Foo {
-    // @is "$.index[*][?(@.name=='Addition')].inner.variant_inner.value" '"0"'
-    // @is "$.index[*][?(@.name=='Addition')].inner.variant_inner.expr" '"{ _ }"'
+    // @is "$.index[*][?(@.name=='Addition')].inner.discriminant.value" '"0"'
+    // @is "$.index[*][?(@.name=='Addition')].inner.discriminant.expr" '"{ _ }"'
     Addition = 0 + 0,
-    // @is "$.index[*][?(@.name=='Bin')].inner.variant_inner.value" '"1"'
-    // @is "$.index[*][?(@.name=='Bin')].inner.variant_inner.expr" '"0b1"'
+    // @is "$.index[*][?(@.name=='Bin')].inner.discriminant.value" '"1"'
+    // @is "$.index[*][?(@.name=='Bin')].inner.discriminant.expr" '"0b1"'
     Bin = 0b1,
-    // @is "$.index[*][?(@.name=='Oct')].inner.variant_inner.value" '"2"'
-    // @is "$.index[*][?(@.name=='Oct')].inner.variant_inner.expr" '"0o2"'
+    // @is "$.index[*][?(@.name=='Oct')].inner.discriminant.value" '"2"'
+    // @is "$.index[*][?(@.name=='Oct')].inner.discriminant.expr" '"0o2"'
     Oct = 0o2,
-    // @is "$.index[*][?(@.name=='PubConst')].inner.variant_inner.value" '"3"'
-    // @is "$.index[*][?(@.name=='PubConst')].inner.variant_inner.expr" '"THREE"'
+    // @is "$.index[*][?(@.name=='PubConst')].inner.discriminant.value" '"3"'
+    // @is "$.index[*][?(@.name=='PubConst')].inner.discriminant.expr" '"THREE"'
     PubConst = THREE,
-    // @is "$.index[*][?(@.name=='Hex')].inner.variant_inner.value" '"4"'
-    // @is "$.index[*][?(@.name=='Hex')].inner.variant_inner.expr" '"0x4"'
+    // @is "$.index[*][?(@.name=='Hex')].inner.discriminant.value" '"4"'
+    // @is "$.index[*][?(@.name=='Hex')].inner.discriminant.expr" '"0x4"'
     Hex = 0x4,
-    // @is "$.index[*][?(@.name=='Cast')].inner.variant_inner.value" '"5"'
-    // @is "$.index[*][?(@.name=='Cast')].inner.variant_inner.expr" '"{ _ }"'
+    // @is "$.index[*][?(@.name=='Cast')].inner.discriminant.value" '"5"'
+    // @is "$.index[*][?(@.name=='Cast')].inner.discriminant.expr" '"{ _ }"'
     Cast = 5 as isize,
-    // @is "$.index[*][?(@.name=='PubCall')].inner.variant_inner.value" '"6"'
-    // @is "$.index[*][?(@.name=='PubCall')].inner.variant_inner.expr" '"{ _ }"'
+    // @is "$.index[*][?(@.name=='PubCall')].inner.discriminant.value" '"6"'
+    // @is "$.index[*][?(@.name=='PubCall')].inner.discriminant.expr" '"{ _ }"'
     PubCall = six(),
-    // @is "$.index[*][?(@.name=='PrivCall')].inner.variant_inner.value" '"7"'
-    // @is "$.index[*][?(@.name=='PrivCall')].inner.variant_inner.expr" '"{ _ }"'
+    // @is "$.index[*][?(@.name=='PrivCall')].inner.discriminant.value" '"7"'
+    // @is "$.index[*][?(@.name=='PrivCall')].inner.discriminant.expr" '"{ _ }"'
     PrivCall = seven(),
-    // @is "$.index[*][?(@.name=='PrivConst')].inner.variant_inner.value" '"8"'
-    // @is "$.index[*][?(@.name=='PrivConst')].inner.variant_inner.expr" '"EIGHT"'
+    // @is "$.index[*][?(@.name=='PrivConst')].inner.discriminant.value" '"8"'
+    // @is "$.index[*][?(@.name=='PrivConst')].inner.discriminant.expr" '"EIGHT"'
     PrivConst = EIGHT,
 }
 
diff --git a/src/test/rustdoc-json/enums/discriminant/limits.rs b/src/test/rustdoc-json/enums/discriminant/limits.rs
index 8df73d78d23..e56d5594f2f 100644
--- a/src/test/rustdoc-json/enums/discriminant/limits.rs
+++ b/src/test/rustdoc-json/enums/discriminant/limits.rs
@@ -4,40 +4,40 @@
 
 #[repr(u64)]
 pub enum U64 {
-    // @is "$.index[*][?(@.name=='U64Min')].inner.variant_inner.value" '"0"'
-    // @is "$.index[*][?(@.name=='U64Min')].inner.variant_inner.expr" '"u64::MIN"'
+    // @is "$.index[*][?(@.name=='U64Min')].inner.discriminant.value" '"0"'
+    // @is "$.index[*][?(@.name=='U64Min')].inner.discriminant.expr" '"u64::MIN"'
     U64Min = u64::MIN,
-    // @is "$.index[*][?(@.name=='U64Max')].inner.variant_inner.value" '"18446744073709551615"'
-    // @is "$.index[*][?(@.name=='U64Max')].inner.variant_inner.expr" '"u64::MAX"'
+    // @is "$.index[*][?(@.name=='U64Max')].inner.discriminant.value" '"18446744073709551615"'
+    // @is "$.index[*][?(@.name=='U64Max')].inner.discriminant.expr" '"u64::MAX"'
     U64Max = u64::MAX,
 }
 
 #[repr(i64)]
 pub enum I64 {
-    // @is "$.index[*][?(@.name=='I64Min')].inner.variant_inner.value" '"-9223372036854775808"'
-    // @is "$.index[*][?(@.name=='I64Min')].inner.variant_inner.expr" '"i64::MIN"'
+    // @is "$.index[*][?(@.name=='I64Min')].inner.discriminant.value" '"-9223372036854775808"'
+    // @is "$.index[*][?(@.name=='I64Min')].inner.discriminant.expr" '"i64::MIN"'
     I64Min = i64::MIN,
-    // @is "$.index[*][?(@.name=='I64Max')].inner.variant_inner.value" '"9223372036854775807"'
-    // @is "$.index[*][?(@.name=='I64Max')].inner.variant_inner.expr" '"i64::MAX"'
+    // @is "$.index[*][?(@.name=='I64Max')].inner.discriminant.value" '"9223372036854775807"'
+    // @is "$.index[*][?(@.name=='I64Max')].inner.discriminant.expr" '"i64::MAX"'
     I64Max = i64::MAX,
 }
 
 #[repr(u128)]
 pub enum U128 {
-    // @is "$.index[*][?(@.name=='U128Min')].inner.variant_inner.value" '"0"'
-    // @is "$.index[*][?(@.name=='U128Min')].inner.variant_inner.expr" '"u128::MIN"'
+    // @is "$.index[*][?(@.name=='U128Min')].inner.discriminant.value" '"0"'
+    // @is "$.index[*][?(@.name=='U128Min')].inner.discriminant.expr" '"u128::MIN"'
     U128Min = u128::MIN,
-    // @is "$.index[*][?(@.name=='U128Max')].inner.variant_inner.value" '"340282366920938463463374607431768211455"'
-    // @is "$.index[*][?(@.name=='U128Max')].inner.variant_inner.expr" '"u128::MAX"'
+    // @is "$.index[*][?(@.name=='U128Max')].inner.discriminant.value" '"340282366920938463463374607431768211455"'
+    // @is "$.index[*][?(@.name=='U128Max')].inner.discriminant.expr" '"u128::MAX"'
     U128Max = u128::MAX,
 }
 
 #[repr(i128)]
 pub enum I128 {
-    // @is "$.index[*][?(@.name=='I128Min')].inner.variant_inner.value" '"-170141183460469231731687303715884105728"'
-    // @is "$.index[*][?(@.name=='I128Min')].inner.variant_inner.expr" '"i128::MIN"'
+    // @is "$.index[*][?(@.name=='I128Min')].inner.discriminant.value" '"-170141183460469231731687303715884105728"'
+    // @is "$.index[*][?(@.name=='I128Min')].inner.discriminant.expr" '"i128::MIN"'
     I128Min = i128::MIN,
-    // @is "$.index[*][?(@.name=='I128Max')].inner.variant_inner.value" '"170141183460469231731687303715884105727"'
-    // @is "$.index[*][?(@.name=='I128Max')].inner.variant_inner.expr" '"i128::MAX"'
+    // @is "$.index[*][?(@.name=='I128Max')].inner.discriminant.value" '"170141183460469231731687303715884105727"'
+    // @is "$.index[*][?(@.name=='I128Max')].inner.discriminant.expr" '"i128::MAX"'
     I128Max = i128::MAX,
 }
diff --git a/src/test/rustdoc-json/enums/discriminant/num_underscore_and_suffix.rs b/src/test/rustdoc-json/enums/discriminant/num_underscore_and_suffix.rs
index 3417baa0760..6889b305ffb 100644
--- a/src/test/rustdoc-json/enums/discriminant/num_underscore_and_suffix.rs
+++ b/src/test/rustdoc-json/enums/discriminant/num_underscore_and_suffix.rs
@@ -1,15 +1,15 @@
 #[repr(u32)]
 pub enum Foo {
-    // @is "$.index[*][?(@.name=='Basic')].inner.variant_inner.value" '"0"'
-    // @is "$.index[*][?(@.name=='Basic')].inner.variant_inner.expr" '"0"'
+    // @is "$.index[*][?(@.name=='Basic')].inner.discriminant.value" '"0"'
+    // @is "$.index[*][?(@.name=='Basic')].inner.discriminant.expr" '"0"'
     Basic = 0,
-    // @is "$.index[*][?(@.name=='Suffix')].inner.variant_inner.value" '"10"'
-    // @is "$.index[*][?(@.name=='Suffix')].inner.variant_inner.expr" '"10u32"'
+    // @is "$.index[*][?(@.name=='Suffix')].inner.discriminant.value" '"10"'
+    // @is "$.index[*][?(@.name=='Suffix')].inner.discriminant.expr" '"10u32"'
     Suffix = 10u32,
-    // @is "$.index[*][?(@.name=='Underscore')].inner.variant_inner.value" '"100"'
-    // @is "$.index[*][?(@.name=='Underscore')].inner.variant_inner.expr" '"1_0_0"'
+    // @is "$.index[*][?(@.name=='Underscore')].inner.discriminant.value" '"100"'
+    // @is "$.index[*][?(@.name=='Underscore')].inner.discriminant.expr" '"1_0_0"'
     Underscore = 1_0_0,
-    // @is "$.index[*][?(@.name=='SuffixUnderscore')].inner.variant_inner.value" '"1000"'
-    // @is "$.index[*][?(@.name=='SuffixUnderscore')].inner.variant_inner.expr" '"1_0_0_0u32"'
+    // @is "$.index[*][?(@.name=='SuffixUnderscore')].inner.discriminant.value" '"1000"'
+    // @is "$.index[*][?(@.name=='SuffixUnderscore')].inner.discriminant.expr" '"1_0_0_0u32"'
     SuffixUnderscore = 1_0_0_0u32,
 }
diff --git a/src/test/rustdoc-json/enums/discriminant/only_some_have_discriminant.rs b/src/test/rustdoc-json/enums/discriminant/only_some_have_discriminant.rs
index 6af944a2219..6a4f54de617 100644
--- a/src/test/rustdoc-json/enums/discriminant/only_some_have_discriminant.rs
+++ b/src/test/rustdoc-json/enums/discriminant/only_some_have_discriminant.rs
@@ -1,10 +1,10 @@
 pub enum Foo {
-    // @is "$.index[*][?(@.name=='Has')].inner.variant_inner" '{"expr":"0", "value":"0"}'
+    // @is "$.index[*][?(@.name=='Has')].inner.discriminant" '{"expr":"0", "value":"0"}'
     Has = 0,
-    // @is "$.index[*][?(@.name=='Doesnt')].inner.variant_inner" null
+    // @is "$.index[*][?(@.name=='Doesnt')].inner.discriminant" null
     Doesnt,
-    // @is "$.index[*][?(@.name=='AlsoDoesnt')].inner.variant_inner" null
+    // @is "$.index[*][?(@.name=='AlsoDoesnt')].inner.discriminant" null
     AlsoDoesnt,
-    // @is "$.index[*][?(@.name=='AlsoHas')].inner.variant_inner" '{"expr":"44", "value":"44"}'
+    // @is "$.index[*][?(@.name=='AlsoHas')].inner.discriminant" '{"expr":"44", "value":"44"}'
     AlsoHas = 44,
 }
diff --git a/src/test/rustdoc-json/enums/discriminant/struct.rs b/src/test/rustdoc-json/enums/discriminant/struct.rs
new file mode 100644
index 00000000000..e91a632a3b3
--- /dev/null
+++ b/src/test/rustdoc-json/enums/discriminant/struct.rs
@@ -0,0 +1,15 @@
+// ignore-tidy-linelength
+
+#[repr(i32)]
+// @is "$.index[*][?(@.name=='Foo')].attrs" '["#[repr(i32)]"]'
+pub enum Foo {
+    // @is    "$.index[*][?(@.name=='Struct')].inner.discriminant" null
+    // @count "$.index[*][?(@.name=='Struct')].inner.kind.struct.fields[*]" 0
+    Struct {},
+    // @is    "$.index[*][?(@.name=='StructWithDiscr')].inner.discriminant" '{"expr": "42", "value": "42"}'
+    // @count "$.index[*][?(@.name=='StructWithDiscr')].inner.kind.struct.fields[*]" 1
+    StructWithDiscr { x: i32 } = 42,
+    // @is    "$.index[*][?(@.name=='StructWithHexDiscr')].inner.discriminant"  '{"expr": "0x42", "value": "66"}'
+    // @count "$.index[*][?(@.name=='StructWithHexDiscr')].inner.kind.struct.fields[*]" 2
+    StructWithHexDiscr { x: i32, y: bool } = 0x42,
+}
diff --git a/src/test/rustdoc-json/enums/discriminant/tuple.rs b/src/test/rustdoc-json/enums/discriminant/tuple.rs
new file mode 100644
index 00000000000..b94d5739eab
--- /dev/null
+++ b/src/test/rustdoc-json/enums/discriminant/tuple.rs
@@ -0,0 +1,15 @@
+// ignore-tidy-linelength
+
+#[repr(u32)]
+// @is "$.index[*][?(@.name=='Foo')].attrs" '["#[repr(u32)]"]'
+pub enum Foo {
+    // @is    "$.index[*][?(@.name=='Tuple')].inner.discriminant" null
+    // @count "$.index[*][?(@.name=='Tuple')].inner.kind.tuple[*]" 0
+    Tuple(),
+    // @is    "$.index[*][?(@.name=='TupleWithDiscr')].inner.discriminant" '{"expr": "1", "value": "1"}'
+    // @count "$.index[*][?(@.name=='TupleWithDiscr')].inner.kind.tuple[*]" 1
+    TupleWithDiscr(i32) = 1,
+    // @is    "$.index[*][?(@.name=='TupleWithBinDiscr')].inner.discriminant" '{"expr": "0b10", "value": "2"}'
+    // @count "$.index[*][?(@.name=='TupleWithBinDiscr')].inner.kind.tuple[*]" 2
+    TupleWithBinDiscr(i32, i32) = 0b10,
+}
diff --git a/src/test/rustdoc-json/enums/field_hidden.rs b/src/test/rustdoc-json/enums/field_hidden.rs
index e6310cc3b99..78a05431472 100644
--- a/src/test/rustdoc-json/enums/field_hidden.rs
+++ b/src/test/rustdoc-json/enums/field_hidden.rs
@@ -5,8 +5,8 @@
 
 // @has "$.index[*][?(@.name=='ParseError')]"
 // @has "$.index[*][?(@.name=='UnexpectedEndTag')]"
-// @is "$.index[*][?(@.name=='UnexpectedEndTag')].inner.variant_kind" '"tuple"'
-// @is "$.index[*][?(@.name=='UnexpectedEndTag')].inner.variant_inner" [null]
+// @is "$.index[*][?(@.name=='UnexpectedEndTag')].inner.kind.tuple" [null]
+// @is "$.index[*][?(@.name=='UnexpectedEndTag')].inner.discriminant" null
 
 pub enum ParseError {
     UnexpectedEndTag(#[doc(hidden)] u32),
diff --git a/src/test/rustdoc-json/enums/kind.rs b/src/test/rustdoc-json/enums/kind.rs
index e9ea3ae23c2..1787a859c8b 100644
--- a/src/test/rustdoc-json/enums/kind.rs
+++ b/src/test/rustdoc-json/enums/kind.rs
@@ -5,27 +5,22 @@
 
 pub enum Foo {
     // @set Unit = "$.index[*][?(@.name=='Unit')].id"
-    // @is "$.index[*][?(@.name=='Unit')].inner.variant_kind" '"plain"'
-    // @is "$.index[*][?(@.name=='Unit')].inner.variant_inner" null
+    // @is "$.index[*][?(@.name=='Unit')].inner.kind" '"plain"'
     Unit,
     // @set Named = "$.index[*][?(@.name=='Named')].id"
-    // @is "$.index[*][?(@.name=='Named')].inner.variant_kind" '"struct"'
-    // @is "$.index[*][?(@.name=='Named')].inner.variant_inner" '{"fields": [], "fields_stripped": false}'
+    // @is "$.index[*][?(@.name=='Named')].inner.kind.struct" '{"fields": [], "fields_stripped": false}'
     Named {},
     // @set Tuple = "$.index[*][?(@.name=='Tuple')].id"
-    // @is "$.index[*][?(@.name=='Tuple')].inner.variant_kind" '"tuple"'
-    // @is "$.index[*][?(@.name=='Tuple')].inner.variant_inner" []
+    // @is "$.index[*][?(@.name=='Tuple')].inner.kind.tuple" []
     Tuple(),
     // @set NamedField = "$.index[*][?(@.name=='NamedField')].id"
     // @set x = "$.index[*][?(@.name=='x' && @.kind=='struct_field')].id"
-    // @is "$.index[*][?(@.name=='NamedField')].inner.variant_kind" '"struct"'
-    // @is "$.index[*][?(@.name=='NamedField')].inner.variant_inner.fields[*]" $x
-    // @is "$.index[*][?(@.name=='NamedField')].inner.variant_inner.fields_stripped" false
+    // @is "$.index[*][?(@.name=='NamedField')].inner.kind.struct.fields[*]" $x
+    // @is "$.index[*][?(@.name=='NamedField')].inner.kind.struct.fields_stripped" false
     NamedField { x: i32 },
     // @set TupleField = "$.index[*][?(@.name=='TupleField')].id"
-    // @is "$.index[*][?(@.name=='TupleField')].inner.variant_kind" '"tuple"'
     // @set tup_field = "$.index[*][?(@.name=='0' && @.kind=='struct_field')].id"
-    // @is "$.index[*][?(@.name=='TupleField')].inner.variant_inner[*]" $tup_field
+    // @is "$.index[*][?(@.name=='TupleField')].inner.kind.tuple[*]" $tup_field
     TupleField(i32),
 }
 
diff --git a/src/test/rustdoc-json/enums/struct_field_hidden.rs b/src/test/rustdoc-json/enums/struct_field_hidden.rs
index f612a34a492..de939cde2e7 100644
--- a/src/test/rustdoc-json/enums/struct_field_hidden.rs
+++ b/src/test/rustdoc-json/enums/struct_field_hidden.rs
@@ -9,9 +9,8 @@ pub enum Foo {
         // @set y = "$.index[*][?(@.name=='y')].id"
         y: i32,
     },
-    // @is "$.index[*][?(@.name=='Variant')].inner.variant_kind" '"struct"'
-    // @is "$.index[*][?(@.name=='Variant')].inner.variant_inner.fields_stripped" true
-    // @is "$.index[*][?(@.name=='Variant')].inner.variant_inner.fields[0]" $b
-    // @is "$.index[*][?(@.name=='Variant')].inner.variant_inner.fields[1]" $y
-    // @count "$.index[*][?(@.name=='Variant')].inner.variant_inner.fields[*]" 2
+    // @is "$.index[*][?(@.name=='Variant')].inner.kind.struct.fields_stripped" true
+    // @is "$.index[*][?(@.name=='Variant')].inner.kind.struct.fields[0]" $b
+    // @is "$.index[*][?(@.name=='Variant')].inner.kind.struct.fields[1]" $y
+    // @count "$.index[*][?(@.name=='Variant')].inner.kind.struct.fields[*]" 2
 }
diff --git a/src/test/rustdoc-json/enums/tuple_fields_hidden.rs b/src/test/rustdoc-json/enums/tuple_fields_hidden.rs
index f546eaa0d17..70bfbb81826 100644
--- a/src/test/rustdoc-json/enums/tuple_fields_hidden.rs
+++ b/src/test/rustdoc-json/enums/tuple_fields_hidden.rs
@@ -14,61 +14,50 @@
 // @set 3.3.1 = "$.index[*][?(@.docs=='3.3.1')].id"
 
 pub enum EnumWithStrippedTupleVariants {
-    // @is    "$.index[*][?(@.name=='None')].inner.variant_kind" '"tuple"'
-    // @count "$.index[*][?(@.name=='None')].inner.variant_inner[*]" 0
+    // @count "$.index[*][?(@.name=='None')].inner.kind.tuple[*]" 0
     None(),
 
-    // @is    "$.index[*][?(@.name=='One')].inner.variant_kind" '"tuple"'
-    // @count "$.index[*][?(@.name=='One')].inner.variant_inner[*]" 1
-    // @is    "$.index[*][?(@.name=='One')].inner.variant_inner[0]" $1.1.0
+    // @count "$.index[*][?(@.name=='One')].inner.kind.tuple[*]" 1
+    // @is    "$.index[*][?(@.name=='One')].inner.kind.tuple[0]" $1.1.0
     One(/** 1.1.0*/ bool),
-    // @is    "$.index[*][?(@.name=='OneHidden')].inner.variant_kind" '"tuple"'
-    // @count "$.index[*][?(@.name=='OneHidden')].inner.variant_inner[*]" 1
-    // @is    "$.index[*][?(@.name=='OneHidden')].inner.variant_inner[0]" null
+    // @count "$.index[*][?(@.name=='OneHidden')].inner.kind.tuple[*]" 1
+    // @is    "$.index[*][?(@.name=='OneHidden')].inner.kind.tuple[0]" null
     OneHidden(#[doc(hidden)] bool),
 
-    // @is    "$.index[*][?(@.name=='Two')].inner.variant_kind" '"tuple"'
-    // @count "$.index[*][?(@.name=='Two')].inner.variant_inner[*]" 2
-    // @is    "$.index[*][?(@.name=='Two')].inner.variant_inner[0]" $2.1.0
-    // @is    "$.index[*][?(@.name=='Two')].inner.variant_inner[1]" $2.1.1
+    // @count "$.index[*][?(@.name=='Two')].inner.kind.tuple[*]" 2
+    // @is    "$.index[*][?(@.name=='Two')].inner.kind.tuple[0]" $2.1.0
+    // @is    "$.index[*][?(@.name=='Two')].inner.kind.tuple[1]" $2.1.1
     Two(/** 2.1.0*/ bool, /** 2.1.1*/ bool),
-    // @is    "$.index[*][?(@.name=='TwoLeftHidden')].inner.variant_kind" '"tuple"'
-    // @count "$.index[*][?(@.name=='TwoLeftHidden')].inner.variant_inner[*]" 2
-    // @is    "$.index[*][?(@.name=='TwoLeftHidden')].inner.variant_inner[0]" null
-    // @is    "$.index[*][?(@.name=='TwoLeftHidden')].inner.variant_inner[1]" $2.2.1
+    // @count "$.index[*][?(@.name=='TwoLeftHidden')].inner.kind.tuple[*]" 2
+    // @is    "$.index[*][?(@.name=='TwoLeftHidden')].inner.kind.tuple[0]" null
+    // @is    "$.index[*][?(@.name=='TwoLeftHidden')].inner.kind.tuple[1]" $2.2.1
     TwoLeftHidden(#[doc(hidden)] bool, /** 2.2.1*/ bool),
-    // @is    "$.index[*][?(@.name=='TwoRightHidden')].inner.variant_kind" '"tuple"'
-    // @count "$.index[*][?(@.name=='TwoRightHidden')].inner.variant_inner[*]" 2
-    // @is    "$.index[*][?(@.name=='TwoRightHidden')].inner.variant_inner[0]" $2.3.0
-    // @is    "$.index[*][?(@.name=='TwoRightHidden')].inner.variant_inner[1]" null
+    // @count "$.index[*][?(@.name=='TwoRightHidden')].inner.kind.tuple[*]" 2
+    // @is    "$.index[*][?(@.name=='TwoRightHidden')].inner.kind.tuple[0]" $2.3.0
+    // @is    "$.index[*][?(@.name=='TwoRightHidden')].inner.kind.tuple[1]" null
     TwoRightHidden(/** 2.3.0*/ bool, #[doc(hidden)] bool),
-    // @is    "$.index[*][?(@.name=='TwoBothHidden')].inner.variant_kind" '"tuple"'
-    // @count "$.index[*][?(@.name=='TwoBothHidden')].inner.variant_inner[*]" 2
-    // @is    "$.index[*][?(@.name=='TwoBothHidden')].inner.variant_inner[0]" null
-    // @is    "$.index[*][?(@.name=='TwoBothHidden')].inner.variant_inner[1]" null
+    // @count "$.index[*][?(@.name=='TwoBothHidden')].inner.kind.tuple[*]" 2
+    // @is    "$.index[*][?(@.name=='TwoBothHidden')].inner.kind.tuple[0]" null
+    // @is    "$.index[*][?(@.name=='TwoBothHidden')].inner.kind.tuple[1]" null
     TwoBothHidden(#[doc(hidden)] bool, #[doc(hidden)] bool),
 
-    // @is    "$.index[*][?(@.name=='Three1')].inner.variant_kind" '"tuple"'
-    // @count "$.index[*][?(@.name=='Three1')].inner.variant_inner[*]" 3
-    // @is    "$.index[*][?(@.name=='Three1')].inner.variant_inner[0]" null
-    // @is    "$.index[*][?(@.name=='Three1')].inner.variant_inner[1]" $3.1.1
-    // @is    "$.index[*][?(@.name=='Three1')].inner.variant_inner[2]" $3.1.2
+    // @count "$.index[*][?(@.name=='Three1')].inner.kind.tuple[*]" 3
+    // @is    "$.index[*][?(@.name=='Three1')].inner.kind.tuple[0]" null
+    // @is    "$.index[*][?(@.name=='Three1')].inner.kind.tuple[1]" $3.1.1
+    // @is    "$.index[*][?(@.name=='Three1')].inner.kind.tuple[2]" $3.1.2
     Three1(#[doc(hidden)] bool, /** 3.1.1*/ bool, /** 3.1.2*/ bool),
-    // @is    "$.index[*][?(@.name=='Three2')].inner.variant_kind" '"tuple"'
-    // @count "$.index[*][?(@.name=='Three2')].inner.variant_inner[*]" 3
-    // @is    "$.index[*][?(@.name=='Three2')].inner.variant_inner[0]" $3.2.0
-    // @is    "$.index[*][?(@.name=='Three2')].inner.variant_inner[1]" null
-    // @is    "$.index[*][?(@.name=='Three2')].inner.variant_inner[2]" $3.2.2
+    // @count "$.index[*][?(@.name=='Three2')].inner.kind.tuple[*]" 3
+    // @is    "$.index[*][?(@.name=='Three2')].inner.kind.tuple[0]" $3.2.0
+    // @is    "$.index[*][?(@.name=='Three2')].inner.kind.tuple[1]" null
+    // @is    "$.index[*][?(@.name=='Three2')].inner.kind.tuple[2]" $3.2.2
     Three2(/** 3.2.0*/ bool, #[doc(hidden)] bool, /** 3.2.2*/ bool),
-    // @is    "$.index[*][?(@.name=='Three3')].inner.variant_kind" '"tuple"'
-    // @count "$.index[*][?(@.name=='Three3')].inner.variant_inner[*]" 3
-    // @is    "$.index[*][?(@.name=='Three3')].inner.variant_inner[0]" $3.3.0
-    // @is    "$.index[*][?(@.name=='Three3')].inner.variant_inner[1]" $3.3.1
-    // @is    "$.index[*][?(@.name=='Three3')].inner.variant_inner[2]" null
+    // @count "$.index[*][?(@.name=='Three3')].inner.kind.tuple[*]" 3
+    // @is    "$.index[*][?(@.name=='Three3')].inner.kind.tuple[0]" $3.3.0
+    // @is    "$.index[*][?(@.name=='Three3')].inner.kind.tuple[1]" $3.3.1
+    // @is    "$.index[*][?(@.name=='Three3')].inner.kind.tuple[2]" null
     Three3(/** 3.3.0*/ bool, /** 3.3.1*/ bool, #[doc(hidden)] bool),
 }
 
-
 // @is "$.index[*][?(@.docs=='1.1.0')].name" '"0"'
 // @is "$.index[*][?(@.docs=='2.1.0')].name" '"0"'
 // @is "$.index[*][?(@.docs=='2.1.1')].name" '"1"'
diff --git a/src/test/rustdoc-json/enums/variant_struct.rs b/src/test/rustdoc-json/enums/variant_struct.rs
index 23b854d8d17..bc870c502a0 100644
--- a/src/test/rustdoc-json/enums/variant_struct.rs
+++ b/src/test/rustdoc-json/enums/variant_struct.rs
@@ -1,11 +1,10 @@
 // @is "$.index[*][?(@.name=='EnumStruct')].visibility" \"public\"
 // @is "$.index[*][?(@.name=='EnumStruct')].kind" \"enum\"
 pub enum EnumStruct {
-    // @is "$.index[*][?(@.name=='VariantS')].inner.variant_kind" \"struct\"
     // @is "$.index[*][?(@.name=='x')].kind" \"struct_field\"
+    // @set x = "$.index[*][?(@.name=='x')].id"
     // @is "$.index[*][?(@.name=='y')].kind" \"struct_field\"
-    VariantS {
-        x: u32,
-        y: String,
-    },
+    // @set y = "$.index[*][?(@.name=='y')].id"
+    // @ismany "$.index[*][?(@.name=='VariantS')].inner.kind.struct.fields[*]" $x $y
+    VariantS { x: u32, y: String },
 }
diff --git a/src/test/rustdoc-json/enums/variant_tuple_struct.rs b/src/test/rustdoc-json/enums/variant_tuple_struct.rs
index b71ec47a804..d1207bbfb18 100644
--- a/src/test/rustdoc-json/enums/variant_tuple_struct.rs
+++ b/src/test/rustdoc-json/enums/variant_tuple_struct.rs
@@ -1,8 +1,10 @@
 // @is "$.index[*][?(@.name=='EnumTupleStruct')].visibility" \"public\"
 // @is "$.index[*][?(@.name=='EnumTupleStruct')].kind" \"enum\"
 pub enum EnumTupleStruct {
-    // @is "$.index[*][?(@.name=='VariantA')].inner.variant_kind" \"tuple\"
     // @is "$.index[*][?(@.name=='0')].kind" \"struct_field\"
+    // @set f0 = "$.index[*][?(@.name=='0')].id"
     // @is "$.index[*][?(@.name=='1')].kind" \"struct_field\"
+    // @set f1 = "$.index[*][?(@.name=='1')].id"
+    // @ismany "$.index[*][?(@.name=='VariantA')].inner.kind.tuple[*]" $f0 $f1
     VariantA(u32, String),
 }
diff --git a/src/test/rustdoc-ui/issue-105334.rs b/src/test/rustdoc-ui/issue-105334.rs
new file mode 100644
index 00000000000..ee1adc6a029
--- /dev/null
+++ b/src/test/rustdoc-ui/issue-105334.rs
@@ -0,0 +1,2 @@
+impl Vec< br##"*.."## > {}
+//~^ ERROR
diff --git a/src/test/rustdoc-ui/issue-105334.stderr b/src/test/rustdoc-ui/issue-105334.stderr
new file mode 100644
index 00000000000..e163bb4db9e
--- /dev/null
+++ b/src/test/rustdoc-ui/issue-105334.stderr
@@ -0,0 +1,9 @@
+error[E0747]: constant provided when a type was expected
+  --> $DIR/issue-105334.rs:1:11
+   |
+LL | impl Vec< br##"*.."## > {}
+   |           ^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0747`.
diff --git a/src/test/rustdoc-ui/issue-105737.rs b/src/test/rustdoc-ui/issue-105737.rs
new file mode 100644
index 00000000000..154f069d8ff
--- /dev/null
+++ b/src/test/rustdoc-ui/issue-105737.rs
@@ -0,0 +1,4 @@
+impl Vec<lol> {}
+//~^ ERROR
+
+pub fn lol() {}
diff --git a/src/test/rustdoc-ui/issue-105737.stderr b/src/test/rustdoc-ui/issue-105737.stderr
new file mode 100644
index 00000000000..2dd9beb17da
--- /dev/null
+++ b/src/test/rustdoc-ui/issue-105737.stderr
@@ -0,0 +1,12 @@
+error[E0747]: constant provided when a type was expected
+  --> $DIR/issue-105737.rs:1:10
+   |
+LL | impl Vec<lol> {}
+   |          ^^^
+   |
+   = help: `lol` is a function item, not a type
+   = help: function item types cannot be named directly
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0747`.
diff --git a/src/test/rustdoc-ui/issue-105742.rs b/src/test/rustdoc-ui/issue-105742.rs
new file mode 100644
index 00000000000..cb1de7433cf
--- /dev/null
+++ b/src/test/rustdoc-ui/issue-105742.rs
@@ -0,0 +1,40 @@
+// compile-flags: -Znormalize-docs
+
+use std::ops::Index;
+
+pub fn next<'a, T>(s: &'a mut dyn SVec<Item = T, Output = T>) {
+//~^ ERROR
+//~^^ ERROR
+//~^^^ ERROR
+    let _ = s;
+}
+
+pub trait SVec: Index<
+    <Self as SVec>::Item,
+//~^ ERROR
+//~^^ ERROR
+//~^^^ ERROR
+//~^^^^ ERROR
+    Output = <Index<<Self as SVec>::Item,
+//~^ ERROR
+//~^^ ERROR
+//~^^^ ERROR
+//~^^^^ ERROR
+    Output = <Self as SVec>::Item> as SVec>::Item,
+//~^ ERROR
+//~^^ ERROR
+//~^^^ ERROR
+//~^^^^ ERROR
+//~^^^^^ ERROR
+//~^^^^^^ ERROR
+//~^^^^^^^ ERROR
+//~^^^^^^^^ ERROR
+> {
+    type Item<'a, T>;
+
+    fn len(&self) -> <Self as SVec>::Item;
+    //~^ ERROR
+    //~^^ ERROR
+    //~^^^ ERROR
+    //~^^^^ ERROR
+}
diff --git a/src/test/rustdoc-ui/issue-105742.stderr b/src/test/rustdoc-ui/issue-105742.stderr
new file mode 100644
index 00000000000..cc101b7ff37
--- /dev/null
+++ b/src/test/rustdoc-ui/issue-105742.stderr
@@ -0,0 +1,385 @@
+error[E0107]: missing generics for associated type `SVec::Item`
+  --> $DIR/issue-105742.rs:13:21
+   |
+LL |     <Self as SVec>::Item,
+   |                     ^^^^ expected 1 lifetime argument
+   |
+note: associated type defined here, with 1 lifetime parameter: `'a`
+  --> $DIR/issue-105742.rs:33:10
+   |
+LL |     type Item<'a, T>;
+   |          ^^^^ --
+help: add missing lifetime argument
+   |
+LL |     <Self as SVec>::Item<'a>,
+   |                     ~~~~~~~~
+
+error[E0107]: missing generics for associated type `SVec::Item`
+  --> $DIR/issue-105742.rs:13:21
+   |
+LL |     <Self as SVec>::Item,
+   |                     ^^^^ expected 1 generic argument
+   |
+note: associated type defined here, with 1 generic parameter: `T`
+  --> $DIR/issue-105742.rs:33:10
+   |
+LL |     type Item<'a, T>;
+   |          ^^^^     -
+help: add missing generic argument
+   |
+LL |     <Self as SVec>::Item<T>,
+   |                     ~~~~~~~
+
+error[E0107]: missing generics for associated type `SVec::Item`
+  --> $DIR/issue-105742.rs:18:37
+   |
+LL |     Output = <Index<<Self as SVec>::Item,
+   |                                     ^^^^ expected 1 lifetime argument
+   |
+note: associated type defined here, with 1 lifetime parameter: `'a`
+  --> $DIR/issue-105742.rs:33:10
+   |
+LL |     type Item<'a, T>;
+   |          ^^^^ --
+help: add missing lifetime argument
+   |
+LL |     Output = <Index<<Self as SVec>::Item<'a>,
+   |                                     ~~~~~~~~
+
+error[E0107]: missing generics for associated type `SVec::Item`
+  --> $DIR/issue-105742.rs:18:37
+   |
+LL |     Output = <Index<<Self as SVec>::Item,
+   |                                     ^^^^ expected 1 generic argument
+   |
+note: associated type defined here, with 1 generic parameter: `T`
+  --> $DIR/issue-105742.rs:33:10
+   |
+LL |     type Item<'a, T>;
+   |          ^^^^     -
+help: add missing generic argument
+   |
+LL |     Output = <Index<<Self as SVec>::Item<T>,
+   |                                     ~~~~~~~
+
+error[E0107]: missing generics for associated type `SVec::Item`
+  --> $DIR/issue-105742.rs:23:30
+   |
+LL |     Output = <Self as SVec>::Item> as SVec>::Item,
+   |                              ^^^^ expected 1 lifetime argument
+   |
+note: associated type defined here, with 1 lifetime parameter: `'a`
+  --> $DIR/issue-105742.rs:33:10
+   |
+LL |     type Item<'a, T>;
+   |          ^^^^ --
+help: add missing lifetime argument
+   |
+LL |     Output = <Self as SVec>::Item<'a>> as SVec>::Item,
+   |                              ~~~~~~~~
+
+error[E0107]: missing generics for associated type `SVec::Item`
+  --> $DIR/issue-105742.rs:23:30
+   |
+LL |     Output = <Self as SVec>::Item> as SVec>::Item,
+   |                              ^^^^ expected 1 generic argument
+   |
+note: associated type defined here, with 1 generic parameter: `T`
+  --> $DIR/issue-105742.rs:33:10
+   |
+LL |     type Item<'a, T>;
+   |          ^^^^     -
+help: add missing generic argument
+   |
+LL |     Output = <Self as SVec>::Item<T>> as SVec>::Item,
+   |                              ~~~~~~~
+
+error[E0107]: missing generics for associated type `SVec::Item`
+  --> $DIR/issue-105742.rs:23:46
+   |
+LL |     Output = <Self as SVec>::Item> as SVec>::Item,
+   |                                              ^^^^ expected 1 lifetime argument
+   |
+note: associated type defined here, with 1 lifetime parameter: `'a`
+  --> $DIR/issue-105742.rs:33:10
+   |
+LL |     type Item<'a, T>;
+   |          ^^^^ --
+help: add missing lifetime argument
+   |
+LL |     Output = <Self as SVec>::Item> as SVec>::Item<'a>,
+   |                                              ~~~~~~~~
+
+error[E0107]: missing generics for associated type `SVec::Item`
+  --> $DIR/issue-105742.rs:23:46
+   |
+LL |     Output = <Self as SVec>::Item> as SVec>::Item,
+   |                                              ^^^^ expected 1 generic argument
+   |
+note: associated type defined here, with 1 generic parameter: `T`
+  --> $DIR/issue-105742.rs:33:10
+   |
+LL |     type Item<'a, T>;
+   |          ^^^^     -
+help: add missing generic argument
+   |
+LL |     Output = <Self as SVec>::Item> as SVec>::Item<T>,
+   |                                              ~~~~~~~
+
+error[E0107]: missing generics for associated type `SVec::Item`
+  --> $DIR/issue-105742.rs:5:40
+   |
+LL | pub fn next<'a, T>(s: &'a mut dyn SVec<Item = T, Output = T>) {
+   |                                        ^^^^ expected 1 lifetime argument
+   |
+note: associated type defined here, with 1 lifetime parameter: `'a`
+  --> $DIR/issue-105742.rs:33:10
+   |
+LL |     type Item<'a, T>;
+   |          ^^^^ --
+help: add missing lifetime argument
+   |
+LL | pub fn next<'a, T>(s: &'a mut dyn SVec<Item<'_> = T, Output = T>) {
+   |                                        ~~~~~~~~
+
+error[E0107]: missing generics for associated type `SVec::Item`
+  --> $DIR/issue-105742.rs:5:40
+   |
+LL | pub fn next<'a, T>(s: &'a mut dyn SVec<Item = T, Output = T>) {
+   |                                        ^^^^ expected 1 generic argument
+   |
+note: associated type defined here, with 1 generic parameter: `T`
+  --> $DIR/issue-105742.rs:33:10
+   |
+LL |     type Item<'a, T>;
+   |          ^^^^     -
+help: add missing generic argument
+   |
+LL | pub fn next<'a, T>(s: &'a mut dyn SVec<Item<T> = T, Output = T>) {
+   |                                        ~~~~~~~
+
+error[E0107]: missing generics for associated type `SVec::Item`
+  --> $DIR/issue-105742.rs:13:21
+   |
+LL |     <Self as SVec>::Item,
+   |                     ^^^^ expected 1 lifetime argument
+   |
+note: associated type defined here, with 1 lifetime parameter: `'a`
+  --> $DIR/issue-105742.rs:33:10
+   |
+LL |     type Item<'a, T>;
+   |          ^^^^ --
+help: add missing lifetime argument
+   |
+LL |     <Self as SVec>::Item<'a>,
+   |                     ~~~~~~~~
+
+error[E0107]: missing generics for associated type `SVec::Item`
+  --> $DIR/issue-105742.rs:13:21
+   |
+LL |     <Self as SVec>::Item,
+   |                     ^^^^ expected 1 generic argument
+   |
+note: associated type defined here, with 1 generic parameter: `T`
+  --> $DIR/issue-105742.rs:33:10
+   |
+LL |     type Item<'a, T>;
+   |          ^^^^     -
+help: add missing generic argument
+   |
+LL |     <Self as SVec>::Item<T>,
+   |                     ~~~~~~~
+
+error[E0107]: missing generics for associated type `SVec::Item`
+  --> $DIR/issue-105742.rs:18:37
+   |
+LL |     Output = <Index<<Self as SVec>::Item,
+   |                                     ^^^^ expected 1 lifetime argument
+   |
+note: associated type defined here, with 1 lifetime parameter: `'a`
+  --> $DIR/issue-105742.rs:33:10
+   |
+LL |     type Item<'a, T>;
+   |          ^^^^ --
+help: add missing lifetime argument
+   |
+LL |     Output = <Index<<Self as SVec>::Item<'a>,
+   |                                     ~~~~~~~~
+
+error[E0107]: missing generics for associated type `SVec::Item`
+  --> $DIR/issue-105742.rs:18:37
+   |
+LL |     Output = <Index<<Self as SVec>::Item,
+   |                                     ^^^^ expected 1 generic argument
+   |
+note: associated type defined here, with 1 generic parameter: `T`
+  --> $DIR/issue-105742.rs:33:10
+   |
+LL |     type Item<'a, T>;
+   |          ^^^^     -
+help: add missing generic argument
+   |
+LL |     Output = <Index<<Self as SVec>::Item<T>,
+   |                                     ~~~~~~~
+
+error[E0107]: missing generics for associated type `SVec::Item`
+  --> $DIR/issue-105742.rs:23:30
+   |
+LL |     Output = <Self as SVec>::Item> as SVec>::Item,
+   |                              ^^^^ expected 1 lifetime argument
+   |
+note: associated type defined here, with 1 lifetime parameter: `'a`
+  --> $DIR/issue-105742.rs:33:10
+   |
+LL |     type Item<'a, T>;
+   |          ^^^^ --
+help: add missing lifetime argument
+   |
+LL |     Output = <Self as SVec>::Item<'a>> as SVec>::Item,
+   |                              ~~~~~~~~
+
+error[E0107]: missing generics for associated type `SVec::Item`
+  --> $DIR/issue-105742.rs:23:30
+   |
+LL |     Output = <Self as SVec>::Item> as SVec>::Item,
+   |                              ^^^^ expected 1 generic argument
+   |
+note: associated type defined here, with 1 generic parameter: `T`
+  --> $DIR/issue-105742.rs:33:10
+   |
+LL |     type Item<'a, T>;
+   |          ^^^^     -
+help: add missing generic argument
+   |
+LL |     Output = <Self as SVec>::Item<T>> as SVec>::Item,
+   |                              ~~~~~~~
+
+error[E0107]: missing generics for associated type `SVec::Item`
+  --> $DIR/issue-105742.rs:23:46
+   |
+LL |     Output = <Self as SVec>::Item> as SVec>::Item,
+   |                                              ^^^^ expected 1 lifetime argument
+   |
+note: associated type defined here, with 1 lifetime parameter: `'a`
+  --> $DIR/issue-105742.rs:33:10
+   |
+LL |     type Item<'a, T>;
+   |          ^^^^ --
+help: add missing lifetime argument
+   |
+LL |     Output = <Self as SVec>::Item> as SVec>::Item<'a>,
+   |                                              ~~~~~~~~
+
+error[E0107]: missing generics for associated type `SVec::Item`
+  --> $DIR/issue-105742.rs:23:46
+   |
+LL |     Output = <Self as SVec>::Item> as SVec>::Item,
+   |                                              ^^^^ expected 1 generic argument
+   |
+note: associated type defined here, with 1 generic parameter: `T`
+  --> $DIR/issue-105742.rs:33:10
+   |
+LL |     type Item<'a, T>;
+   |          ^^^^     -
+help: add missing generic argument
+   |
+LL |     Output = <Self as SVec>::Item> as SVec>::Item<T>,
+   |                                              ~~~~~~~
+
+error[E0038]: the trait `SVec` cannot be made into an object
+  --> $DIR/issue-105742.rs:5:31
+   |
+LL | pub fn next<'a, T>(s: &'a mut dyn SVec<Item = T, Output = T>) {
+   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `SVec` cannot be made into an object
+   |
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $DIR/issue-105742.rs:12:17
+   |
+LL |    pub trait SVec: Index<
+   |  ____________----__^
+   | |            |
+   | |            this trait cannot be made into an object...
+LL | |      <Self as SVec>::Item,
+LL | |
+LL | |
+...  |
+LL | |/     Output = <Index<<Self as SVec>::Item,
+LL | ||
+LL | ||
+LL | ||
+LL | ||
+LL | ||     Output = <Self as SVec>::Item> as SVec>::Item,
+   | ||_________________________________________________^ ...because it uses `Self` as a type parameter
+...  |
+LL | |
+LL | |  > {
+   | |__^ ...because it uses `Self` as a type parameter
+
+error[E0107]: missing generics for associated type `SVec::Item`
+  --> $DIR/issue-105742.rs:35:38
+   |
+LL |     fn len(&self) -> <Self as SVec>::Item;
+   |                                      ^^^^ expected 1 lifetime argument
+   |
+note: associated type defined here, with 1 lifetime parameter: `'a`
+  --> $DIR/issue-105742.rs:33:10
+   |
+LL |     type Item<'a, T>;
+   |          ^^^^ --
+help: add missing lifetime argument
+   |
+LL |     fn len(&self) -> <Self as SVec>::Item<'_>;
+   |                                      ~~~~~~~~
+
+error[E0107]: missing generics for associated type `SVec::Item`
+  --> $DIR/issue-105742.rs:35:38
+   |
+LL |     fn len(&self) -> <Self as SVec>::Item;
+   |                                      ^^^^ expected 1 generic argument
+   |
+note: associated type defined here, with 1 generic parameter: `T`
+  --> $DIR/issue-105742.rs:33:10
+   |
+LL |     type Item<'a, T>;
+   |          ^^^^     -
+help: add missing generic argument
+   |
+LL |     fn len(&self) -> <Self as SVec>::Item<T>;
+   |                                      ~~~~~~~
+
+error[E0107]: missing generics for associated type `SVec::Item`
+  --> $DIR/issue-105742.rs:35:38
+   |
+LL |     fn len(&self) -> <Self as SVec>::Item;
+   |                                      ^^^^ expected 1 lifetime argument
+   |
+note: associated type defined here, with 1 lifetime parameter: `'a`
+  --> $DIR/issue-105742.rs:33:10
+   |
+LL |     type Item<'a, T>;
+   |          ^^^^ --
+help: add missing lifetime argument
+   |
+LL |     fn len(&self) -> <Self as SVec>::Item<'_>;
+   |                                      ~~~~~~~~
+
+error[E0107]: missing generics for associated type `SVec::Item`
+  --> $DIR/issue-105742.rs:35:38
+   |
+LL |     fn len(&self) -> <Self as SVec>::Item;
+   |                                      ^^^^ expected 1 generic argument
+   |
+note: associated type defined here, with 1 generic parameter: `T`
+  --> $DIR/issue-105742.rs:33:10
+   |
+LL |     type Item<'a, T>;
+   |          ^^^^     -
+help: add missing generic argument
+   |
+LL |     fn len(&self) -> <Self as SVec>::Item<T>;
+   |                                      ~~~~~~~
+
+error: aborting due to 23 previous errors
+
+Some errors have detailed explanations: E0038, E0107.
+For more information about an error, try `rustc --explain E0038`.
diff --git a/src/test/rustdoc-ui/issue-106226.rs b/src/test/rustdoc-ui/issue-106226.rs
new file mode 100644
index 00000000000..71b497a9adc
--- /dev/null
+++ b/src/test/rustdoc-ui/issue-106226.rs
@@ -0,0 +1,3 @@
+// This is a regression test for <https://github.com/rust-lang/rust/issues/106226>.
+type F = [_; ()];
+//~^ ERROR
diff --git a/src/test/rustdoc-ui/issue-106226.stderr b/src/test/rustdoc-ui/issue-106226.stderr
new file mode 100644
index 00000000000..2beffbc125b
--- /dev/null
+++ b/src/test/rustdoc-ui/issue-106226.stderr
@@ -0,0 +1,9 @@
+error[E0308]: mismatched types
+  --> $DIR/issue-106226.rs:2:14
+   |
+LL | type F = [_; ()];
+   |              ^^ expected `usize`, found `()`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/rustdoc-ui/issue-96287.rs b/src/test/rustdoc-ui/issue-96287.rs
new file mode 100644
index 00000000000..8d8b4456e63
--- /dev/null
+++ b/src/test/rustdoc-ui/issue-96287.rs
@@ -0,0 +1,17 @@
+#![feature(type_alias_impl_trait)]
+
+pub trait TraitWithAssoc {
+    type Assoc;
+}
+
+pub type Foo<V> = impl Trait<V::Assoc>;
+//~^ ERROR
+//~^^ ERROR
+
+pub trait Trait<U> {}
+
+impl<W> Trait<W> for () {}
+
+pub fn foo_desugared<T: TraitWithAssoc>(_: T) -> Foo<T> {
+    ()
+}
diff --git a/src/test/rustdoc-ui/issue-96287.stderr b/src/test/rustdoc-ui/issue-96287.stderr
new file mode 100644
index 00000000000..0236b9fe647
--- /dev/null
+++ b/src/test/rustdoc-ui/issue-96287.stderr
@@ -0,0 +1,15 @@
+error[E0220]: associated type `Assoc` not found for `V`
+  --> $DIR/issue-96287.rs:7:33
+   |
+LL | pub type Foo<V> = impl Trait<V::Assoc>;
+   |                                 ^^^^^ there is a similarly named associated type `Assoc` in the trait `TraitWithAssoc`
+
+error[E0220]: associated type `Assoc` not found for `V`
+  --> $DIR/issue-96287.rs:7:33
+   |
+LL | pub type Foo<V> = impl Trait<V::Assoc>;
+   |                                 ^^^^^ there is a similarly named associated type `Assoc` in the trait `TraitWithAssoc`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0220`.
diff --git a/src/test/ui-fulldeps/deriving-encodable-decodable-box.rs b/src/test/ui-fulldeps/deriving-encodable-decodable-box.rs
index a4b911878e0..1c376f59e51 100644
--- a/src/test/ui-fulldeps/deriving-encodable-decodable-box.rs
+++ b/src/test/ui-fulldeps/deriving-encodable-decodable-box.rs
@@ -6,6 +6,11 @@
 extern crate rustc_macros;
 extern crate rustc_serialize;
 
+// Necessary to pull in object code as the rest of the rustc crates are shipped only as rmeta
+// files.
+#[allow(unused_extern_crates)]
+extern crate rustc_driver;
+
 use rustc_macros::{Decodable, Encodable};
 use rustc_serialize::opaque::{MemDecoder, MemEncoder};
 use rustc_serialize::{Decodable, Encodable, Encoder};
diff --git a/src/test/ui-fulldeps/deriving-encodable-decodable-cell-refcell.rs b/src/test/ui-fulldeps/deriving-encodable-decodable-cell-refcell.rs
index 580c85f9b78..844d40f2ecd 100644
--- a/src/test/ui-fulldeps/deriving-encodable-decodable-cell-refcell.rs
+++ b/src/test/ui-fulldeps/deriving-encodable-decodable-cell-refcell.rs
@@ -8,6 +8,11 @@
 extern crate rustc_macros;
 extern crate rustc_serialize;
 
+// Necessary to pull in object code as the rest of the rustc crates are shipped only as rmeta
+// files.
+#[allow(unused_extern_crates)]
+extern crate rustc_driver;
+
 use rustc_macros::{Decodable, Encodable};
 use rustc_serialize::opaque::{MemDecoder, MemEncoder};
 use rustc_serialize::{Decodable, Encodable, Encoder};
diff --git a/src/test/ui-fulldeps/deriving-global.rs b/src/test/ui-fulldeps/deriving-global.rs
index 921767af981..214bb4368ff 100644
--- a/src/test/ui-fulldeps/deriving-global.rs
+++ b/src/test/ui-fulldeps/deriving-global.rs
@@ -5,6 +5,11 @@
 extern crate rustc_macros;
 extern crate rustc_serialize;
 
+// Necessary to pull in object code as the rest of the rustc crates are shipped only as rmeta
+// files.
+#[allow(unused_extern_crates)]
+extern crate rustc_driver;
+
 mod submod {
     use rustc_macros::{Decodable, Encodable};
 
diff --git a/src/test/ui-fulldeps/deriving-hygiene.rs b/src/test/ui-fulldeps/deriving-hygiene.rs
index 8486b8b6e48..e1084a08fec 100644
--- a/src/test/ui-fulldeps/deriving-hygiene.rs
+++ b/src/test/ui-fulldeps/deriving-hygiene.rs
@@ -7,6 +7,11 @@ extern crate rustc_serialize;
 
 use rustc_macros::{Decodable, Encodable};
 
+// Necessary to pull in object code as the rest of the rustc crates are shipped only as rmeta
+// files.
+#[allow(unused_extern_crates)]
+extern crate rustc_driver;
+
 pub const other: u8 = 1;
 pub const f: u8 = 1;
 pub const d: u8 = 1;
diff --git a/src/test/ui-fulldeps/dropck_tarena_sound_drop.rs b/src/test/ui-fulldeps/dropck_tarena_sound_drop.rs
index 187f9a24a90..ffad80171da 100644
--- a/src/test/ui-fulldeps/dropck_tarena_sound_drop.rs
+++ b/src/test/ui-fulldeps/dropck_tarena_sound_drop.rs
@@ -14,6 +14,11 @@
 
 extern crate rustc_arena;
 
+// Necessary to pull in object code as the rest of the rustc crates are shipped only as rmeta
+// files.
+#[allow(unused_extern_crates)]
+extern crate rustc_driver;
+
 use rustc_arena::TypedArena;
 
 trait HasId { fn count(&self) -> usize; }
diff --git a/src/test/ui-fulldeps/empty-struct-braces-derive.rs b/src/test/ui-fulldeps/empty-struct-braces-derive.rs
index 6e5eb54629c..10e8beaa7b1 100644
--- a/src/test/ui-fulldeps/empty-struct-braces-derive.rs
+++ b/src/test/ui-fulldeps/empty-struct-braces-derive.rs
@@ -6,6 +6,11 @@
 extern crate rustc_macros;
 extern crate rustc_serialize;
 
+// Necessary to pull in object code as the rest of the rustc crates are shipped only as rmeta
+// files.
+#[allow(unused_extern_crates)]
+extern crate rustc_driver;
+
 use rustc_macros::{Decodable, Encodable};
 
 #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default, Debug, Encodable, Decodable)]
diff --git a/src/test/ui-fulldeps/issue-14021.rs b/src/test/ui-fulldeps/issue-14021.rs
index 215dfaed7ab..309b5c4a03d 100644
--- a/src/test/ui-fulldeps/issue-14021.rs
+++ b/src/test/ui-fulldeps/issue-14021.rs
@@ -7,6 +7,11 @@
 extern crate rustc_macros;
 extern crate rustc_serialize;
 
+// Necessary to pull in object code as the rest of the rustc crates are shipped only as rmeta
+// files.
+#[allow(unused_extern_crates)]
+extern crate rustc_driver;
+
 use rustc_macros::{Decodable, Encodable};
 use rustc_serialize::opaque::{MemDecoder, MemEncoder};
 use rustc_serialize::{Decodable, Encodable, Encoder};
diff --git a/src/test/ui-fulldeps/missing-rustc-driver-error.rs b/src/test/ui-fulldeps/missing-rustc-driver-error.rs
new file mode 100644
index 00000000000..654cd6f6dc9
--- /dev/null
+++ b/src/test/ui-fulldeps/missing-rustc-driver-error.rs
@@ -0,0 +1,11 @@
+// Test that we get the following hint when trying to use a compiler crate without rustc_driver.
+// error-pattern: try adding `extern crate rustc_driver;` at the top level of this crate
+// compile-flags: --emit link
+// The exactly list of required crates depends on the target. as such only test Unix targets.
+// only-unix
+
+#![feature(rustc_private)]
+
+extern crate rustc_serialize;
+
+fn main() {}
diff --git a/src/test/ui-fulldeps/missing-rustc-driver-error.stderr b/src/test/ui-fulldeps/missing-rustc-driver-error.stderr
new file mode 100644
index 00000000000..ad03ba0103c
--- /dev/null
+++ b/src/test/ui-fulldeps/missing-rustc-driver-error.stderr
@@ -0,0 +1,24 @@
+error: crate `rustc_serialize` required to be available in rlib format, but was not found in this form
+   |
+   = help: try adding `extern crate rustc_driver;` at the top level of this crate
+
+error: crate `smallvec` required to be available in rlib format, but was not found in this form
+
+error: crate `thin_vec` required to be available in rlib format, but was not found in this form
+
+error: crate `indexmap` required to be available in rlib format, but was not found in this form
+
+error: crate `hashbrown` required to be available in rlib format, but was not found in this form
+
+error: crate `ahash` required to be available in rlib format, but was not found in this form
+
+error: crate `once_cell` required to be available in rlib format, but was not found in this form
+
+error: crate `getrandom` required to be available in rlib format, but was not found in this form
+
+error: crate `cfg_if` required to be available in rlib format, but was not found in this form
+
+error: crate `libc` required to be available in rlib format, but was not found in this form
+
+error: aborting due to 10 previous errors
+
diff --git a/src/test/ui-fulldeps/mod_dir_path_canonicalized.rs b/src/test/ui-fulldeps/mod_dir_path_canonicalized.rs
index bb246de0e57..ff1be080415 100644
--- a/src/test/ui-fulldeps/mod_dir_path_canonicalized.rs
+++ b/src/test/ui-fulldeps/mod_dir_path_canonicalized.rs
@@ -10,6 +10,11 @@ extern crate rustc_parse;
 extern crate rustc_session;
 extern crate rustc_span;
 
+// Necessary to pull in object code as the rest of the rustc crates are shipped only as rmeta
+// files.
+#[allow(unused_extern_crates)]
+extern crate rustc_driver;
+
 use rustc_parse::new_parser_from_file;
 use rustc_session::parse::ParseSess;
 use rustc_span::source_map::FilePathMapping;
diff --git a/src/test/ui-fulldeps/pprust-expr-roundtrip.rs b/src/test/ui-fulldeps/pprust-expr-roundtrip.rs
index a93ba87470a..6dbabc8eb34 100644
--- a/src/test/ui-fulldeps/pprust-expr-roundtrip.rs
+++ b/src/test/ui-fulldeps/pprust-expr-roundtrip.rs
@@ -27,6 +27,11 @@ extern crate rustc_session;
 extern crate rustc_span;
 extern crate thin_vec;
 
+// Necessary to pull in object code as the rest of the rustc crates are shipped only as rmeta
+// files.
+#[allow(unused_extern_crates)]
+extern crate rustc_driver;
+
 use rustc_ast::mut_visit::{self, visit_clobber, MutVisitor};
 use rustc_ast::ptr::P;
 use rustc_ast::*;
diff --git a/src/test/ui-fulldeps/regions-mock-tcx.rs b/src/test/ui-fulldeps/regions-mock-tcx.rs
index 30e62723240..63975ef62c5 100644
--- a/src/test/ui-fulldeps/regions-mock-tcx.rs
+++ b/src/test/ui-fulldeps/regions-mock-tcx.rs
@@ -14,6 +14,11 @@
 extern crate rustc_arena;
 extern crate libc;
 
+// Necessary to pull in object code as the rest of the rustc crates are shipped only as rmeta
+// files.
+#[allow(unused_extern_crates)]
+extern crate rustc_driver;
+
 use TypeStructure::{TypeInt, TypeFunction};
 use AstKind::{ExprInt, ExprVar, ExprLambda};
 use rustc_arena::TypedArena;
diff --git a/src/test/ui-fulldeps/rustc_encodable_hygiene.rs b/src/test/ui-fulldeps/rustc_encodable_hygiene.rs
index 452110a65e4..509a6b1d22c 100644
--- a/src/test/ui-fulldeps/rustc_encodable_hygiene.rs
+++ b/src/test/ui-fulldeps/rustc_encodable_hygiene.rs
@@ -6,6 +6,11 @@ extern crate rustc_macros;
 #[allow(dead_code)]
 extern crate rustc_serialize;
 
+// Necessary to pull in object code as the rest of the rustc crates are shipped only as rmeta
+// files.
+#[allow(unused_extern_crates)]
+extern crate rustc_driver;
+
 use rustc_macros::{Decodable, Encodable};
 
 #[derive(Decodable, Encodable, Debug)]
diff --git a/src/test/ui/borrowck/borrowck-drop-from-guard.rs b/src/test/ui/borrowck/borrowck-drop-from-guard.rs
index 4995029a70f..0f320af2657 100644
--- a/src/test/ui/borrowck/borrowck-drop-from-guard.rs
+++ b/src/test/ui/borrowck/borrowck-drop-from-guard.rs
@@ -1,3 +1,5 @@
+#![feature(if_let_guard)]
+
 fn foo(_:String) {}
 
 fn main()
@@ -8,4 +10,11 @@ fn main()
         Some(_) => {}
         None => { foo(my_str); } //~ ERROR [E0382]
     }
+
+    let my_str = "hello".to_owned();
+    match Some(42) {
+        Some(_) if let Some(()) = { drop(my_str); None } => {}
+        Some(_) => {}
+        None => { foo(my_str); } //~ ERROR [E0382]
+    }
 }
diff --git a/src/test/ui/borrowck/borrowck-drop-from-guard.stderr b/src/test/ui/borrowck/borrowck-drop-from-guard.stderr
index eaf4bb38bc5..9fa28efd855 100644
--- a/src/test/ui/borrowck/borrowck-drop-from-guard.stderr
+++ b/src/test/ui/borrowck/borrowck-drop-from-guard.stderr
@@ -1,5 +1,5 @@
 error[E0382]: use of moved value: `my_str`
-  --> $DIR/borrowck-drop-from-guard.rs:9:23
+  --> $DIR/borrowck-drop-from-guard.rs:11:23
    |
 LL |     let my_str = "hello".to_owned();
    |         ------ move occurs because `my_str` has type `String`, which does not implement the `Copy` trait
@@ -15,6 +15,23 @@ help: consider cloning the value if the performance cost is acceptable
 LL |         Some(_) if { drop(my_str.clone()); false } => {}
    |                                 ++++++++
 
-error: aborting due to previous error
+error[E0382]: use of moved value: `my_str`
+  --> $DIR/borrowck-drop-from-guard.rs:18:23
+   |
+LL |     let my_str = "hello".to_owned();
+   |         ------ move occurs because `my_str` has type `String`, which does not implement the `Copy` trait
+LL |     match Some(42) {
+LL |         Some(_) if let Some(()) = { drop(my_str); None } => {}
+   |                                          ------ value moved here
+LL |         Some(_) => {}
+LL |         None => { foo(my_str); }
+   |                       ^^^^^^ value used here after move
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |         Some(_) if let Some(()) = { drop(my_str.clone()); None } => {}
+   |                                                ++++++++
+
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0382`.
diff --git a/src/test/ui/borrowck/borrowck-mutate-in-guard.rs b/src/test/ui/borrowck/borrowck-mutate-in-guard.rs
index 9cbceeb945c..d80a9e81576 100644
--- a/src/test/ui/borrowck/borrowck-mutate-in-guard.rs
+++ b/src/test/ui/borrowck/borrowck-mutate-in-guard.rs
@@ -1,9 +1,11 @@
+#![feature(if_let_guard)]
+
 enum Enum<'a> {
     A(&'a isize),
     B(bool),
 }
 
-fn foo() -> isize {
+fn if_guard() -> isize {
     let mut n = 42;
     let mut x = Enum::A(&mut n);
     match x {
@@ -16,6 +18,17 @@ fn foo() -> isize {
     }
 }
 
-fn main() {
-    foo();
+fn if_let_guard() -> isize {
+    let mut n = 42;
+    let mut x = Enum::A(&mut n);
+    match x {
+        Enum::A(_) if let Some(()) = { x = Enum::B(false); None } => 1,
+        //~^ ERROR cannot assign `x` in match guard
+        Enum::A(_) if let Some(()) = { let y = &mut x; *y = Enum::B(false); None } => 1,
+        //~^ ERROR cannot mutably borrow `x` in match guard
+        Enum::A(p) => *p,
+        Enum::B(_) => 2,
+    }
 }
+
+fn main() {}
diff --git a/src/test/ui/borrowck/borrowck-mutate-in-guard.stderr b/src/test/ui/borrowck/borrowck-mutate-in-guard.stderr
index 6d05e97252d..dbb3272fdc3 100644
--- a/src/test/ui/borrowck/borrowck-mutate-in-guard.stderr
+++ b/src/test/ui/borrowck/borrowck-mutate-in-guard.stderr
@@ -1,5 +1,5 @@
 error[E0510]: cannot assign `x` in match guard
-  --> $DIR/borrowck-mutate-in-guard.rs:10:25
+  --> $DIR/borrowck-mutate-in-guard.rs:12:25
    |
 LL |     match x {
    |           - value is immutable in match guard
@@ -7,7 +7,7 @@ LL |         Enum::A(_) if { x = Enum::B(false); false } => 1,
    |                         ^^^^^^^^^^^^^^^^^^ cannot assign
 
 error[E0510]: cannot mutably borrow `x` in match guard
-  --> $DIR/borrowck-mutate-in-guard.rs:12:33
+  --> $DIR/borrowck-mutate-in-guard.rs:14:33
    |
 LL |     match x {
    |           - value is immutable in match guard
@@ -15,6 +15,23 @@ LL |     match x {
 LL |         Enum::A(_) if { let y = &mut x; *y = Enum::B(false); false } => 1,
    |                                 ^^^^^^ cannot mutably borrow
 
-error: aborting due to 2 previous errors
+error[E0510]: cannot assign `x` in match guard
+  --> $DIR/borrowck-mutate-in-guard.rs:25:40
+   |
+LL |     match x {
+   |           - value is immutable in match guard
+LL |         Enum::A(_) if let Some(()) = { x = Enum::B(false); None } => 1,
+   |                                        ^^^^^^^^^^^^^^^^^^ cannot assign
+
+error[E0510]: cannot mutably borrow `x` in match guard
+  --> $DIR/borrowck-mutate-in-guard.rs:27:48
+   |
+LL |     match x {
+   |           - value is immutable in match guard
+...
+LL |         Enum::A(_) if let Some(()) = { let y = &mut x; *y = Enum::B(false); None } => 1,
+   |                                                ^^^^^^ cannot mutably borrow
+
+error: aborting due to 4 previous errors
 
 For more information about this error, try `rustc --explain E0510`.
diff --git a/src/test/ui/borrowck/issue-31287-drop-in-guard.rs b/src/test/ui/borrowck/issue-31287-drop-in-guard.rs
index 07125b98a1f..5b824adc6e2 100644
--- a/src/test/ui/borrowck/issue-31287-drop-in-guard.rs
+++ b/src/test/ui/borrowck/issue-31287-drop-in-guard.rs
@@ -1,8 +1,15 @@
+#![feature(if_let_guard)]
+
 fn main() {
     let a = Some("...".to_owned());
     let b = match a {
         Some(_) if { drop(a); false } => None,
         x => x, //~ ERROR use of moved value: `a`
     };
-    println!("{:?}", b);
+
+    let a = Some("...".to_owned());
+    let b = match a {
+        Some(_) if let Some(()) = { drop(a); None } => None,
+        x => x, //~ ERROR use of moved value: `a`
+    };
 }
diff --git a/src/test/ui/borrowck/issue-31287-drop-in-guard.stderr b/src/test/ui/borrowck/issue-31287-drop-in-guard.stderr
index ad898fcabd9..18f371c2073 100644
--- a/src/test/ui/borrowck/issue-31287-drop-in-guard.stderr
+++ b/src/test/ui/borrowck/issue-31287-drop-in-guard.stderr
@@ -1,5 +1,5 @@
 error[E0382]: use of moved value: `a`
-  --> $DIR/issue-31287-drop-in-guard.rs:5:9
+  --> $DIR/issue-31287-drop-in-guard.rs:7:9
    |
 LL |     let a = Some("...".to_owned());
    |         - move occurs because `a` has type `Option<String>`, which does not implement the `Copy` trait
@@ -14,6 +14,22 @@ help: consider cloning the value if the performance cost is acceptable
 LL |         Some(_) if { drop(a.clone()); false } => None,
    |                            ++++++++
 
-error: aborting due to previous error
+error[E0382]: use of moved value: `a`
+  --> $DIR/issue-31287-drop-in-guard.rs:13:9
+   |
+LL |     let a = Some("...".to_owned());
+   |         - move occurs because `a` has type `Option<String>`, which does not implement the `Copy` trait
+LL |     let b = match a {
+LL |         Some(_) if let Some(()) = { drop(a); None } => None,
+   |                                          - value moved here
+LL |         x => x,
+   |         ^ value used here after move
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |         Some(_) if let Some(()) = { drop(a.clone()); None } => None,
+   |                                           ++++++++
+
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0382`.
diff --git a/src/test/ui/fmt/ifmt-bad-arg.stderr b/src/test/ui/fmt/ifmt-bad-arg.stderr
index a8a2a47fe46..c2619d6df58 100644
--- a/src/test/ui/fmt/ifmt-bad-arg.stderr
+++ b/src/test/ui/fmt/ifmt-bad-arg.stderr
@@ -170,7 +170,7 @@ LL |     format!("foo %s baz", "bar");
    |                  |
    |                  help: format specifiers use curly braces: `{}`
    |
-   = note: printf formatting not supported; see the documentation for `std::fmt`
+   = note: printf formatting is not supported; see the documentation for `std::fmt`
 
 error: invalid format string: expected `'}'`, found `'t'`
   --> $DIR/ifmt-bad-arg.rs:75:1
diff --git a/src/test/ui/fmt/issue-89173.rs b/src/test/ui/fmt/issue-89173.rs
index 96277d4d0d9..fc99af40859 100644
--- a/src/test/ui/fmt/issue-89173.rs
+++ b/src/test/ui/fmt/issue-89173.rs
@@ -10,5 +10,5 @@ fn main() {
     //~| NOTE: argument never used
     //~| NOTE: argument never used
     //~| NOTE: format specifiers use curly braces, and you have to use a positional or named parameter for the width
-    //~| NOTE: printf formatting not supported
+    //~| NOTE: printf formatting is not supported
 }
diff --git a/src/test/ui/fmt/issue-89173.stderr b/src/test/ui/fmt/issue-89173.stderr
index 7b21e0a4fc8..ddeb769eadc 100644
--- a/src/test/ui/fmt/issue-89173.stderr
+++ b/src/test/ui/fmt/issue-89173.stderr
@@ -12,7 +12,7 @@ note: format specifiers use curly braces, and you have to use a positional or na
    |
 LL |     print!("%0*x", width, num);
    |             ^^^^
-   = note: printf formatting not supported; see the documentation for `std::fmt`
+   = note: printf formatting is not supported; see the documentation for `std::fmt`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-29723.rs b/src/test/ui/issues/issue-29723.rs
index ce91022f093..399e9ba0df7 100644
--- a/src/test/ui/issues/issue-29723.rs
+++ b/src/test/ui/issues/issue-29723.rs
@@ -1,5 +1,7 @@
 // test for https://github.com/rust-lang/rust/issues/29723
 
+#![feature(if_let_guard)]
+
 fn main() {
     let s = String::new();
     let _s = match 0 {
@@ -11,4 +13,10 @@ fn main() {
             //~^ ERROR use of moved value: `s`
         }
     };
+
+    let s = String::new();
+    let _s = match 0 {
+        0 if let Some(()) = { drop(s); None } => String::from("oops"),
+        _ => s //~ ERROR use of moved value: `s`
+    };
 }
diff --git a/src/test/ui/issues/issue-29723.stderr b/src/test/ui/issues/issue-29723.stderr
index 92ee5cf22b7..044d8a9b5dd 100644
--- a/src/test/ui/issues/issue-29723.stderr
+++ b/src/test/ui/issues/issue-29723.stderr
@@ -1,5 +1,5 @@
 error[E0382]: use of moved value: `s`
-  --> $DIR/issue-29723.rs:10:13
+  --> $DIR/issue-29723.rs:12:13
    |
 LL |     let s = String::new();
    |         - move occurs because `s` has type `String`, which does not implement the `Copy` trait
@@ -15,6 +15,22 @@ help: consider cloning the value if the performance cost is acceptable
 LL |         0 if { drop(s.clone()); false } => String::from("oops"),
    |                      ++++++++
 
-error: aborting due to previous error
+error[E0382]: use of moved value: `s`
+  --> $DIR/issue-29723.rs:20:14
+   |
+LL |     let s = String::new();
+   |         - move occurs because `s` has type `String`, which does not implement the `Copy` trait
+LL |     let _s = match 0 {
+LL |         0 if let Some(()) = { drop(s); None } => String::from("oops"),
+   |                                    - value moved here
+LL |         _ => s
+   |              ^ value used here after move
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |         0 if let Some(()) = { drop(s.clone()); None } => String::from("oops"),
+   |                                     ++++++++
+
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0382`.
diff --git a/src/test/ui/macros/format-foreign.stderr b/src/test/ui/macros/format-foreign.stderr
index ff5236dc949..7971c2ab2b9 100644
--- a/src/test/ui/macros/format-foreign.stderr
+++ b/src/test/ui/macros/format-foreign.stderr
@@ -8,7 +8,7 @@ LL |     println!("%.*3$s %s!\n", "Hello,", "World", 4);
    |              |               argument never used
    |              multiple missing formatting specifiers
    |
-   = note: printf formatting not supported; see the documentation for `std::fmt`
+   = note: printf formatting is not supported; see the documentation for `std::fmt`
 help: format specifiers use curly braces
    |
 LL |     println!("{:.2$} {}!\n", "Hello,", "World", 4);
@@ -22,7 +22,7 @@ LL |     println!("%1$*2$.*3$f", 123.456);
    |               |
    |               help: format specifiers use curly braces: `{0:1$.2$}`
    |
-   = note: printf formatting not supported; see the documentation for `std::fmt`
+   = note: printf formatting is not supported; see the documentation for `std::fmt`
 
 error: multiple unused formatting arguments
   --> $DIR/format-foreign.rs:6:7
@@ -37,7 +37,7 @@ LL | | "###, "Hello,", "World", 4);
    | |____|  argument never used
    |      multiple missing formatting specifiers
    |
-   = note: printf formatting not supported; see the documentation for `std::fmt`
+   = note: printf formatting is not supported; see the documentation for `std::fmt`
 help: format specifiers use curly braces
    |
 LL ~     println!(r###"{:.2$}
@@ -60,7 +60,7 @@ LL |     println!("Hi there, $NAME.", NAME="Tim");
    |                         |
    |                         help: format specifiers use curly braces: `{NAME}`
    |
-   = note: shell formatting not supported; see the documentation for `std::fmt`
+   = note: shell formatting is not supported; see the documentation for `std::fmt`
 
 error: multiple unused formatting arguments
   --> $DIR/format-foreign.rs:15:32
@@ -72,7 +72,7 @@ LL |     println!("$1 $0 $$ $NAME", 1, 2, NAME=3);
    |              |                 argument never used
    |              multiple missing formatting specifiers
    |
-   = note: shell formatting not supported; see the documentation for `std::fmt`
+   = note: shell formatting is not supported; see the documentation for `std::fmt`
 help: format specifiers use curly braces
    |
 LL |     println!("{1} {0} $$ {NAME}", 1, 2, NAME=3);
diff --git a/src/test/ui/macros/format-unused-lables.stderr b/src/test/ui/macros/format-unused-lables.stderr
index 7423c7b7c8b..fad87fa2aee 100644
--- a/src/test/ui/macros/format-unused-lables.stderr
+++ b/src/test/ui/macros/format-unused-lables.stderr
@@ -44,7 +44,7 @@ LL |        "things"
 LL |              , UNUSED="args");
    |                       ^^^^^^ named argument never used
    |
-   = note: shell formatting not supported; see the documentation for `std::fmt`
+   = note: shell formatting is not supported; see the documentation for `std::fmt`
 
 error: aborting due to 4 previous errors
 
diff --git a/src/test/ui/macros/issue-92267.stderr b/src/test/ui/macros/issue-92267.stderr
index d2d66c81198..5359f68cd55 100644
--- a/src/test/ui/macros/issue-92267.stderr
+++ b/src/test/ui/macros/issue-92267.stderr
@@ -10,7 +10,7 @@ note: format specifiers use curly braces, and the conversion specifier `
    |
 LL | pub fn main() { println!("🦀%%%", 0) }
    |                               ^^
-   = note: printf formatting not supported; see the documentation for `std::fmt`
+   = note: printf formatting is not supported; see the documentation for `std::fmt`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/nll/issue-24535-allow-mutable-borrow-in-match-guard.rs b/src/test/ui/nll/issue-24535-allow-mutable-borrow-in-match-guard.rs
index 7253d35ed2d..ccfc8937fd7 100644
--- a/src/test/ui/nll/issue-24535-allow-mutable-borrow-in-match-guard.rs
+++ b/src/test/ui/nll/issue-24535-allow-mutable-borrow-in-match-guard.rs
@@ -5,6 +5,8 @@
 // See further discussion on rust-lang/rust#24535,
 // rust-lang/rfcs#1006, and rust-lang/rfcs#107
 
+#![feature(if_let_guard)]
+
 fn main() {
     rust_issue_24535();
     rfcs_issue_1006_1();
@@ -23,6 +25,12 @@ fn rust_issue_24535() {
         3 if compare(&a, &mut 3) => (),
         _ => panic!("nope"),
     }
+
+    match a {
+        0 => panic!("nope"),
+        3 if let true = compare(&a, &mut 3) => (),
+        _ => panic!("nope"),
+    }
 }
 
 fn rfcs_issue_1006_1() {
diff --git a/src/test/ui/nll/issue-27282-move-match-input-into-guard.rs b/src/test/ui/nll/issue-27282-move-match-input-into-guard.rs
index 4109c10e2e4..85feda5824b 100644
--- a/src/test/ui/nll/issue-27282-move-match-input-into-guard.rs
+++ b/src/test/ui/nll/issue-27282-move-match-input-into-guard.rs
@@ -7,6 +7,8 @@
 // reaches the panic code when executed, despite the compiler warning
 // about that match arm being unreachable.
 
+#![feature(if_let_guard)]
+
 fn main() {
     let b = &mut true;
     match b {
@@ -17,4 +19,16 @@ fn main() {
         &mut true => { println!("You might think we should get here"); },
         _ => panic!("surely we could never get here, since rustc warns it is unreachable."),
     }
+
+    let b = &mut true;
+    match b {
+        //~^ ERROR use of moved value: `b` [E0382]
+        &mut false => {}
+        _ if let Some(()) = {
+            (|| { let bar = b; *bar = false; })();
+            None
+        } => {}
+        &mut true => {}
+        _ => {}
+    }
 }
diff --git a/src/test/ui/nll/issue-27282-move-match-input-into-guard.stderr b/src/test/ui/nll/issue-27282-move-match-input-into-guard.stderr
index 9be1a927999..ae797800457 100644
--- a/src/test/ui/nll/issue-27282-move-match-input-into-guard.stderr
+++ b/src/test/ui/nll/issue-27282-move-match-input-into-guard.stderr
@@ -1,5 +1,5 @@
 error[E0382]: use of moved value: `b`
-  --> $DIR/issue-27282-move-match-input-into-guard.rs:12:5
+  --> $DIR/issue-27282-move-match-input-into-guard.rs:14:5
    |
 LL |     let b = &mut true;
    |         - move occurs because `b` has type `&mut bool`, which does not implement the `Copy` trait
@@ -11,6 +11,19 @@ LL |         _ if { (|| { let bar = b; *bar = false; })();
    |                 |
    |                 value moved into closure here
 
-error: aborting due to previous error
+error[E0382]: use of moved value: `b`
+  --> $DIR/issue-27282-move-match-input-into-guard.rs:24:5
+   |
+LL |     let b = &mut true;
+   |         - move occurs because `b` has type `&mut bool`, which does not implement the `Copy` trait
+LL |     match b {
+   |     ^^^^^^^ value used here after move
+...
+LL |             (|| { let bar = b; *bar = false; })();
+   |              --             - variable moved due to use in closure
+   |              |
+   |              value moved into closure here
+
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0382`.
diff --git a/src/test/ui/nll/issue-27282-move-ref-mut-into-guard.rs b/src/test/ui/nll/issue-27282-move-ref-mut-into-guard.rs
index afa0ba780de..833ca8afd61 100644
--- a/src/test/ui/nll/issue-27282-move-ref-mut-into-guard.rs
+++ b/src/test/ui/nll/issue-27282-move-ref-mut-into-guard.rs
@@ -2,6 +2,8 @@
 // mutable borrows in match guards by hiding the mutable borrow in a
 // guard behind a move (of the ref mut pattern id) within a closure.
 
+#![feature(if_let_guard)]
+
 fn main() {
     match Some(&4) {
         None => {},
@@ -10,4 +12,12 @@ fn main() {
         //~^ ERROR cannot move out of `foo` in pattern guard [E0507]
         Some(s) => std::process::exit(*s),
     }
+
+    match Some(&4) {
+        None => {},
+        ref mut foo
+            if let Some(()) = { (|| { let bar = foo; bar.take() })(); None } => {},
+        //~^ ERROR cannot move out of `foo` in pattern guard [E0507]
+        Some(s) => std::process::exit(*s),
+    }
 }
diff --git a/src/test/ui/nll/issue-27282-move-ref-mut-into-guard.stderr b/src/test/ui/nll/issue-27282-move-ref-mut-into-guard.stderr
index a0d32616f83..45119018d4e 100644
--- a/src/test/ui/nll/issue-27282-move-ref-mut-into-guard.stderr
+++ b/src/test/ui/nll/issue-27282-move-ref-mut-into-guard.stderr
@@ -1,5 +1,5 @@
 error[E0507]: cannot move out of `foo` in pattern guard
-  --> $DIR/issue-27282-move-ref-mut-into-guard.rs:9:19
+  --> $DIR/issue-27282-move-ref-mut-into-guard.rs:11:19
    |
 LL |             if { (|| { let bar = foo; bar.take() })(); false } => {},
    |                   ^^             --- move occurs because `foo` has type `&mut Option<&i32>`, which does not implement the `Copy` trait
@@ -8,6 +8,16 @@ LL |             if { (|| { let bar = foo; bar.take() })(); false } => {},
    |
    = note: variables bound in patterns cannot be moved from until after the end of the pattern guard
 
-error: aborting due to previous error
+error[E0507]: cannot move out of `foo` in pattern guard
+  --> $DIR/issue-27282-move-ref-mut-into-guard.rs:19:34
+   |
+LL |             if let Some(()) = { (|| { let bar = foo; bar.take() })(); None } => {},
+   |                                  ^^             --- move occurs because `foo` has type `&mut Option<&i32>`, which does not implement the `Copy` trait
+   |                                  |
+   |                                  move out of `foo` occurs here
+   |
+   = note: variables bound in patterns cannot be moved from until after the end of the pattern guard
+
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0507`.
diff --git a/src/test/ui/nll/issue-27282-mutation-in-guard.rs b/src/test/ui/nll/issue-27282-mutation-in-guard.rs
index 395c7d214d0..4f41fc23fc3 100644
--- a/src/test/ui/nll/issue-27282-mutation-in-guard.rs
+++ b/src/test/ui/nll/issue-27282-mutation-in-guard.rs
@@ -1,3 +1,5 @@
+#![feature(if_let_guard)]
+
 fn main() {
     match Some(&4) {
         None => {},
@@ -10,4 +12,15 @@ fn main() {
         Some(ref _s) => println!("Note this arm is bogus; the `Some` became `None` in the guard."),
         _ => println!("Here is some supposedly unreachable code."),
     }
+
+    match Some(&4) {
+        None => {},
+        ref mut foo
+            if let Some(()) = {
+                (|| { let bar = foo; bar.take() })();
+                //~^ ERROR cannot move out of `foo` in pattern guard
+                None
+            } => {},
+        Some(_) => {},
+    }
 }
diff --git a/src/test/ui/nll/issue-27282-mutation-in-guard.stderr b/src/test/ui/nll/issue-27282-mutation-in-guard.stderr
index c4ce7e62fda..1ba696593af 100644
--- a/src/test/ui/nll/issue-27282-mutation-in-guard.stderr
+++ b/src/test/ui/nll/issue-27282-mutation-in-guard.stderr
@@ -1,5 +1,5 @@
 error[E0507]: cannot move out of `foo` in pattern guard
-  --> $DIR/issue-27282-mutation-in-guard.rs:6:18
+  --> $DIR/issue-27282-mutation-in-guard.rs:8:18
    |
 LL |                 (|| { let bar = foo; bar.take() })();
    |                  ^^             --- move occurs because `foo` has type `&mut Option<&i32>`, which does not implement the `Copy` trait
@@ -8,6 +8,16 @@ LL |                 (|| { let bar = foo; bar.take() })();
    |
    = note: variables bound in patterns cannot be moved from until after the end of the pattern guard
 
-error: aborting due to previous error
+error[E0507]: cannot move out of `foo` in pattern guard
+  --> $DIR/issue-27282-mutation-in-guard.rs:20:18
+   |
+LL |                 (|| { let bar = foo; bar.take() })();
+   |                  ^^             --- move occurs because `foo` has type `&mut Option<&i32>`, which does not implement the `Copy` trait
+   |                  |
+   |                  move out of `foo` occurs here
+   |
+   = note: variables bound in patterns cannot be moved from until after the end of the pattern guard
+
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0507`.
diff --git a/src/test/ui/nll/issue-27282-reborrow-ref-mut-in-guard.rs b/src/test/ui/nll/issue-27282-reborrow-ref-mut-in-guard.rs
index 82d8b9e9ed9..ac06b2b0102 100644
--- a/src/test/ui/nll/issue-27282-reborrow-ref-mut-in-guard.rs
+++ b/src/test/ui/nll/issue-27282-reborrow-ref-mut-in-guard.rs
@@ -3,7 +3,9 @@
 // It reborrows instead of moving the `ref mut` pattern borrow. This
 // means that our conservative check for mutation in guards will
 // reject it. But I want to make sure that we continue to reject it
-// (under NLL) even when that conservaive check goes away.
+// (under NLL) even when that conservative check goes away.
+
+#![feature(if_let_guard)]
 
 fn main() {
     let mut b = &mut true;
@@ -15,4 +17,14 @@ fn main() {
         &mut true => { println!("You might think we should get here"); },
         _ => panic!("surely we could never get here, since rustc warns it is unreachable."),
     }
+
+    let mut b = &mut true;
+    match b {
+        &mut false => {},
+        ref mut r if let Some(()) = { (|| { let bar = &mut *r; **bar = false; })();
+        //~^ ERROR cannot borrow `r` as mutable, as it is immutable for the pattern guard
+                             None } => { &mut *r; },
+        &mut true => {},
+        _ => {},
+    }
 }
diff --git a/src/test/ui/nll/issue-27282-reborrow-ref-mut-in-guard.stderr b/src/test/ui/nll/issue-27282-reborrow-ref-mut-in-guard.stderr
index 48433432de1..5eb7a25bf9f 100644
--- a/src/test/ui/nll/issue-27282-reborrow-ref-mut-in-guard.stderr
+++ b/src/test/ui/nll/issue-27282-reborrow-ref-mut-in-guard.stderr
@@ -1,5 +1,5 @@
 error[E0596]: cannot borrow `r` as mutable, as it is immutable for the pattern guard
-  --> $DIR/issue-27282-reborrow-ref-mut-in-guard.rs:12:25
+  --> $DIR/issue-27282-reborrow-ref-mut-in-guard.rs:14:25
    |
 LL |         ref mut r if { (|| { let bar = &mut *r; **bar = false; })();
    |                         ^^                  -- mutable borrow occurs due to use of `r` in closure
@@ -8,6 +8,16 @@ LL |         ref mut r if { (|| { let bar = &mut *r; **bar = false; })();
    |
    = note: variables bound in patterns are immutable until the end of the pattern guard
 
-error: aborting due to previous error
+error[E0596]: cannot borrow `r` as mutable, as it is immutable for the pattern guard
+  --> $DIR/issue-27282-reborrow-ref-mut-in-guard.rs:24:40
+   |
+LL |         ref mut r if let Some(()) = { (|| { let bar = &mut *r; **bar = false; })();
+   |                                        ^^                  -- mutable borrow occurs due to use of `r` in closure
+   |                                        |
+   |                                        cannot borrow as mutable
+   |
+   = note: variables bound in patterns are immutable until the end of the pattern guard
+
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0596`.
diff --git a/src/test/ui/nll/match-cfg-fake-edges.rs b/src/test/ui/nll/match-cfg-fake-edges.rs
index 252f7f8ba07..1afc7931a6b 100644
--- a/src/test/ui/nll/match-cfg-fake-edges.rs
+++ b/src/test/ui/nll/match-cfg-fake-edges.rs
@@ -1,6 +1,8 @@
 // Test that we have enough false edges to avoid exposing the exact matching
 // algorithm in borrow checking.
 
+#![feature(if_let_guard)]
+
 fn guard_always_precedes_arm(y: i32) {
     let mut x;
     // x should always be initialized, as the only way to reach the arm is
@@ -9,6 +11,12 @@ fn guard_always_precedes_arm(y: i32) {
         0 | 2 if { x = 2; true } => x,
         _ => 2,
     };
+
+    let mut x;
+    match y {
+        0 | 2 if let Some(()) = { x = 2; Some(()) } => x,
+        _ => 2,
+    };
 }
 
 fn guard_may_be_skipped(y: i32) {
@@ -23,6 +31,16 @@ fn guard_may_be_skipped(y: i32) {
         } => 2,
         _ => 3,
     };
+
+    let x;
+    match y {
+        _ if let Some(()) = { x = 2; Some(()) } => 1,
+        _ if let Some(()) = {
+            x; //~ ERROR E0381
+            None
+        } => 2,
+        _ => 3,
+    };
 }
 
 fn guard_may_be_taken(y: bool) {
@@ -37,6 +55,16 @@ fn guard_may_be_taken(y: bool) {
         }
         false => 3,
     };
+
+    let x = String::new();
+    match y {
+        false if let Some(()) = { drop(x); Some(()) } => 1,
+        true => {
+            x; //~ ERROR use of moved value: `x`
+            2
+        }
+        false => 3,
+    };
 }
 
 fn main() {}
diff --git a/src/test/ui/nll/match-cfg-fake-edges.stderr b/src/test/ui/nll/match-cfg-fake-edges.stderr
index f72ed3af718..a6261345cea 100644
--- a/src/test/ui/nll/match-cfg-fake-edges.stderr
+++ b/src/test/ui/nll/match-cfg-fake-edges.stderr
@@ -1,5 +1,5 @@
 error[E0381]: used binding `x` isn't initialized
-  --> $DIR/match-cfg-fake-edges.rs:21:13
+  --> $DIR/match-cfg-fake-edges.rs:29:13
    |
 LL |     let x;
    |         - binding declared here but left uninitialized
@@ -15,8 +15,25 @@ help: consider assigning a value
 LL |     let x = 0;
    |           +++
 
+error[E0381]: used binding `x` isn't initialized
+  --> $DIR/match-cfg-fake-edges.rs:39:13
+   |
+LL |     let x;
+   |         - binding declared here but left uninitialized
+LL |     match y {
+LL |         _ if let Some(()) = { x = 2; Some(()) } => 1,
+   |                               ----- binding initialized here in some conditions
+LL |         _ if let Some(()) = {
+LL |             x;
+   |             ^ `x` used here but it isn't initialized
+   |
+help: consider assigning a value
+   |
+LL |     let x = 0;
+   |           +++
+
 error[E0382]: use of moved value: `x`
-  --> $DIR/match-cfg-fake-edges.rs:35:13
+  --> $DIR/match-cfg-fake-edges.rs:53:13
    |
 LL |     let x = String::new();
    |         - move occurs because `x` has type `String`, which does not implement the `Copy` trait
@@ -32,7 +49,24 @@ help: consider cloning the value if the performance cost is acceptable
 LL |         false if { drop(x.clone()); true } => 1,
    |                          ++++++++
 
-error: aborting due to 2 previous errors
+error[E0382]: use of moved value: `x`
+  --> $DIR/match-cfg-fake-edges.rs:63:13
+   |
+LL |     let x = String::new();
+   |         - move occurs because `x` has type `String`, which does not implement the `Copy` trait
+LL |     match y {
+LL |         false if let Some(()) = { drop(x); Some(()) } => 1,
+   |                                        - value moved here
+LL |         true => {
+LL |             x;
+   |             ^ value used here after move
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |         false if let Some(()) = { drop(x.clone()); Some(()) } => 1,
+   |                                         ++++++++
+
+error: aborting due to 4 previous errors
 
 Some errors have detailed explanations: E0381, E0382.
 For more information about an error, try `rustc --explain E0381`.
diff --git a/src/test/ui/nll/match-guards-always-borrow.rs b/src/test/ui/nll/match-guards-always-borrow.rs
index 87dba187ba2..ff63cc09273 100644
--- a/src/test/ui/nll/match-guards-always-borrow.rs
+++ b/src/test/ui/nll/match-guards-always-borrow.rs
@@ -1,3 +1,5 @@
+#![feature(if_let_guard)]
+
 // Here is arielb1's basic example from rust-lang/rust#27282
 // that AST borrowck is flummoxed by:
 
@@ -10,6 +12,15 @@ fn should_reject_destructive_mutate_in_guard() {
             false } => { },
         Some(s) => std::process::exit(*s),
     }
+
+    match Some(&4) {
+        None => {},
+        ref mut foo if let Some(()) = {
+            (|| { let bar = foo; bar.take() })();
+            //~^ ERROR cannot move out of `foo` in pattern guard [E0507]
+            None } => { },
+        Some(s) => std::process::exit(*s),
+    }
 }
 
 // Here below is a case that needs to keep working: we only use the
@@ -18,7 +29,13 @@ fn should_reject_destructive_mutate_in_guard() {
 fn allow_mutate_in_arm_body() {
     match Some(&4) {
         None => {},
-        ref mut foo if foo.is_some() && false => { foo.take(); () }
+        ref mut foo if foo.is_some() => { foo.take(); () }
+        Some(s) => std::process::exit(*s),
+    }
+
+    match Some(&4) {
+        None => {},
+        ref mut foo if let Some(_) = foo => { foo.take(); () }
         Some(s) => std::process::exit(*s),
     }
 }
@@ -29,7 +46,13 @@ fn allow_mutate_in_arm_body() {
 fn allow_move_into_arm_body() {
     match Some(&4) {
         None => {},
-        mut foo if foo.is_some() && false => { foo.take(); () }
+        mut foo if foo.is_some() => { foo.unwrap(); () }
+        Some(s) => std::process::exit(*s),
+    }
+
+    match Some(&4) {
+        None => {},
+        mut foo if let Some(_) = foo => { foo.unwrap(); () }
         Some(s) => std::process::exit(*s),
     }
 }
diff --git a/src/test/ui/nll/match-guards-always-borrow.stderr b/src/test/ui/nll/match-guards-always-borrow.stderr
index c0fb5f65382..fa01d3a6fd1 100644
--- a/src/test/ui/nll/match-guards-always-borrow.stderr
+++ b/src/test/ui/nll/match-guards-always-borrow.stderr
@@ -1,5 +1,5 @@
 error[E0507]: cannot move out of `foo` in pattern guard
-  --> $DIR/match-guards-always-borrow.rs:8:14
+  --> $DIR/match-guards-always-borrow.rs:10:14
    |
 LL |             (|| { let bar = foo; bar.take() })();
    |              ^^             --- move occurs because `foo` has type `&mut Option<&i32>`, which does not implement the `Copy` trait
@@ -8,6 +8,16 @@ LL |             (|| { let bar = foo; bar.take() })();
    |
    = note: variables bound in patterns cannot be moved from until after the end of the pattern guard
 
-error: aborting due to previous error
+error[E0507]: cannot move out of `foo` in pattern guard
+  --> $DIR/match-guards-always-borrow.rs:19:14
+   |
+LL |             (|| { let bar = foo; bar.take() })();
+   |              ^^             --- move occurs because `foo` has type `&mut Option<&i32>`, which does not implement the `Copy` trait
+   |              |
+   |              move out of `foo` occurs here
+   |
+   = note: variables bound in patterns cannot be moved from until after the end of the pattern guard
+
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0507`.
diff --git a/src/test/ui/nll/match-guards-partially-borrow.rs b/src/test/ui/nll/match-guards-partially-borrow.rs
index 81ae19ebf8a..3a9e1654b1c 100644
--- a/src/test/ui/nll/match-guards-partially-borrow.rs
+++ b/src/test/ui/nll/match-guards-partially-borrow.rs
@@ -5,7 +5,9 @@
 // Test that we don't allow mutating the value being matched on in a way that
 // changes which patterns it matches, until we have chosen an arm.
 
-fn ok_mutation_in_guard(mut q: i32) {
+#![feature(if_let_guard)]
+
+fn ok_mutation_in_if_guard(mut q: i32) {
     match q {
         // OK, mutation doesn't change which patterns g matches
         _ if { q = 1; false } => (),
@@ -13,7 +15,15 @@ fn ok_mutation_in_guard(mut q: i32) {
     }
 }
 
-fn ok_mutation_in_guard2(mut u: bool) {
+fn ok_mutation_in_if_let_guard(mut q: i32) {
+    match q {
+        // OK, mutation doesn't change which patterns g matches
+        _ if let Some(()) = { q = 1; None } => (),
+        _ => (),
+    }
+}
+
+fn ok_mutation_in_if_guard2(mut u: bool) {
     // OK value of u is unused before modification
     match u {
         _ => (),
@@ -25,7 +35,19 @@ fn ok_mutation_in_guard2(mut u: bool) {
     }
 }
 
-fn ok_mutation_in_guard4(mut w: (&mut bool,)) {
+fn ok_mutation_in_if_let_guard2(mut u: bool) {
+    // OK value of u is unused before modification
+    match u {
+        _ => (),
+        _ if let Some(()) = {
+            u = true;
+            None
+        } => (),
+        x => (),
+    }
+}
+
+fn ok_mutation_in_if_guard4(mut w: (&mut bool,)) {
     // OK value of u is unused before modification
     match w {
         _ => (),
@@ -37,7 +59,19 @@ fn ok_mutation_in_guard4(mut w: (&mut bool,)) {
     }
 }
 
-fn ok_indirect_mutation_in_guard(mut p: &bool) {
+fn ok_mutation_in_if_let_guard4(mut w: (&mut bool,)) {
+    // OK value of u is unused before modification
+    match w {
+        _ => (),
+        _ if let Some(()) = {
+            *w.0 = true;
+            None
+        } => (),
+        x => (),
+    }
+}
+
+fn ok_indirect_mutation_in_if_guard(mut p: &bool) {
     match *p {
         // OK, mutation doesn't change which patterns s matches
         _ if {
@@ -48,7 +82,18 @@ fn ok_indirect_mutation_in_guard(mut p: &bool) {
     }
 }
 
-fn mutation_invalidates_pattern_in_guard(mut q: bool) {
+fn ok_indirect_mutation_in_if_let_guard(mut p: &bool) {
+    match *p {
+        // OK, mutation doesn't change which patterns s matches
+        _ if let Some(()) = {
+            p = &true;
+            None
+        } => (),
+        _ => (),
+    }
+}
+
+fn mutation_invalidates_pattern_in_if_guard(mut q: bool) {
     match q {
         // q doesn't match the pattern with the guard by the end of the guard.
         false if {
@@ -59,7 +104,18 @@ fn mutation_invalidates_pattern_in_guard(mut q: bool) {
     }
 }
 
-fn mutation_invalidates_previous_pattern_in_guard(mut r: bool) {
+fn mutation_invalidates_pattern_in_if_let_guard(mut q: bool) {
+    match q {
+        // q doesn't match the pattern with the guard by the end of the guard.
+        false if let Some(()) = {
+            q = true; //~ ERROR
+            Some(())
+        } => (),
+        _ => (),
+    }
+}
+
+fn mutation_invalidates_previous_pattern_in_if_guard(mut r: bool) {
     match r {
         // r matches a previous pattern by the end of the guard.
         true => (),
@@ -71,7 +127,19 @@ fn mutation_invalidates_previous_pattern_in_guard(mut r: bool) {
     }
 }
 
-fn match_on_borrowed_early_end(mut s: bool) {
+fn mutation_invalidates_previous_pattern_in_if_let_guard(mut r: bool) {
+    match r {
+        // r matches a previous pattern by the end of the guard.
+        true => (),
+        _ if let Some(()) = {
+            r = true; //~ ERROR
+            Some(())
+        } => (),
+        _ => (),
+    }
+}
+
+fn match_on_borrowed_early_end_if_guard(mut s: bool) {
     let h = &mut s;
     // OK value of s is unused before modification.
     match s {
@@ -84,7 +152,20 @@ fn match_on_borrowed_early_end(mut s: bool) {
     }
 }
 
-fn bad_mutation_in_guard(mut t: bool) {
+fn match_on_borrowed_early_end_if_let_guard(mut s: bool) {
+    let h = &mut s;
+    // OK value of s is unused before modification.
+    match s {
+        _ if let Some(()) = {
+            *h = !*h;
+            None
+        } => (),
+        true => (),
+        false => (),
+    }
+}
+
+fn bad_mutation_in_if_guard(mut t: bool) {
     match t {
         true => (),
         false if {
@@ -95,7 +176,18 @@ fn bad_mutation_in_guard(mut t: bool) {
     }
 }
 
-fn bad_mutation_in_guard2(mut x: Option<Option<&i32>>) {
+fn bad_mutation_in_if_let_guard(mut t: bool) {
+    match t {
+        true => (),
+        false if let Some(()) = {
+            t = true; //~ ERROR
+            None
+        } => (),
+        false => (),
+    }
+}
+
+fn bad_mutation_in_if_guard2(mut x: Option<Option<&i32>>) {
     // Check that nested patterns are checked.
     match x {
         None => (),
@@ -111,7 +203,23 @@ fn bad_mutation_in_guard2(mut x: Option<Option<&i32>>) {
     }
 }
 
-fn bad_mutation_in_guard3(mut t: bool) {
+fn bad_mutation_in_if_let_guard2(mut x: Option<Option<&i32>>) {
+    // Check that nested patterns are checked.
+    match x {
+        None => (),
+        Some(None) => (),
+        _ if let Some(()) = {
+            match x {
+                Some(ref mut r) => *r = None, //~ ERROR
+                _ => return,
+            };
+            None
+        } => (),
+        Some(Some(r)) => println!("{}", r),
+    }
+}
+
+fn bad_mutation_in_if_guard3(mut t: bool) {
     match t {
         s if {
             t = !t; //~ ERROR
@@ -121,7 +229,17 @@ fn bad_mutation_in_guard3(mut t: bool) {
     }
 }
 
-fn bad_indirect_mutation_in_guard(mut y: &bool) {
+fn bad_mutation_in_if_let_guard3(mut t: bool) {
+    match t {
+        s if let Some(()) = {
+            t = !t; //~ ERROR
+            None
+        } => (), // What value should `s` have in the arm?
+        _ => (),
+    }
+}
+
+fn bad_indirect_mutation_in_if_guard(mut y: &bool) {
     match *y {
         true => (),
         false if {
@@ -132,7 +250,18 @@ fn bad_indirect_mutation_in_guard(mut y: &bool) {
     }
 }
 
-fn bad_indirect_mutation_in_guard2(mut z: &bool) {
+fn bad_indirect_mutation_in_if_let_guard(mut y: &bool) {
+    match *y {
+        true => (),
+        false if let Some(()) = {
+            y = &true; //~ ERROR
+            None
+        } => (),
+        false => (),
+    }
+}
+
+fn bad_indirect_mutation_in_if_guard2(mut z: &bool) {
     match z {
         &true => (),
         &false if {
@@ -143,8 +272,19 @@ fn bad_indirect_mutation_in_guard2(mut z: &bool) {
     }
 }
 
-fn bad_indirect_mutation_in_guard3(mut a: &bool) {
-    // Same as bad_indirect_mutation_in_guard2, but using match ergonomics
+fn bad_indirect_mutation_in_if_let_guard2(mut z: &bool) {
+    match z {
+        &true => (),
+        &false if let Some(()) = {
+            z = &true; //~ ERROR
+            None
+        } => (),
+        &false => (),
+    }
+}
+
+fn bad_indirect_mutation_in_if_guard3(mut a: &bool) {
+    // Same as bad_indirect_mutation_in_if_guard2, but using match ergonomics
     match a {
         true => (),
         false if {
@@ -155,7 +295,19 @@ fn bad_indirect_mutation_in_guard3(mut a: &bool) {
     }
 }
 
-fn bad_indirect_mutation_in_guard4(mut b: &bool) {
+fn bad_indirect_mutation_in_if_let_guard3(mut a: &bool) {
+    // Same as bad_indirect_mutation_in_if_guard2, but using match ergonomics
+    match a {
+        true => (),
+        false if let Some(()) = {
+            a = &true; //~ ERROR
+            None
+        } => (),
+        false => (),
+    }
+}
+
+fn bad_indirect_mutation_in_if_guard4(mut b: &bool) {
     match b {
         &_ => (),
         &_ if {
@@ -166,4 +318,15 @@ fn bad_indirect_mutation_in_guard4(mut b: &bool) {
     }
 }
 
+fn bad_indirect_mutation_in_if_let_guard4(mut b: &bool) {
+    match b {
+        &_ => (),
+        &_ if let Some(()) = {
+            b = &true; //~ ERROR
+            None
+        } => (),
+        &b => (),
+    }
+}
+
 fn main() {}
diff --git a/src/test/ui/nll/match-guards-partially-borrow.stderr b/src/test/ui/nll/match-guards-partially-borrow.stderr
index 48e3a7c6993..60b8dee71a8 100644
--- a/src/test/ui/nll/match-guards-partially-borrow.stderr
+++ b/src/test/ui/nll/match-guards-partially-borrow.stderr
@@ -1,5 +1,5 @@
 error[E0510]: cannot assign `q` in match guard
-  --> $DIR/match-guards-partially-borrow.rs:55:13
+  --> $DIR/match-guards-partially-borrow.rs:100:13
    |
 LL |     match q {
    |           - value is immutable in match guard
@@ -7,8 +7,26 @@ LL |     match q {
 LL |             q = true;
    |             ^^^^^^^^ cannot assign
 
+error[E0510]: cannot assign `q` in match guard
+  --> $DIR/match-guards-partially-borrow.rs:111:13
+   |
+LL |     match q {
+   |           - value is immutable in match guard
+...
+LL |             q = true;
+   |             ^^^^^^^^ cannot assign
+
+error[E0510]: cannot assign `r` in match guard
+  --> $DIR/match-guards-partially-borrow.rs:123:13
+   |
+LL |     match r {
+   |           - value is immutable in match guard
+...
+LL |             r = true;
+   |             ^^^^^^^^ cannot assign
+
 error[E0510]: cannot assign `r` in match guard
-  --> $DIR/match-guards-partially-borrow.rs:67:13
+  --> $DIR/match-guards-partially-borrow.rs:135:13
    |
 LL |     match r {
    |           - value is immutable in match guard
@@ -17,7 +35,16 @@ LL |             r = true;
    |             ^^^^^^^^ cannot assign
 
 error[E0510]: cannot assign `t` in match guard
-  --> $DIR/match-guards-partially-borrow.rs:91:13
+  --> $DIR/match-guards-partially-borrow.rs:172:13
+   |
+LL |     match t {
+   |           - value is immutable in match guard
+...
+LL |             t = true;
+   |             ^^^^^^^^ cannot assign
+
+error[E0510]: cannot assign `t` in match guard
+  --> $DIR/match-guards-partially-borrow.rs:183:13
    |
 LL |     match t {
    |           - value is immutable in match guard
@@ -26,7 +53,16 @@ LL |             t = true;
    |             ^^^^^^^^ cannot assign
 
 error[E0510]: cannot mutably borrow `x.0` in match guard
-  --> $DIR/match-guards-partially-borrow.rs:105:22
+  --> $DIR/match-guards-partially-borrow.rs:197:22
+   |
+LL |     match x {
+   |           - value is immutable in match guard
+...
+LL |                 Some(ref mut r) => *r = None,
+   |                      ^^^^^^^^^ cannot mutably borrow
+
+error[E0510]: cannot mutably borrow `x.0` in match guard
+  --> $DIR/match-guards-partially-borrow.rs:213:22
    |
 LL |     match x {
    |           - value is immutable in match guard
@@ -35,7 +71,7 @@ LL |                 Some(ref mut r) => *r = None,
    |                      ^^^^^^^^^ cannot mutably borrow
 
 error[E0506]: cannot assign to `t` because it is borrowed
-  --> $DIR/match-guards-partially-borrow.rs:117:13
+  --> $DIR/match-guards-partially-borrow.rs:225:13
    |
 LL |         s if {
    |         - borrow of `t` occurs here
@@ -45,8 +81,28 @@ LL |             false
 LL |         } => (), // What value should `s` have in the arm?
    |         - borrow later used here
 
+error[E0506]: cannot assign to `t` because it is borrowed
+  --> $DIR/match-guards-partially-borrow.rs:235:13
+   |
+LL |         s if let Some(()) = {
+   |         - borrow of `t` occurs here
+LL |             t = !t;
+   |             ^^^^^^ assignment to borrowed `t` occurs here
+LL |             None
+LL |         } => (), // What value should `s` have in the arm?
+   |         - borrow later used here
+
+error[E0510]: cannot assign `y` in match guard
+  --> $DIR/match-guards-partially-borrow.rs:246:13
+   |
+LL |     match *y {
+   |           -- value is immutable in match guard
+...
+LL |             y = &true;
+   |             ^^^^^^^^^ cannot assign
+
 error[E0510]: cannot assign `y` in match guard
-  --> $DIR/match-guards-partially-borrow.rs:128:13
+  --> $DIR/match-guards-partially-borrow.rs:257:13
    |
 LL |     match *y {
    |           -- value is immutable in match guard
@@ -55,7 +111,16 @@ LL |             y = &true;
    |             ^^^^^^^^^ cannot assign
 
 error[E0510]: cannot assign `z` in match guard
-  --> $DIR/match-guards-partially-borrow.rs:139:13
+  --> $DIR/match-guards-partially-borrow.rs:268:13
+   |
+LL |     match z {
+   |           - value is immutable in match guard
+...
+LL |             z = &true;
+   |             ^^^^^^^^^ cannot assign
+
+error[E0510]: cannot assign `z` in match guard
+  --> $DIR/match-guards-partially-borrow.rs:279:13
    |
 LL |     match z {
    |           - value is immutable in match guard
@@ -64,7 +129,16 @@ LL |             z = &true;
    |             ^^^^^^^^^ cannot assign
 
 error[E0510]: cannot assign `a` in match guard
-  --> $DIR/match-guards-partially-borrow.rs:151:13
+  --> $DIR/match-guards-partially-borrow.rs:291:13
+   |
+LL |     match a {
+   |           - value is immutable in match guard
+...
+LL |             a = &true;
+   |             ^^^^^^^^^ cannot assign
+
+error[E0510]: cannot assign `a` in match guard
+  --> $DIR/match-guards-partially-borrow.rs:303:13
    |
 LL |     match a {
    |           - value is immutable in match guard
@@ -73,7 +147,16 @@ LL |             a = &true;
    |             ^^^^^^^^^ cannot assign
 
 error[E0510]: cannot assign `b` in match guard
-  --> $DIR/match-guards-partially-borrow.rs:162:13
+  --> $DIR/match-guards-partially-borrow.rs:314:13
+   |
+LL |     match b {
+   |           - value is immutable in match guard
+...
+LL |             b = &true;
+   |             ^^^^^^^^^ cannot assign
+
+error[E0510]: cannot assign `b` in match guard
+  --> $DIR/match-guards-partially-borrow.rs:325:13
    |
 LL |     match b {
    |           - value is immutable in match guard
@@ -81,7 +164,7 @@ LL |     match b {
 LL |             b = &true;
    |             ^^^^^^^^^ cannot assign
 
-error: aborting due to 9 previous errors
+error: aborting due to 18 previous errors
 
 Some errors have detailed explanations: E0506, E0510.
 For more information about an error, try `rustc --explain E0506`.
diff --git a/src/test/ui/rfc-0107-bind-by-move-pattern-guards/rfc-reject-double-move-across-arms.rs b/src/test/ui/rfc-0107-bind-by-move-pattern-guards/rfc-reject-double-move-across-arms.rs
index d1f685f3e7a..6f0d2b04591 100644
--- a/src/test/ui/rfc-0107-bind-by-move-pattern-guards/rfc-reject-double-move-across-arms.rs
+++ b/src/test/ui/rfc-0107-bind-by-move-pattern-guards/rfc-reject-double-move-across-arms.rs
@@ -1,6 +1,8 @@
+#![feature(if_let_guard)]
+
 enum VecWrapper { A(Vec<i32>) }
 
-fn foo(x: VecWrapper) -> usize {
+fn if_guard(x: VecWrapper) -> usize {
     match x {
         VecWrapper::A(v) if { drop(v); false } => 1,
         //~^ ERROR cannot move out of `v` in pattern guard
@@ -8,6 +10,15 @@ fn foo(x: VecWrapper) -> usize {
     }
 }
 
+fn if_let_guard(x: VecWrapper) -> usize {
+    match x {
+        VecWrapper::A(v) if let Some(()) = { drop(v); None } => 1,
+        //~^ ERROR cannot move out of `v` in pattern guard
+        VecWrapper::A(v) => v.len()
+    }
+}
+
 fn main() {
-    foo(VecWrapper::A(vec![107]));
+    if_guard(VecWrapper::A(vec![107]));
+    if_let_guard(VecWrapper::A(vec![107]));
 }
diff --git a/src/test/ui/rfc-0107-bind-by-move-pattern-guards/rfc-reject-double-move-across-arms.stderr b/src/test/ui/rfc-0107-bind-by-move-pattern-guards/rfc-reject-double-move-across-arms.stderr
index 6c3d1caf807..a749361bf30 100644
--- a/src/test/ui/rfc-0107-bind-by-move-pattern-guards/rfc-reject-double-move-across-arms.stderr
+++ b/src/test/ui/rfc-0107-bind-by-move-pattern-guards/rfc-reject-double-move-across-arms.stderr
@@ -1,11 +1,19 @@
 error[E0507]: cannot move out of `v` in pattern guard
-  --> $DIR/rfc-reject-double-move-across-arms.rs:5:36
+  --> $DIR/rfc-reject-double-move-across-arms.rs:7:36
    |
 LL |         VecWrapper::A(v) if { drop(v); false } => 1,
    |                                    ^ move occurs because `v` has type `Vec<i32>`, which does not implement the `Copy` trait
    |
    = note: variables bound in patterns cannot be moved from until after the end of the pattern guard
 
-error: aborting due to previous error
+error[E0507]: cannot move out of `v` in pattern guard
+  --> $DIR/rfc-reject-double-move-across-arms.rs:15:51
+   |
+LL |         VecWrapper::A(v) if let Some(()) = { drop(v); None } => 1,
+   |                                                   ^ move occurs because `v` has type `Vec<i32>`, which does not implement the `Copy` trait
+   |
+   = note: variables bound in patterns cannot be moved from until after the end of the pattern guard
+
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0507`.
diff --git a/src/test/ui/rfc-0107-bind-by-move-pattern-guards/rfc-reject-double-move-in-first-arm.rs b/src/test/ui/rfc-0107-bind-by-move-pattern-guards/rfc-reject-double-move-in-first-arm.rs
index 571f51c9001..827335f6a84 100644
--- a/src/test/ui/rfc-0107-bind-by-move-pattern-guards/rfc-reject-double-move-in-first-arm.rs
+++ b/src/test/ui/rfc-0107-bind-by-move-pattern-guards/rfc-reject-double-move-in-first-arm.rs
@@ -1,6 +1,8 @@
+#![feature(if_let_guard)]
+
 struct A { a: Box<i32> }
 
-fn foo(n: i32) {
+fn if_guard(n: i32) {
     let x = A { a: Box::new(n) };
     let _y = match x {
         A { a: v } if { drop(v); true } => v,
@@ -9,6 +11,16 @@ fn foo(n: i32) {
     };
 }
 
+fn if_let_guard(n: i32) {
+    let x = A { a: Box::new(n) };
+    let _y = match x {
+        A { a: v } if let Some(()) = { drop(v); Some(()) } => v,
+        //~^ ERROR cannot move out of `v` in pattern guard
+        _ => Box::new(0),
+    };
+}
+
 fn main() {
-    foo(107);
+    if_guard(107);
+    if_let_guard(107);
 }
diff --git a/src/test/ui/rfc-0107-bind-by-move-pattern-guards/rfc-reject-double-move-in-first-arm.stderr b/src/test/ui/rfc-0107-bind-by-move-pattern-guards/rfc-reject-double-move-in-first-arm.stderr
index d1204bc2601..9285492b224 100644
--- a/src/test/ui/rfc-0107-bind-by-move-pattern-guards/rfc-reject-double-move-in-first-arm.stderr
+++ b/src/test/ui/rfc-0107-bind-by-move-pattern-guards/rfc-reject-double-move-in-first-arm.stderr
@@ -1,11 +1,19 @@
 error[E0507]: cannot move out of `v` in pattern guard
-  --> $DIR/rfc-reject-double-move-in-first-arm.rs:6:30
+  --> $DIR/rfc-reject-double-move-in-first-arm.rs:8:30
    |
 LL |         A { a: v } if { drop(v); true } => v,
    |                              ^ move occurs because `v` has type `Box<i32>`, which does not implement the `Copy` trait
    |
    = note: variables bound in patterns cannot be moved from until after the end of the pattern guard
 
-error: aborting due to previous error
+error[E0507]: cannot move out of `v` in pattern guard
+  --> $DIR/rfc-reject-double-move-in-first-arm.rs:17:45
+   |
+LL |         A { a: v } if let Some(()) = { drop(v); Some(()) } => v,
+   |                                             ^ move occurs because `v` has type `Box<i32>`, which does not implement the `Copy` trait
+   |
+   = note: variables bound in patterns cannot be moved from until after the end of the pattern guard
+
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0507`.
diff --git a/src/test/ui/thir-tree.stdout b/src/test/ui/thir-tree.stdout
index 7fb90581f8a..4b6915f7715 100644
--- a/src/test/ui/thir-tree.stdout
+++ b/src/test/ui/thir-tree.stdout
@@ -32,12 +32,7 @@ Thir {
             kind: Scope {
                 region_scope: Node(2),
                 lint_level: Explicit(
-                    HirId {
-                        owner: OwnerId {
-                            def_id: DefId(0:3 ~ thir_tree[8f1d]::main),
-                        },
-                        local_id: 2,
-                    },
+                    HirId(DefId(0:3 ~ thir_tree[8f1d]::main).2),
                 ),
                 value: e0,
             },
diff --git a/src/tools/jsondoclint/src/validator.rs b/src/tools/jsondoclint/src/validator.rs
index e15f5fe3ccc..291d02d67bd 100644
--- a/src/tools/jsondoclint/src/validator.rs
+++ b/src/tools/jsondoclint/src/validator.rs
@@ -5,7 +5,7 @@ use rustdoc_json_types::{
     Constant, Crate, DynTrait, Enum, FnDecl, Function, FunctionPointer, GenericArg, GenericArgs,
     GenericBound, GenericParamDef, Generics, Id, Impl, Import, ItemEnum, Module, OpaqueTy, Path,
     Primitive, ProcMacro, Static, Struct, StructKind, Term, Trait, TraitAlias, Type, TypeBinding,
-    TypeBindingKind, Typedef, Union, Variant, WherePredicate,
+    TypeBindingKind, Typedef, Union, Variant, VariantKind, WherePredicate,
 };
 
 use crate::{item_kind::Kind, Error, ErrorKind};
@@ -140,24 +140,24 @@ impl<'a> Validator<'a> {
     }
 
     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
-                            )),
-                        );
-                    }
-                }
+        let Variant { kind, discriminant } = x;
+
+        if let Some(discr) = discriminant {
+            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: _ } => {
+        }
+
+        match kind {
+            VariantKind::Plain => {}
+            VariantKind::Tuple(tys) => tys.iter().flatten().for_each(|t| self.add_field_id(t)),
+            VariantKind::Struct { fields, fields_stripped: _ } => {
                 fields.iter().for_each(|f| self.add_field_id(f))
             }
         }
diff --git a/src/tools/miri/src/lib.rs b/src/tools/miri/src/lib.rs
index 97750cb78cd..7024927b205 100644
--- a/src/tools/miri/src/lib.rs
+++ b/src/tools/miri/src/lib.rs
@@ -54,6 +54,11 @@ extern crate rustc_session;
 extern crate rustc_span;
 extern crate rustc_target;
 
+// Necessary to pull in object code as the rest of the rustc crates are shipped only as rmeta
+// files.
+#[allow(unused_extern_crates)]
+extern crate rustc_driver;
+
 mod borrow_tracker;
 mod clock;
 mod concurrency;
diff --git a/src/tools/rustfmt/src/lib.rs b/src/tools/rustfmt/src/lib.rs
index 1d1ef525f23..0c27bcacfb8 100644
--- a/src/tools/rustfmt/src/lib.rs
+++ b/src/tools/rustfmt/src/lib.rs
@@ -24,6 +24,11 @@ extern crate rustc_parse;
 extern crate rustc_session;
 extern crate rustc_span;
 
+// Necessary to pull in object code as the rest of the rustc crates are shipped only as rmeta
+// files.
+#[allow(unused_extern_crates)]
+extern crate rustc_driver;
+
 use std::cell::RefCell;
 use std::collections::HashMap;
 use std::fmt;
diff --git a/src/tools/tidy/Cargo.toml b/src/tools/tidy/Cargo.toml
index fff83a1d097..5f5ae3a65ef 100644
--- a/src/tools/tidy/Cargo.toml
+++ b/src/tools/tidy/Cargo.toml
@@ -11,6 +11,7 @@ miropt-test-tools = { path = "../miropt-test-tools" }
 lazy_static = "1"
 walkdir = "2"
 ignore = "0.4.18"
+semver = "1.0.14"
 termcolor = "1.1.3"
 
 [[bin]]
diff --git a/src/tools/tidy/src/lib.rs b/src/tools/tidy/src/lib.rs
index ce7e7ac5cd4..4075f2616b0 100644
--- a/src/tools/tidy/src/lib.rs
+++ b/src/tools/tidy/src/lib.rs
@@ -69,3 +69,4 @@ pub mod ui_tests;
 pub mod unit_tests;
 pub mod unstable_book;
 pub mod walk;
+pub mod x_version;
diff --git a/src/tools/tidy/src/main.rs b/src/tools/tidy/src/main.rs
index 6714c63ee62..7bb8ddc6949 100644
--- a/src/tools/tidy/src/main.rs
+++ b/src/tools/tidy/src/main.rs
@@ -58,7 +58,7 @@ fn main() {
 
                 let handle = s.spawn(|| {
                     let mut flag = false;
-                    $p::check($($args),* , &mut flag);
+                    $p::check($($args, )* &mut flag);
                     if (flag) {
                         bad.store(true, Ordering::Relaxed);
                     }
@@ -107,6 +107,8 @@ fn main() {
         check!(alphabetical, &compiler_path);
         check!(alphabetical, &library_path);
 
+        check!(x_version, &root_path, &cargo);
+
         let collected = {
             drain_handles(&mut handles);
 
diff --git a/src/tools/tidy/src/x_version.rs b/src/tools/tidy/src/x_version.rs
new file mode 100644
index 00000000000..5dc6a0588c3
--- /dev/null
+++ b/src/tools/tidy/src/x_version.rs
@@ -0,0 +1,65 @@
+use semver::Version;
+use std::io::ErrorKind;
+use std::path::Path;
+use std::process::{Command, Stdio};
+
+pub fn check(root: &Path, cargo: &Path, bad: &mut bool) {
+    let result = Command::new("x").arg("--wrapper-version").stdout(Stdio::piped()).spawn();
+    // This runs the command inside a temporary directory.
+    // This allows us to compare output of result to see if `--wrapper-version` is not a recognized argument to x.
+    let temp_result = Command::new("x")
+        .arg("--wrapper-version")
+        .current_dir(std::env::temp_dir())
+        .stdout(Stdio::piped())
+        .spawn();
+
+    let (child, temp_child) = match (result, temp_result) {
+        (Ok(child), Ok(temp_child)) => (child, temp_child),
+        (Err(e), _) | (_, Err(e)) => match e.kind() {
+            ErrorKind::NotFound => return,
+            _ => return tidy_error!(bad, "failed to run `x`: {}", e),
+        },
+    };
+
+    let output = child.wait_with_output().unwrap();
+    let temp_output = temp_child.wait_with_output().unwrap();
+
+    if output != temp_output {
+        return tidy_error!(
+            bad,
+            "Current version of x does not support the `--wrapper-version` argument\nConsider updating to the newer version of x by running `cargo install --path src/tools/x`"
+        );
+    }
+
+    if output.status.success() {
+        let version = String::from_utf8_lossy(&output.stdout);
+        let version = Version::parse(version.trim_end()).unwrap();
+
+        if let Some(expected) = get_x_wrapper_version(root, cargo) {
+            if version < expected {
+                return tidy_error!(
+                    bad,
+                    "Current version of x is {version}, but the latest version is {expected}\nConsider updating to the newer version of x by running `cargo install --path src/tools/x`"
+                );
+            }
+        } else {
+            return tidy_error!(
+                bad,
+                "Unable to parse the latest version of `x` at `src/tools/x/Cargo.toml`"
+            );
+        }
+    } else {
+        return tidy_error!(bad, "failed to check version of `x`: {}", output.status);
+    }
+}
+
+// Parse latest version out of `x` Cargo.toml
+fn get_x_wrapper_version(root: &Path, cargo: &Path) -> Option<Version> {
+    let mut cmd = cargo_metadata::MetadataCommand::new();
+    cmd.cargo_path(cargo)
+        .manifest_path(root.join("src/tools/x/Cargo.toml"))
+        .no_deps()
+        .features(cargo_metadata::CargoOpt::AllFeatures);
+    let mut metadata = t!(cmd.exec());
+    metadata.packages.pop().map(|x| x.version)
+}
diff --git a/src/tools/x/src/main.rs b/src/tools/x/src/main.rs
index f07ff43efe9..01f7187851e 100644
--- a/src/tools/x/src/main.rs
+++ b/src/tools/x/src/main.rs
@@ -52,6 +52,14 @@ fn exec_or_status(command: &mut Command) -> io::Result<ExitStatus> {
 }
 
 fn main() {
+    match env::args().skip(1).next().as_deref() {
+        Some("--wrapper-version") => {
+            let version = env!("CARGO_PKG_VERSION");
+            println!("{}", version);
+            return;
+        }
+        _ => {}
+    }
     let current = match env::current_dir() {
         Ok(dir) => dir,
         Err(err) => {