diff --git a/Cargo.lock b/Cargo.lock
index 4421e526d10..ff21d5f8c08 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -4525,6 +4525,7 @@ dependencies = [
  "rustc_middle",
  "rustc_span",
  "rustc_target",
+ "scoped-tls",
  "stable_mir",
  "tracing",
 ]
diff --git a/compiler/rustc_attr/messages.ftl b/compiler/rustc_attr/messages.ftl
index e6cbbaf3704..7281282fec3 100644
--- a/compiler/rustc_attr/messages.ftl
+++ b/compiler/rustc_attr/messages.ftl
@@ -58,6 +58,9 @@ attr_invalid_repr_hint_no_paren =
 attr_invalid_repr_hint_no_value =
     invalid representation hint: `{$name}` does not take a value
 
+attr_invalid_since =
+    'since' must be a Rust version number, such as "1.31.0"
+
 attr_missing_feature =
     missing 'feature'
 
diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs
index 60eacde1c72..44ba495721d 100644
--- a/compiler/rustc_attr/src/builtin.rs
+++ b/compiler/rustc_attr/src/builtin.rs
@@ -3,6 +3,7 @@
 use rustc_ast::{self as ast, attr};
 use rustc_ast::{Attribute, LitKind, MetaItem, MetaItemKind, MetaItemLit, NestedMetaItem, NodeId};
 use rustc_ast_pretty::pprust;
+use rustc_errors::ErrorGuaranteed;
 use rustc_feature::{find_gated_cfg, is_builtin_attr_name, Features, GatedCfg};
 use rustc_macros::HashStable_Generic;
 use rustc_session::config::ExpectedValues;
@@ -361,25 +362,32 @@ fn parse_stability(sess: &Session, attr: &Attribute) -> Option<(Symbol, Stabilit
         }
     }
 
-    if let Some(s) = since
-        && s.as_str() == VERSION_PLACEHOLDER
-    {
-        since = Some(rust_version_symbol());
-    }
+    let feature = match feature {
+        Some(feature) if rustc_lexer::is_ident(feature.as_str()) => Ok(feature),
+        Some(_bad_feature) => {
+            Err(sess.emit_err(session_diagnostics::NonIdentFeature { span: attr.span }))
+        }
+        None => Err(sess.emit_err(session_diagnostics::MissingFeature { span: attr.span })),
+    };
+
+    let since = if let Some(since) = since {
+        if since.as_str() == VERSION_PLACEHOLDER {
+            Ok(rust_version_symbol())
+        } else if parse_version(since.as_str(), false).is_some() {
+            Ok(since)
+        } else {
+            Err(sess.emit_err(session_diagnostics::InvalidSince { span: attr.span }))
+        }
+    } else {
+        Err(sess.emit_err(session_diagnostics::MissingSince { span: attr.span }))
+    };
 
     match (feature, since) {
-        (Some(feature), Some(since)) => {
+        (Ok(feature), Ok(since)) => {
             let level = StabilityLevel::Stable { since, allowed_through_unstable_modules: false };
             Some((feature, level))
         }
-        (None, _) => {
-            sess.emit_err(session_diagnostics::MissingFeature { span: attr.span });
-            None
-        }
-        _ => {
-            sess.emit_err(session_diagnostics::MissingSince { span: attr.span });
-            None
-        }
+        (Err(ErrorGuaranteed { .. }), _) | (_, Err(ErrorGuaranteed { .. })) => None,
     }
 }
 
@@ -451,12 +459,19 @@ fn parse_unstability(sess: &Session, attr: &Attribute) -> Option<(Symbol, Stabil
         }
     }
 
-    match (feature, reason, issue) {
-        (Some(feature), reason, Some(_)) => {
-            if !rustc_lexer::is_ident(feature.as_str()) {
-                sess.emit_err(session_diagnostics::NonIdentFeature { span: attr.span });
-                return None;
-            }
+    let feature = match feature {
+        Some(feature) if rustc_lexer::is_ident(feature.as_str()) => Ok(feature),
+        Some(_bad_feature) => {
+            Err(sess.emit_err(session_diagnostics::NonIdentFeature { span: attr.span }))
+        }
+        None => Err(sess.emit_err(session_diagnostics::MissingFeature { span: attr.span })),
+    };
+
+    let issue =
+        issue.ok_or_else(|| sess.emit_err(session_diagnostics::MissingIssue { span: attr.span }));
+
+    match (feature, issue) {
+        (Ok(feature), Ok(_)) => {
             let level = StabilityLevel::Unstable {
                 reason: UnstableReason::from_opt_reason(reason),
                 issue: issue_num,
@@ -465,14 +480,7 @@ fn parse_unstability(sess: &Session, attr: &Attribute) -> Option<(Symbol, Stabil
             };
             Some((feature, level))
         }
-        (None, _, _) => {
-            sess.emit_err(session_diagnostics::MissingFeature { span: attr.span });
-            return None;
-        }
-        _ => {
-            sess.emit_err(session_diagnostics::MissingIssue { span: attr.span });
-            return None;
-        }
+        (Err(ErrorGuaranteed { .. }), _) | (_, Err(ErrorGuaranteed { .. })) => None,
     }
 }
 
diff --git a/compiler/rustc_attr/src/session_diagnostics.rs b/compiler/rustc_attr/src/session_diagnostics.rs
index 86f27254db2..ca9bbd28b95 100644
--- a/compiler/rustc_attr/src/session_diagnostics.rs
+++ b/compiler/rustc_attr/src/session_diagnostics.rs
@@ -370,6 +370,13 @@ pub(crate) struct ExpectsFeatures {
     pub name: String,
 }
 
+#[derive(Diagnostic)]
+#[diag(attr_invalid_since)]
+pub(crate) struct InvalidSince {
+    #[primary_span]
+    pub span: Span,
+}
+
 #[derive(Diagnostic)]
 #[diag(attr_soft_no_args)]
 pub(crate) struct SoftNoArgs {
diff --git a/compiler/rustc_borrowck/src/renumber.rs b/compiler/rustc_borrowck/src/renumber.rs
index 5d6f5cc8967..ec0131c5349 100644
--- a/compiler/rustc_borrowck/src/renumber.rs
+++ b/compiler/rustc_borrowck/src/renumber.rs
@@ -81,6 +81,10 @@ impl<'a, 'tcx> MutVisitor<'tcx> for RegionRenumberer<'a, 'tcx> {
 
     #[instrument(skip(self), level = "debug")]
     fn visit_ty(&mut self, ty: &mut Ty<'tcx>, ty_context: TyContext) {
+        if matches!(ty_context, TyContext::ReturnTy(_)) {
+            // We will renumber the return ty when called again with `TyContext::LocalDecl`
+            return;
+        }
         *ty = self.renumber_regions(*ty, || RegionCtxt::TyContext(ty_context));
 
         debug!(?ty);
diff --git a/compiler/rustc_codegen_cranelift/.vscode/settings.json b/compiler/rustc_codegen_cranelift/.vscode/settings.json
index 60cb51d5663..834a1362caf 100644
--- a/compiler/rustc_codegen_cranelift/.vscode/settings.json
+++ b/compiler/rustc_codegen_cranelift/.vscode/settings.json
@@ -33,7 +33,7 @@
             ]
         },
         {
-            "sysroot_src": "./download/sysroot/sysroot_src/library",
+            "sysroot_src": "./build/stdlib/library",
             "crates": [
                 {
                     "root_module": "./example/std_example.rs",
diff --git a/compiler/rustc_codegen_cranelift/Cargo.lock b/compiler/rustc_codegen_cranelift/Cargo.lock
index 8079913cb0f..c716d501173 100644
--- a/compiler/rustc_codegen_cranelift/Cargo.lock
+++ b/compiler/rustc_codegen_cranelift/Cargo.lock
@@ -45,18 +45,18 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
 
 [[package]]
 name = "cranelift-bforest"
-version = "0.101.0"
+version = "0.101.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8e5e1df0da8488dd03b34afc134ba84b754d61862cc465932a9e5d07952f661e"
+checksum = "c1512c3bb6b13018e7109fc3ac964bc87b329eaf3a77825d337558d0c7f6f1be"
 dependencies = [
  "cranelift-entity",
 ]
 
 [[package]]
 name = "cranelift-codegen"
-version = "0.101.0"
+version = "0.101.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "77a17ca4e699a0aaf49a0c88f6311a864f321048aa63f6b787cab20eb5f93f10"
+checksum = "16cb8fb9220a6ea7a226705a273ab905309ee546267bdf34948d57932d7f0396"
 dependencies = [
  "bumpalo",
  "cranelift-bforest",
@@ -75,39 +75,39 @@ dependencies = [
 
 [[package]]
 name = "cranelift-codegen-meta"
-version = "0.101.0"
+version = "0.101.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "022f2793cdade1d37a1f755ac42938a3f832f533eac6cafc8b26b209544c3c06"
+checksum = "ab3a8d3b0d4745b183da5ea0792b13d79f5c23d6e69ac04761728e2532b56649"
 dependencies = [
  "cranelift-codegen-shared",
 ]
 
 [[package]]
 name = "cranelift-codegen-shared"
-version = "0.101.0"
+version = "0.101.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a4d72dbb83c2ad788dec4ad0843070973cb48c35a3ca19b1e7437ac40834fd9c"
+checksum = "524141c8e68f2abc2043de4c2b31f6d9dd42432738c246431d0572a1422a4a84"
 
 [[package]]
 name = "cranelift-control"
-version = "0.101.0"
+version = "0.101.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ae07cf26dcc90d546826d747ac63b6c40c916f34b03e92a6ae0422c28d771b8a"
+checksum = "97513b57c961c713789a03886a57b43e14ebcd204cbaa8ae50ca6c70a8e716b3"
 dependencies = [
  "arbitrary",
 ]
 
 [[package]]
 name = "cranelift-entity"
-version = "0.101.0"
+version = "0.101.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c2fe6b7e49820893691aea497f36257e9d6f52061d8c4758d61d802d5f101a3d"
+checksum = "e3f23d3cf3afa7e45f239702612c76d87964f652a55e28d13ed6d7e20f3479dd"
 
 [[package]]
 name = "cranelift-frontend"
-version = "0.101.0"
+version = "0.101.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "44f497576ca3674581581601b6a55ccc1b43447217648c880e5bce70db3cf659"
+checksum = "554cd4947ec9209b58bf9ae5bf83581b5ddf9128bd967208e334b504a57db54e"
 dependencies = [
  "cranelift-codegen",
  "log",
@@ -117,15 +117,15 @@ dependencies = [
 
 [[package]]
 name = "cranelift-isle"
-version = "0.101.0"
+version = "0.101.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b96aa02eac00fffee13b0cd37d17874ccdb3d5458983041accd825ef78ce6454"
+checksum = "6c1892a439696b6413cb54083806f5fd9fc431768b8de74864b3d9e8b93b124f"
 
 [[package]]
 name = "cranelift-jit"
-version = "0.101.0"
+version = "0.101.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b1d6e0e308c873eefc185745a6b21daec2a10f7554c9fb67e334c2d7d756d979"
+checksum = "32209252fb38acaf1662ccd0397907bbe0e92bdb13b6ddbfd2f74e437f83e685"
 dependencies = [
  "anyhow",
  "cranelift-codegen",
@@ -143,9 +143,9 @@ dependencies = [
 
 [[package]]
 name = "cranelift-module"
-version = "0.101.0"
+version = "0.101.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c1aa8ebb06eced4e478c3f94f1d65d4e7c93493f4640057912b27a3e34b84841"
+checksum = "bf42656f5f6df7bfafc4dd7b63a1888b0627c07b43b2cb9aa54e13843fed39eb"
 dependencies = [
  "anyhow",
  "cranelift-codegen",
@@ -154,9 +154,9 @@ dependencies = [
 
 [[package]]
 name = "cranelift-native"
-version = "0.101.0"
+version = "0.101.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2870170ca44054b202c737626607b87be6e35655084bd94a6ff807a5812ba7df"
+checksum = "e0c2d3badd4b9690865f5bb68a71fa94de592fa2df3f3d11a5a062c60c0a107a"
 dependencies = [
  "cranelift-codegen",
  "libc",
@@ -165,9 +165,9 @@ dependencies = [
 
 [[package]]
 name = "cranelift-object"
-version = "0.101.0"
+version = "0.101.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "20647761742d17dabac8205da958910ede78599550e06418a16711a3ee2fc897"
+checksum = "88eca54bbecea3170035168357306e9c779d4a63d8bf036c9e16bd21fdaa69b5"
 dependencies = [
  "anyhow",
  "cranelift-codegen",
@@ -374,9 +374,9 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
 
 [[package]]
 name = "wasmtime-jit-icache-coherence"
-version = "14.0.0"
+version = "14.0.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a3a5dda53ad6993f9b0a2d65fb49e0348a7232a27a8794064122870d6ee19eb2"
+checksum = "9aaf2fa8fd2d6b65abae9b92edfe69254cc5d6b166e342364036c3e347de8da9"
 dependencies = [
  "cfg-if",
  "libc",
diff --git a/compiler/rustc_codegen_cranelift/Cargo.toml b/compiler/rustc_codegen_cranelift/Cargo.toml
index 5ad5e0e8140..f2ce714e8ff 100644
--- a/compiler/rustc_codegen_cranelift/Cargo.toml
+++ b/compiler/rustc_codegen_cranelift/Cargo.toml
@@ -8,12 +8,12 @@ crate-type = ["dylib"]
 
 [dependencies]
 # These have to be in sync with each other
-cranelift-codegen = { version = "0.101", features = ["unwind", "all-arch"] }
-cranelift-frontend = { version = "0.101" }
-cranelift-module = { version = "0.101" }
-cranelift-native = { version = "0.101" }
-cranelift-jit = { version = "0.101", optional = true }
-cranelift-object = { version = "0.101" }
+cranelift-codegen = { version = "0.101.1", features = ["unwind", "all-arch"] }
+cranelift-frontend = { version = "0.101.1" }
+cranelift-module = { version = "0.101.1" }
+cranelift-native = { version = "0.101.1" }
+cranelift-jit = { version = "0.101.1", optional = true }
+cranelift-object = { version = "0.101.1" }
 target-lexicon = "0.12.0"
 gimli = { version = "0.28", default-features = false, features = ["write"]}
 object = { version = "0.32", default-features = false, features = ["std", "read_core", "write", "archive", "coff", "elf", "macho", "pe"] }
diff --git a/compiler/rustc_codegen_cranelift/Readme.md b/compiler/rustc_codegen_cranelift/Readme.md
index 6f2027be96d..5664cbe7d4f 100644
--- a/compiler/rustc_codegen_cranelift/Readme.md
+++ b/compiler/rustc_codegen_cranelift/Readme.md
@@ -8,7 +8,7 @@ If not please open an issue.
 ## Building and testing
 
 ```bash
-$ git clone https://github.com/bjorn3/rustc_codegen_cranelift
+$ git clone https://github.com/rust-lang/rustc_codegen_cranelift
 $ cd rustc_codegen_cranelift
 $ ./y.sh prepare
 $ ./y.sh build
@@ -29,7 +29,7 @@ Extract the `dist` directory in the archive anywhere you want.
 If you want to use `cargo clif build` instead of having to specify the full path to the `cargo-clif` executable, you can add the `bin` subdirectory of the extracted `dist` directory to your `PATH`.
 (tutorial [for Windows](https://stackoverflow.com/a/44272417), and [for Linux/MacOS](https://unix.stackexchange.com/questions/26047/how-to-correctly-add-a-path-to-path/26059#26059)).
 
-[releases]: https://github.com/bjorn3/rustc_codegen_cranelift/releases/tag/dev
+[releases]: https://github.com/rust-lang/rustc_codegen_cranelift/releases/tag/dev
 
 ## Usage
 
@@ -78,7 +78,7 @@ configuration options.
 
 * Inline assembly ([no cranelift support](https://github.com/bytecodealliance/wasmtime/issues/1041))
     * On UNIX there is support for invoking an external assembler for `global_asm!` and `asm!`.
-* SIMD ([tracked here](https://github.com/bjorn3/rustc_codegen_cranelift/issues/171), `std::simd` fully works, `std::arch` is partially supported)
+* SIMD ([tracked here](https://github.com/rust-lang/rustc_codegen_cranelift/issues/171), `std::simd` fully works, `std::arch` is partially supported)
 * Unwinding on panics ([no cranelift support](https://github.com/bytecodealliance/wasmtime/issues/1677), `-Cpanic=abort` is enabled by default)
 
 ## License
diff --git a/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs b/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs
index 91de04d9770..afc51a47f14 100644
--- a/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs
+++ b/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs
@@ -353,6 +353,17 @@ fn main() {
 
     let f = V([0.0, 1.0]);
     let _a = f.0[0];
+
+    stack_val_align();
+}
+
+#[inline(never)]
+fn stack_val_align() {
+    #[repr(align(8192))]
+    struct Foo(u8);
+
+    let a = Foo(0);
+    assert_eq!(&a as *const Foo as usize % 8192, 0);
 }
 
 #[cfg(all(
diff --git a/compiler/rustc_codegen_cranelift/patches/0001-regex-Ignore-test-which-gets-miscompiled-with-llvm-sysroot.patch b/compiler/rustc_codegen_cranelift/patches/0001-regex-Ignore-test-which-gets-miscompiled-with-llvm-sysroot.patch
deleted file mode 100644
index e6ebdcec783..00000000000
--- a/compiler/rustc_codegen_cranelift/patches/0001-regex-Ignore-test-which-gets-miscompiled-with-llvm-sysroot.patch
+++ /dev/null
@@ -1,25 +0,0 @@
-From 5d4afb8d807d181038b6a004d17ed055a8d191b2 Mon Sep 17 00:00:00 2001
-From: bjorn3 <17426603+bjorn3@users.noreply.github.com>
-Date: Mon, 2 Oct 2023 13:59:00 +0000
-Subject: [PATCH] Ignore test which gets miscompiled with llvm sysroot
-
----
- regex-automata/src/util/pool.rs | 2 ++
- 1 file changed, 2 insertions(+)
-
-diff --git a/regex-automata/src/util/pool.rs b/regex-automata/src/util/pool.rs
-index c03d7b0..28b233b 100644
---- a/regex-automata/src/util/pool.rs
-+++ b/regex-automata/src/util/pool.rs
-@@ -1081,6 +1081,8 @@ mod tests {
-     // into the pool. This in turn resulted in this test producing a data race.
-     #[cfg(feature = "std")]
-     #[test]
-+    // FIXME(rustc_codegen_cranelift#1395) miscompilation of thread::scope with LLVM sysroot
-+    #[ignore]
-     fn thread_owner_sync() {
-         let pool = Pool::new(|| vec!['a']);
-         {
--- 
-2.34.1
-
diff --git a/compiler/rustc_codegen_cranelift/src/abi/mod.rs b/compiler/rustc_codegen_cranelift/src/abi/mod.rs
index c75ad852f82..c4572e03525 100644
--- a/compiler/rustc_codegen_cranelift/src/abi/mod.rs
+++ b/compiler/rustc_codegen_cranelift/src/abi/mod.rs
@@ -120,32 +120,25 @@ impl<'tcx> FunctionCx<'_, '_, 'tcx> {
         args: &[Value],
     ) -> Cow<'_, [Value]> {
         if self.tcx.sess.target.is_like_windows {
-            let (mut params, mut args): (Vec<_>, Vec<_>) =
-                params
-                    .into_iter()
-                    .zip(args)
-                    .map(|(param, &arg)| {
-                        if param.value_type == types::I128 {
-                            let arg_ptr = Pointer::stack_slot(self.bcx.create_sized_stack_slot(
-                                StackSlotData { kind: StackSlotKind::ExplicitSlot, size: 16 },
-                            ));
-                            arg_ptr.store(self, arg, MemFlags::trusted());
-                            (AbiParam::new(self.pointer_type), arg_ptr.get_addr(self))
-                        } else {
-                            (param, arg)
-                        }
-                    })
-                    .unzip();
+            let (mut params, mut args): (Vec<_>, Vec<_>) = params
+                .into_iter()
+                .zip(args)
+                .map(|(param, &arg)| {
+                    if param.value_type == types::I128 {
+                        let arg_ptr = self.create_stack_slot(16, 16);
+                        arg_ptr.store(self, arg, MemFlags::trusted());
+                        (AbiParam::new(self.pointer_type), arg_ptr.get_addr(self))
+                    } else {
+                        (param, arg)
+                    }
+                })
+                .unzip();
 
             let indirect_ret_val = returns.len() == 1 && returns[0].value_type == types::I128;
 
             if indirect_ret_val {
                 params.insert(0, AbiParam::new(self.pointer_type));
-                let ret_ptr =
-                    Pointer::stack_slot(self.bcx.create_sized_stack_slot(StackSlotData {
-                        kind: StackSlotKind::ExplicitSlot,
-                        size: 16,
-                    }));
+                let ret_ptr = self.create_stack_slot(16, 16);
                 args.insert(0, ret_ptr.get_addr(self));
                 self.lib_call_unadjusted(name, params, vec![], &args);
                 return Cow::Owned(vec![ret_ptr.load(self, types::I128, MemFlags::trusted())]);
diff --git a/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs b/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs
index 7c9f8c1051c..06522670029 100644
--- a/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs
+++ b/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs
@@ -189,16 +189,13 @@ pub(super) fn from_casted_value<'tcx>(
     let abi_params = cast_target_to_abi_params(cast);
     let abi_param_size: u32 = abi_params.iter().map(|param| param.value_type.bytes()).sum();
     let layout_size = u32::try_from(layout.size.bytes()).unwrap();
-    let stack_slot = fx.bcx.create_sized_stack_slot(StackSlotData {
-        kind: StackSlotKind::ExplicitSlot,
-        // FIXME Don't force the size to a multiple of 16 bytes once Cranelift gets a way to
-        // specify stack slot alignment.
+    let ptr = fx.create_stack_slot(
         // Stack slot size may be bigger for example `[u8; 3]` which is packed into an `i32`.
         // It may also be smaller for example when the type is a wrapper around an integer with a
         // larger alignment than the integer.
-        size: (std::cmp::max(abi_param_size, layout_size) + 15) / 16 * 16,
-    });
-    let ptr = Pointer::stack_slot(stack_slot);
+        std::cmp::max(abi_param_size, layout_size),
+        u32::try_from(layout.align.pref.bytes()).unwrap(),
+    );
     let mut offset = 0;
     let mut block_params_iter = block_params.iter().copied();
     for param in abi_params {
diff --git a/compiler/rustc_codegen_cranelift/src/cast.rs b/compiler/rustc_codegen_cranelift/src/cast.rs
index 7e027c5f1b3..0b5cb1547fc 100644
--- a/compiler/rustc_codegen_cranelift/src/cast.rs
+++ b/compiler/rustc_codegen_cranelift/src/cast.rs
@@ -104,11 +104,7 @@ pub(crate) fn clif_int_or_float_cast(
                     &[from],
                 )[0];
                 // FIXME(bytecodealliance/wasmtime#6104) use bitcast instead of store to get from i64x2 to i128
-                let stack_slot = fx.bcx.create_sized_stack_slot(StackSlotData {
-                    kind: StackSlotKind::ExplicitSlot,
-                    size: 16,
-                });
-                let ret_ptr = Pointer::stack_slot(stack_slot);
+                let ret_ptr = fx.create_stack_slot(16, 16);
                 ret_ptr.store(fx, ret, MemFlags::trusted());
                 ret_ptr.load(fx, types::I128, MemFlags::trusted())
             } else {
diff --git a/compiler/rustc_codegen_cranelift/src/common.rs b/compiler/rustc_codegen_cranelift/src/common.rs
index 7a3ae6ebf52..9771f44f62c 100644
--- a/compiler/rustc_codegen_cranelift/src/common.rs
+++ b/compiler/rustc_codegen_cranelift/src/common.rs
@@ -383,6 +383,25 @@ impl<'tcx> FunctionCx<'_, '_, 'tcx> {
         })
     }
 
+    pub(crate) fn create_stack_slot(&mut self, size: u32, align: u32) -> Pointer {
+        if align <= 16 {
+            let stack_slot = self.bcx.create_sized_stack_slot(StackSlotData {
+                kind: StackSlotKind::ExplicitSlot,
+                // FIXME Don't force the size to a multiple of 16 bytes once Cranelift gets a way to
+                // specify stack slot alignment.
+                size: (size + 15) / 16 * 16,
+            });
+            Pointer::stack_slot(stack_slot)
+        } else {
+            // Alignment is too big to handle using the above hack. Dynamically realign a stack slot
+            // instead. This wastes some space for the realignment.
+            let base_ptr = self.create_stack_slot(size + align, 16).get_addr(self);
+            let misalign_offset = self.bcx.ins().urem_imm(base_ptr, i64::from(align));
+            let realign_offset = self.bcx.ins().irsub_imm(misalign_offset, i64::from(align));
+            Pointer::new(self.bcx.ins().iadd(base_ptr, realign_offset))
+        }
+    }
+
     pub(crate) fn set_debug_loc(&mut self, source_info: mir::SourceInfo) {
         if let Some(debug_context) = &mut self.cx.debug_context {
             let (file, line, column) =
diff --git a/compiler/rustc_codegen_cranelift/src/driver/aot.rs b/compiler/rustc_codegen_cranelift/src/driver/aot.rs
index d3a7decc543..11229dd421e 100644
--- a/compiler/rustc_codegen_cranelift/src/driver/aot.rs
+++ b/compiler/rustc_codegen_cranelift/src/driver/aot.rs
@@ -361,12 +361,26 @@ pub(crate) fn run_aot(
     metadata: EncodedMetadata,
     need_metadata_module: bool,
 ) -> Box<OngoingCodegen> {
+    // FIXME handle `-Ctarget-cpu=native`
+    let target_cpu = match tcx.sess.opts.cg.target_cpu {
+        Some(ref name) => name,
+        None => tcx.sess.target.cpu.as_ref(),
+    }
+    .to_owned();
+
     let cgus = if tcx.sess.opts.output_types.should_codegen() {
         tcx.collect_and_partition_mono_items(()).1
     } else {
         // If only `--emit metadata` is used, we shouldn't perform any codegen.
         // Also `tcx.collect_and_partition_mono_items` may panic in that case.
-        &[]
+        return Box::new(OngoingCodegen {
+            modules: vec![],
+            allocator_module: None,
+            metadata_module: None,
+            metadata,
+            crate_info: CrateInfo::new(tcx, target_cpu),
+            concurrency_limiter: ConcurrencyLimiter::new(tcx.sess, 0),
+        });
     };
 
     if tcx.dep_graph.is_fully_enabled() {
@@ -481,13 +495,6 @@ pub(crate) fn run_aot(
         None
     };
 
-    // FIXME handle `-Ctarget-cpu=native`
-    let target_cpu = match tcx.sess.opts.cg.target_cpu {
-        Some(ref name) => name,
-        None => tcx.sess.target.cpu.as_ref(),
-    }
-    .to_owned();
-
     Box::new(OngoingCodegen {
         modules,
         allocator_module,
diff --git a/compiler/rustc_codegen_cranelift/src/inline_asm.rs b/compiler/rustc_codegen_cranelift/src/inline_asm.rs
index ed077234254..0517c609337 100644
--- a/compiler/rustc_codegen_cranelift/src/inline_asm.rs
+++ b/compiler/rustc_codegen_cranelift/src/inline_asm.rs
@@ -878,13 +878,7 @@ fn call_inline_asm<'tcx>(
     inputs: Vec<(Size, Value)>,
     outputs: Vec<(Size, CPlace<'tcx>)>,
 ) {
-    let stack_slot = fx.bcx.func.create_sized_stack_slot(StackSlotData {
-        kind: StackSlotKind::ExplicitSlot,
-        size: u32::try_from(slot_size.bytes()).unwrap(),
-    });
-    if fx.clif_comments.enabled() {
-        fx.add_comment(stack_slot, "inline asm scratch slot");
-    }
+    let stack_slot = fx.create_stack_slot(u32::try_from(slot_size.bytes()).unwrap(), 16);
 
     let inline_asm_func = fx
         .module
@@ -904,15 +898,23 @@ fn call_inline_asm<'tcx>(
     }
 
     for (offset, value) in inputs {
-        fx.bcx.ins().stack_store(value, stack_slot, i32::try_from(offset.bytes()).unwrap());
+        stack_slot.offset(fx, i32::try_from(offset.bytes()).unwrap().into()).store(
+            fx,
+            value,
+            MemFlags::trusted(),
+        );
     }
 
-    let stack_slot_addr = fx.bcx.ins().stack_addr(fx.pointer_type, stack_slot, 0);
+    let stack_slot_addr = stack_slot.get_addr(fx);
     fx.bcx.ins().call(inline_asm_func, &[stack_slot_addr]);
 
     for (offset, place) in outputs {
         let ty = fx.clif_type(place.layout().ty).unwrap();
-        let value = fx.bcx.ins().stack_load(ty, stack_slot, i32::try_from(offset.bytes()).unwrap());
+        let value = stack_slot.offset(fx, i32::try_from(offset.bytes()).unwrap().into()).load(
+            fx,
+            ty,
+            MemFlags::trusted(),
+        );
         place.write_cvalue(fx, CValue::by_val(value, place.layout()));
     }
 }
diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs
index 0c9a94e1c23..35f144d7dad 100644
--- a/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs
+++ b/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs
@@ -310,6 +310,143 @@ pub(crate) fn codegen_x86_llvm_intrinsic_call<'tcx>(
             let val = CValue::by_val_pair(cb_out, c, layout);
             ret.write_cvalue(fx, val);
         }
+        "llvm.x86.sse2.pavg.b" | "llvm.x86.sse2.pavg.w" => {
+            intrinsic_args!(fx, args => (a, b); intrinsic);
+
+            // FIXME use vector instructions when possible
+            simd_pair_for_each_lane(
+                fx,
+                a,
+                b,
+                ret,
+                &|fx, _lane_ty, _res_lane_ty, a_lane, b_lane| {
+                    // (a + b + 1) >> 1
+                    let lane_ty = fx.bcx.func.dfg.value_type(a_lane);
+                    let a_lane = fx.bcx.ins().uextend(lane_ty.double_width().unwrap(), a_lane);
+                    let b_lane = fx.bcx.ins().uextend(lane_ty.double_width().unwrap(), b_lane);
+                    let sum = fx.bcx.ins().iadd(a_lane, b_lane);
+                    let num_plus_one = fx.bcx.ins().iadd_imm(sum, 1);
+                    let res = fx.bcx.ins().ushr_imm(num_plus_one, 1);
+                    fx.bcx.ins().ireduce(lane_ty, res)
+                },
+            );
+        }
+        "llvm.x86.sse2.psra.w" => {
+            intrinsic_args!(fx, args => (a, count); intrinsic);
+
+            let count_lane = count.force_stack(fx).0.load(fx, types::I64, MemFlags::trusted());
+            let lane_ty = fx.clif_type(a.layout().ty.simd_size_and_type(fx.tcx).1).unwrap();
+            let max_count = fx.bcx.ins().iconst(types::I64, i64::from(lane_ty.bits() - 1));
+            let saturated_count = fx.bcx.ins().umin(count_lane, max_count);
+
+            // FIXME use vector instructions when possible
+            simd_for_each_lane(fx, a, ret, &|fx, _lane_ty, _res_lane_ty, a_lane| {
+                fx.bcx.ins().sshr(a_lane, saturated_count)
+            });
+        }
+        "llvm.x86.sse2.psad.bw" => {
+            intrinsic_args!(fx, args => (a, b); intrinsic);
+
+            assert_eq!(a.layout(), b.layout());
+            let layout = a.layout();
+
+            let (lane_count, lane_ty) = layout.ty.simd_size_and_type(fx.tcx);
+            let (ret_lane_count, ret_lane_ty) = ret.layout().ty.simd_size_and_type(fx.tcx);
+            assert_eq!(lane_ty, fx.tcx.types.u8);
+            assert_eq!(ret_lane_ty, fx.tcx.types.u64);
+            assert_eq!(lane_count, ret_lane_count * 8);
+
+            let ret_lane_layout = fx.layout_of(fx.tcx.types.u64);
+            for out_lane_idx in 0..lane_count / 8 {
+                let mut lane_diff_acc = fx.bcx.ins().iconst(types::I64, 0);
+
+                for lane_idx in out_lane_idx * 8..out_lane_idx * 8 + 1 {
+                    let a_lane = a.value_lane(fx, lane_idx).load_scalar(fx);
+                    let b_lane = b.value_lane(fx, lane_idx).load_scalar(fx);
+
+                    let lane_diff = fx.bcx.ins().isub(a_lane, b_lane);
+                    let abs_lane_diff = fx.bcx.ins().iabs(lane_diff);
+                    let abs_lane_diff = fx.bcx.ins().uextend(types::I64, abs_lane_diff);
+                    lane_diff_acc = fx.bcx.ins().iadd(lane_diff_acc, abs_lane_diff);
+                }
+
+                let res_lane = CValue::by_val(lane_diff_acc, ret_lane_layout);
+
+                ret.place_lane(fx, out_lane_idx).write_cvalue(fx, res_lane);
+            }
+        }
+        "llvm.x86.ssse3.pmadd.ub.sw.128" => {
+            intrinsic_args!(fx, args => (a, b); intrinsic);
+
+            let (lane_count, lane_ty) = a.layout().ty.simd_size_and_type(fx.tcx);
+            let (ret_lane_count, ret_lane_ty) = ret.layout().ty.simd_size_and_type(fx.tcx);
+            assert_eq!(lane_ty, fx.tcx.types.u8);
+            assert_eq!(ret_lane_ty, fx.tcx.types.i16);
+            assert_eq!(lane_count, ret_lane_count * 2);
+
+            let ret_lane_layout = fx.layout_of(fx.tcx.types.i16);
+            for out_lane_idx in 0..lane_count / 2 {
+                let a_lane0 = a.value_lane(fx, out_lane_idx * 2).load_scalar(fx);
+                let a_lane0 = fx.bcx.ins().uextend(types::I16, a_lane0);
+                let b_lane0 = b.value_lane(fx, out_lane_idx * 2).load_scalar(fx);
+                let b_lane0 = fx.bcx.ins().sextend(types::I16, b_lane0);
+
+                let a_lane1 = a.value_lane(fx, out_lane_idx * 2 + 1).load_scalar(fx);
+                let a_lane1 = fx.bcx.ins().uextend(types::I16, a_lane1);
+                let b_lane1 = b.value_lane(fx, out_lane_idx * 2 + 1).load_scalar(fx);
+                let b_lane1 = fx.bcx.ins().sextend(types::I16, b_lane1);
+
+                let mul0: Value = fx.bcx.ins().imul(a_lane0, b_lane0);
+                let mul1 = fx.bcx.ins().imul(a_lane1, b_lane1);
+
+                let (val, has_overflow) = fx.bcx.ins().sadd_overflow(mul0, mul1);
+
+                let rhs_ge_zero = fx.bcx.ins().icmp_imm(IntCC::SignedGreaterThanOrEqual, mul1, 0);
+
+                let min = fx.bcx.ins().iconst(types::I16, i64::from(i16::MIN as u16));
+                let max = fx.bcx.ins().iconst(types::I16, i64::from(i16::MAX as u16));
+
+                let sat_val = fx.bcx.ins().select(rhs_ge_zero, max, min);
+                let res_lane = fx.bcx.ins().select(has_overflow, sat_val, val);
+
+                let res_lane = CValue::by_val(res_lane, ret_lane_layout);
+
+                ret.place_lane(fx, out_lane_idx).write_cvalue(fx, res_lane);
+            }
+        }
+        "llvm.x86.sse2.pmadd.wd" => {
+            intrinsic_args!(fx, args => (a, b); intrinsic);
+
+            assert_eq!(a.layout(), b.layout());
+            let layout = a.layout();
+
+            let (lane_count, lane_ty) = layout.ty.simd_size_and_type(fx.tcx);
+            let (ret_lane_count, ret_lane_ty) = ret.layout().ty.simd_size_and_type(fx.tcx);
+            assert_eq!(lane_ty, fx.tcx.types.i16);
+            assert_eq!(ret_lane_ty, fx.tcx.types.i32);
+            assert_eq!(lane_count, ret_lane_count * 2);
+
+            let ret_lane_layout = fx.layout_of(fx.tcx.types.i32);
+            for out_lane_idx in 0..lane_count / 2 {
+                let a_lane0 = a.value_lane(fx, out_lane_idx * 2).load_scalar(fx);
+                let a_lane0 = fx.bcx.ins().uextend(types::I32, a_lane0);
+                let b_lane0 = b.value_lane(fx, out_lane_idx * 2).load_scalar(fx);
+                let b_lane0 = fx.bcx.ins().sextend(types::I32, b_lane0);
+
+                let a_lane1 = a.value_lane(fx, out_lane_idx * 2 + 1).load_scalar(fx);
+                let a_lane1 = fx.bcx.ins().uextend(types::I32, a_lane1);
+                let b_lane1 = b.value_lane(fx, out_lane_idx * 2 + 1).load_scalar(fx);
+                let b_lane1 = fx.bcx.ins().sextend(types::I32, b_lane1);
+
+                let mul0: Value = fx.bcx.ins().imul(a_lane0, b_lane0);
+                let mul1 = fx.bcx.ins().imul(a_lane1, b_lane1);
+
+                let res_lane = fx.bcx.ins().iadd(mul0, mul1);
+                let res_lane = CValue::by_val(res_lane, ret_lane_layout);
+
+                ret.place_lane(fx, out_lane_idx).write_cvalue(fx, res_lane);
+            }
+        }
         _ => {
             fx.tcx
                 .sess
diff --git a/compiler/rustc_codegen_cranelift/src/value_and_place.rs b/compiler/rustc_codegen_cranelift/src/value_and_place.rs
index 3a6a6c9e3f5..5f0aa6c5581 100644
--- a/compiler/rustc_codegen_cranelift/src/value_and_place.rs
+++ b/compiler/rustc_codegen_cranelift/src/value_and_place.rs
@@ -132,18 +132,11 @@ impl<'tcx> CValue<'tcx> {
                 (ptr.get_addr(fx), vtable)
             }
             CValueInner::ByValPair(data, vtable) => {
-                let stack_slot = fx.bcx.create_sized_stack_slot(StackSlotData {
-                    kind: StackSlotKind::ExplicitSlot,
-                    // FIXME Don't force the size to a multiple of 16 bytes once Cranelift gets a way to
-                    // specify stack slot alignment.
-                    size: (u32::try_from(fx.target_config.pointer_type().bytes()).unwrap() + 15)
-                        / 16
-                        * 16,
-                });
-                let data_ptr = Pointer::stack_slot(stack_slot);
-                let mut flags = MemFlags::new();
-                flags.set_notrap();
-                data_ptr.store(fx, data, flags);
+                let data_ptr = fx.create_stack_slot(
+                    u32::try_from(fx.target_config.pointer_type().bytes()).unwrap(),
+                    u32::try_from(fx.target_config.pointer_type().bytes()).unwrap(),
+                );
+                data_ptr.store(fx, data, MemFlags::trusted());
 
                 (data_ptr.get_addr(fx), vtable)
             }
@@ -372,13 +365,11 @@ impl<'tcx> CPlace<'tcx> {
                 .fatal(format!("values of type {} are too big to store on the stack", layout.ty));
         }
 
-        let stack_slot = fx.bcx.create_sized_stack_slot(StackSlotData {
-            kind: StackSlotKind::ExplicitSlot,
-            // FIXME Don't force the size to a multiple of 16 bytes once Cranelift gets a way to
-            // specify stack slot alignment.
-            size: (u32::try_from(layout.size.bytes()).unwrap() + 15) / 16 * 16,
-        });
-        CPlace { inner: CPlaceInner::Addr(Pointer::stack_slot(stack_slot), None), layout }
+        let stack_slot = fx.create_stack_slot(
+            u32::try_from(layout.size.bytes()).unwrap(),
+            u32::try_from(layout.align.pref.bytes()).unwrap(),
+        );
+        CPlace { inner: CPlaceInner::Addr(stack_slot, None), layout }
     }
 
     pub(crate) fn new_var(
@@ -543,13 +534,7 @@ impl<'tcx> CPlace<'tcx> {
                 _ if src_ty.is_vector() && dst_ty.is_vector() => codegen_bitcast(fx, dst_ty, data),
                 _ if src_ty.is_vector() || dst_ty.is_vector() => {
                     // FIXME(bytecodealliance/wasmtime#6104) do something more efficient for transmutes between vectors and integers.
-                    let stack_slot = fx.bcx.create_sized_stack_slot(StackSlotData {
-                        kind: StackSlotKind::ExplicitSlot,
-                        // FIXME Don't force the size to a multiple of 16 bytes once Cranelift gets a way to
-                        // specify stack slot alignment.
-                        size: (src_ty.bytes() + 15) / 16 * 16,
-                    });
-                    let ptr = Pointer::stack_slot(stack_slot);
+                    let ptr = fx.create_stack_slot(src_ty.bytes(), src_ty.bytes());
                     ptr.store(fx, data, MemFlags::trusted());
                     ptr.load(fx, dst_ty, MemFlags::trusted())
                 }
diff --git a/compiler/rustc_codegen_ssa/src/target_features.rs b/compiler/rustc_codegen_ssa/src/target_features.rs
index baf6b19d3f9..13a3f432b03 100644
--- a/compiler/rustc_codegen_ssa/src/target_features.rs
+++ b/compiler/rustc_codegen_ssa/src/target_features.rs
@@ -342,6 +342,19 @@ const CSKY_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
     ("hard-float-abi", Some(sym::csky_target_feature)),
     // tidy-alphabetical-end
 ];
+
+const LOONGARCH_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
+    // tidy-alphabetical-start
+    ("d", Some(sym::loongarch_target_feature)),
+    ("f", Some(sym::loongarch_target_feature)),
+    ("lasx", Some(sym::loongarch_target_feature)),
+    ("lbt", Some(sym::loongarch_target_feature)),
+    ("lsx", Some(sym::loongarch_target_feature)),
+    ("lvz", Some(sym::loongarch_target_feature)),
+    ("ual", Some(sym::loongarch_target_feature)),
+    // tidy-alphabetical-end
+];
+
 /// When rustdoc is running, provide a list of all known features so that all their respective
 /// primitives may be documented.
 ///
@@ -358,6 +371,7 @@ pub fn all_known_features() -> impl Iterator<Item = (&'static str, Option<Symbol
         .chain(WASM_ALLOWED_FEATURES.iter())
         .chain(BPF_ALLOWED_FEATURES.iter())
         .chain(CSKY_ALLOWED_FEATURES)
+        .chain(LOONGARCH_ALLOWED_FEATURES)
         .cloned()
 }
 
@@ -373,6 +387,7 @@ pub fn supported_target_features(sess: &Session) -> &'static [(&'static str, Opt
         "wasm32" | "wasm64" => WASM_ALLOWED_FEATURES,
         "bpf" => BPF_ALLOWED_FEATURES,
         "csky" => CSKY_ALLOWED_FEATURES,
+        "loongarch64" => LOONGARCH_ALLOWED_FEATURES,
         _ => &[],
     }
 }
@@ -445,6 +460,7 @@ pub fn from_target_feature(
                 Some(sym::bpf_target_feature) => rust_features.bpf_target_feature,
                 Some(sym::aarch64_ver_target_feature) => rust_features.aarch64_ver_target_feature,
                 Some(sym::csky_target_feature) => rust_features.csky_target_feature,
+                Some(sym::loongarch_target_feature) => rust_features.loongarch_target_feature,
                 Some(name) => bug!("unknown target feature gate {}", name),
                 None => true,
             };
diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs
index 1202b0030ca..ec0af79459c 100644
--- a/compiler/rustc_const_eval/src/interpret/eval_context.rs
+++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs
@@ -1010,7 +1010,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
             // Just make this an efficient immediate.
             // Note that not calling `layout_of` here does have one real consequence:
             // if the type is too big, we'll only notice this when the local is actually initialized,
-            // which is a bit too late -- we should ideally notice this alreayd here, when the memory
+            // which is a bit too late -- we should ideally notice this already here, when the memory
             // is conceptually allocated. But given how rare that error is and that this is a hot function,
             // we accept this downside for now.
             Operand::Immediate(Immediate::Uninit)
diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs
index 65e697c8f3b..e808e4815fe 100644
--- a/compiler/rustc_feature/src/builtin_attrs.rs
+++ b/compiler/rustc_feature/src/builtin_attrs.rs
@@ -825,6 +825,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
     rustc_attr!(TEST, rustc_strict_coherence, Normal, template!(Word), WarnFollowing),
     rustc_attr!(TEST, rustc_variance, Normal, template!(Word), WarnFollowing),
     rustc_attr!(TEST, rustc_variance_of_opaques, Normal, template!(Word), WarnFollowing),
+    rustc_attr!(TEST, rustc_hidden_type_of_opaques, Normal, template!(Word), WarnFollowing),
     rustc_attr!(TEST, rustc_layout, Normal, template!(List: "field1, field2, ..."), WarnFollowing),
     rustc_attr!(TEST, rustc_abi, Normal, template!(List: "field1, field2, ..."), WarnFollowing),
     rustc_attr!(TEST, rustc_regions, Normal, template!(Word), WarnFollowing),
diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs
index 8185a8a3e43..695de54eefa 100644
--- a/compiler/rustc_feature/src/unstable.rs
+++ b/compiler/rustc_feature/src/unstable.rs
@@ -288,6 +288,7 @@ declare_features! (
     (unstable, csky_target_feature, "1.73.0", Some(44839), None),
     (unstable, ermsb_target_feature, "1.49.0", Some(44839), None),
     (unstable, hexagon_target_feature, "1.27.0", Some(44839), None),
+    (unstable, loongarch_target_feature, "1.73.0", Some(44839), None),
     (unstable, mips_target_feature, "1.27.0", Some(44839), None),
     (unstable, powerpc_target_feature, "1.27.0", Some(44839), None),
     (unstable, riscv_target_feature, "1.45.0", Some(44839), None),
diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl
index ee475e3de7e..e8d9918be22 100644
--- a/compiler/rustc_hir_analysis/messages.ftl
+++ b/compiler/rustc_hir_analysis/messages.ftl
@@ -72,6 +72,12 @@ hir_analysis_copy_impl_on_type_with_dtor =
     the trait `Copy` cannot be implemented for this type; the type has a destructor
     .label = `Copy` not allowed on types with destructors
 
+hir_analysis_cross_crate_traits = cross-crate traits with a default impl, like `{$traits}`, can only be implemented for a struct/enum type, not `{$self_ty}`
+    .label = can't implement cross-crate trait with a default impl for non-struct/enum type
+
+hir_analysis_cross_crate_traits_defined = cross-crate traits with a default impl, like `{$traits}`, can only be implemented for a struct/enum type defined in the current crate
+    .label = can't implement cross-crate trait for type in another crate
+
 hir_analysis_dispatch_from_dyn_multi = implementing the `DispatchFromDyn` trait requires multiple coercions
     .note = the trait `DispatchFromDyn` may only be implemented for a coercion between structures with a single field being coerced
     .coercions_note = currently, {$number} fields need coercions: {$coercions}
@@ -237,6 +243,28 @@ hir_analysis_must_implement_not_function_span_note = required by this annotation
 
 hir_analysis_must_implement_one_of_attribute = the `#[rustc_must_implement_one_of]` attribute must be used with at least 2 args
 
+hir_analysis_only_current_traits_arbitrary = only traits defined in the current crate can be implemented for arbitrary types
+
+hir_analysis_only_current_traits_foreign = this is not defined in the current crate because this is a foreign trait
+
+hir_analysis_only_current_traits_label = impl doesn't use only types from inside the current crate
+
+hir_analysis_only_current_traits_name = this is not defined in the current crate because {$name} are always foreign
+
+hir_analysis_only_current_traits_note = define and implement a trait or new type instead
+
+hir_analysis_only_current_traits_opaque = type alias impl trait is treated as if it were foreign, because its hidden type could be from a foreign crate
+
+hir_analysis_only_current_traits_outside = only traits defined in the current crate can be implemented for types defined outside of the crate
+
+hir_analysis_only_current_traits_pointer = `{$pointer}` is not defined in the current crate because raw pointers are always foreign
+
+hir_analysis_only_current_traits_pointer_sugg = consider introducing a new wrapper type
+
+hir_analysis_only_current_traits_primitive = only traits defined in the current crate can be implemented for primitive types
+
+hir_analysis_only_current_traits_ty = `{$ty}` is not defined in the current crate
+
 hir_analysis_paren_sugar_attribute = the `#[rustc_paren_sugar]` attribute is a temporary means of controlling which traits can use parenthetical notation
     .help = add `#![feature(unboxed_closures)]` to the crate attributes to use it
 
@@ -326,6 +354,9 @@ hir_analysis_trait_object_declared_with_no_traits =
     at least one trait is required for an object type
     .alias_span = this alias does not contain a trait
 
+hir_analysis_traits_with_defualt_impl = traits with a default impl, like `{$traits}`, cannot be implemented for {$problematic_kind} `{$self_ty}`
+    .note = a trait object implements `{$traits}` if and only if `{$traits}` is one of the trait object's trait bounds
+
 hir_analysis_transparent_enum_variant = transparent enum needs exactly one variant, but has {$number}
     .label = needs exactly one variant, but has {$number}
     .many_label = too many variants in `{$path}`
@@ -339,6 +370,18 @@ hir_analysis_transparent_non_zero_sized_enum = the variant of a transparent {$de
     .label = needs at most one field with non-trivial size or alignment, but has {$field_count}
     .labels = this field has non-zero size or requires alignment
 
+hir_analysis_ty_param_first_local = type parameter `{$param_ty}` must be covered by another type when it appears before the first local type (`{$local_type}`)
+    .label = type parameter `{$param_ty}` must be covered by another type when it appears before the first local type (`{$local_type}`)
+    .note = implementing a foreign trait is only possible if at least one of the types for which it is implemented is local, and no uncovered type parameters appear before that first local type
+    .case_note = in this case, 'before' refers to the following order: `impl<..> ForeignTrait<T1, ..., Tn> for T0`, where `T0` is the first and `Tn` is the last
+
+hir_analysis_ty_param_some = type parameter `{$param_ty}` must be used as the type parameter for some local type (e.g., `MyStruct<{$param_ty}>`)
+    .label = type parameter `{$param_ty}` must be used as the type parameter for some local type
+    .note = implementing a foreign trait is only possible if at least one of the types for which it is implemented is local
+    .only_note = only traits defined in the current crate can be implemented for a type parameter
+
+hir_analysis_type_of = {$type_of}
+
 hir_analysis_typeof_reserved_keyword_used =
     `typeof` is a reserved keyword but unimplemented
     .suggestion = consider replacing `typeof(...)` with an actual type
diff --git a/compiler/rustc_hir_analysis/src/coherence/orphan.rs b/compiler/rustc_hir_analysis/src/coherence/orphan.rs
index faddb0c3829..7eeb7837467 100644
--- a/compiler/rustc_hir_analysis/src/coherence/orphan.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/orphan.rs
@@ -2,8 +2,7 @@
 //! crate or pertains to a type defined in this crate.
 
 use rustc_data_structures::fx::FxHashSet;
-use rustc_errors::{struct_span_err, DelayDm};
-use rustc_errors::{Diagnostic, ErrorGuaranteed};
+use rustc_errors::{DelayDm, ErrorGuaranteed};
 use rustc_hir as hir;
 use rustc_middle::ty::util::CheckRegions;
 use rustc_middle::ty::GenericArgs;
@@ -17,6 +16,8 @@ use rustc_span::Span;
 use rustc_trait_selection::traits;
 use std::ops::ControlFlow;
 
+use crate::errors;
+
 #[instrument(skip(tcx), level = "debug")]
 pub(crate) fn orphan_check_impl(
     tcx: TyCtxt<'_>,
@@ -259,49 +260,30 @@ fn do_orphan_check_impl<'tcx>(
             match local_impl {
                 LocalImpl::Allow => {}
                 LocalImpl::Disallow { problematic_kind } => {
-                    let msg = format!(
-                        "traits with a default impl, like `{trait}`, \
-                                cannot be implemented for {problematic_kind} `{self_ty}`",
-                        trait = tcx.def_path_str(trait_def_id),
-                    );
-                    let label = format!(
-                        "a trait object implements `{trait}` if and only if `{trait}` \
-                                is one of the trait object's trait bounds",
-                        trait = tcx.def_path_str(trait_def_id),
-                    );
-                    let sp = tcx.def_span(def_id);
-                    let reported =
-                        struct_span_err!(tcx.sess, sp, E0321, "{}", msg).note(label).emit();
-                    return Err(reported);
+                    return Err(tcx.sess.emit_err(errors::TraitsWithDefaultImpl {
+                        span: tcx.def_span(def_id),
+                        traits: tcx.def_path_str(trait_def_id),
+                        problematic_kind,
+                        self_ty,
+                    }));
                 }
             }
         } else {
-            if let Some((msg, label)) = match nonlocal_impl {
-                NonlocalImpl::Allow => None,
-                NonlocalImpl::DisallowBecauseNonlocal => Some((
-                    format!(
-                        "cross-crate traits with a default impl, like `{}`, \
-                                can only be implemented for a struct/enum type \
-                                defined in the current crate",
-                        tcx.def_path_str(trait_def_id)
-                    ),
-                    "can't implement cross-crate trait for type in another crate",
-                )),
-                NonlocalImpl::DisallowOther => Some((
-                    format!(
-                        "cross-crate traits with a default impl, like `{}`, can \
-                                only be implemented for a struct/enum type, not `{}`",
-                        tcx.def_path_str(trait_def_id),
-                        self_ty
-                    ),
-                    "can't implement cross-crate trait with a default impl for \
-                            non-struct/enum type",
-                )),
-            } {
-                let sp = tcx.def_span(def_id);
-                let reported =
-                    struct_span_err!(tcx.sess, sp, E0321, "{}", msg).span_label(sp, label).emit();
-                return Err(reported);
+            match nonlocal_impl {
+                NonlocalImpl::Allow => {}
+                NonlocalImpl::DisallowBecauseNonlocal => {
+                    return Err(tcx.sess.emit_err(errors::CrossCrateTraitsDefined {
+                        span: tcx.def_span(def_id),
+                        traits: tcx.def_path_str(trait_def_id),
+                    }));
+                }
+                NonlocalImpl::DisallowOther => {
+                    return Err(tcx.sess.emit_err(errors::CrossCrateTraits {
+                        span: tcx.def_span(def_id),
+                        traits: tcx.def_path_str(trait_def_id),
+                        self_ty,
+                    }));
+                }
             }
         }
     }
@@ -322,19 +304,18 @@ fn emit_orphan_check_error<'tcx>(
     let self_ty = trait_ref.self_ty();
     Err(match err {
         traits::OrphanCheckErr::NonLocalInputType(tys) => {
-            let msg = match self_ty.kind() {
-                ty::Adt(..) => "can be implemented for types defined outside of the crate",
-                _ if self_ty.is_primitive() => "can be implemented for primitive types",
-                _ => "can be implemented for arbitrary types",
-            };
-            let mut err = struct_span_err!(
-                tcx.sess,
-                sp,
-                E0117,
-                "only traits defined in the current crate {msg}"
-            );
-            err.span_label(sp, "impl doesn't use only types from inside the current crate");
+            let (mut opaque, mut foreign, mut name, mut pointer, mut ty_diag) =
+                (Vec::new(), Vec::new(), Vec::new(), Vec::new(), Vec::new());
+            let mut sugg = None;
             for &(mut ty, is_target_ty) in &tys {
+                let span = if is_target_ty {
+                    // Point at `D<A>` in `impl<A, B> for C<B> in D<A>`
+                    self_ty_span
+                } else {
+                    // Point at `C<B>` in `impl<A, B> for C<B> in D<A>`
+                    trait_span
+                };
+
                 ty = tcx.erase_regions(ty);
                 ty = match ty.kind() {
                     // Remove the type arguments from the output, as they are not relevant.
@@ -345,50 +326,103 @@ fn emit_orphan_check_error<'tcx>(
                     ty::Adt(def, _) => Ty::new_adt(tcx, *def, ty::List::empty()),
                     _ => ty,
                 };
-                let msg = |ty: &str, postfix: &str| {
-                    format!("{ty} is not defined in the current crate{postfix}")
-                };
 
-                let this = |name: &str| {
-                    if !trait_ref.def_id.is_local() && !is_target_ty {
-                        msg("this", " because this is a foreign trait")
+                fn push_to_foreign_or_name<'tcx>(
+                    is_foreign: bool,
+                    foreign: &mut Vec<errors::OnlyCurrentTraitsForeign>,
+                    name: &mut Vec<errors::OnlyCurrentTraitsName<'tcx>>,
+                    span: Span,
+                    sname: &'tcx str,
+                ) {
+                    if is_foreign {
+                        foreign.push(errors::OnlyCurrentTraitsForeign { span })
                     } else {
-                        msg("this", &format!(" because {name} are always foreign"))
+                        name.push(errors::OnlyCurrentTraitsName { span, name: sname });
+                    }
+                }
+
+                let is_foreign = !trait_ref.def_id.is_local() && !is_target_ty;
+
+                match &ty.kind() {
+                    ty::Slice(_) => {
+                        push_to_foreign_or_name(
+                            is_foreign,
+                            &mut foreign,
+                            &mut name,
+                            span,
+                            "slices",
+                        );
+                    }
+                    ty::Array(..) => {
+                        push_to_foreign_or_name(
+                            is_foreign,
+                            &mut foreign,
+                            &mut name,
+                            span,
+                            "arrays",
+                        );
+                    }
+                    ty::Tuple(..) => {
+                        push_to_foreign_or_name(
+                            is_foreign,
+                            &mut foreign,
+                            &mut name,
+                            span,
+                            "tuples",
+                        );
                     }
-                };
-                let msg = match &ty.kind() {
-                    ty::Slice(_) => this("slices"),
-                    ty::Array(..) => this("arrays"),
-                    ty::Tuple(..) => this("tuples"),
                     ty::Alias(ty::Opaque, ..) => {
-                        "type alias impl trait is treated as if it were foreign, \
-                        because its hidden type could be from a foreign crate"
-                            .to_string()
+                        opaque.push(errors::OnlyCurrentTraitsOpaque { span })
                     }
                     ty::RawPtr(ptr_ty) => {
-                        emit_newtype_suggestion_for_raw_ptr(
-                            full_impl_span,
-                            self_ty,
-                            self_ty_span,
-                            ptr_ty,
-                            &mut err,
-                        );
-
-                        msg(&format!("`{ty}`"), " because raw pointers are always foreign")
+                        if !self_ty.has_param() {
+                            let mut_key = ptr_ty.mutbl.prefix_str();
+                            sugg = Some(errors::OnlyCurrentTraitsPointerSugg {
+                                wrapper_span: self_ty_span,
+                                struct_span: full_impl_span.shrink_to_lo(),
+                                mut_key,
+                                ptr_ty: ptr_ty.ty,
+                            });
+                        }
+                        pointer.push(errors::OnlyCurrentTraitsPointer { span, pointer: ty });
                     }
-                    _ => msg(&format!("`{ty}`"), ""),
-                };
-
-                if is_target_ty {
-                    // Point at `D<A>` in `impl<A, B> for C<B> in D<A>`
-                    err.span_label(self_ty_span, msg);
-                } else {
-                    // Point at `C<B>` in `impl<A, B> for C<B> in D<A>`
-                    err.span_label(trait_span, msg);
+                    _ => ty_diag.push(errors::OnlyCurrentTraitsTy { span, ty }),
                 }
             }
-            err.note("define and implement a trait or new type instead");
-            err.emit()
+
+            let err_struct = match self_ty.kind() {
+                ty::Adt(..) => errors::OnlyCurrentTraits::Outside {
+                    span: sp,
+                    note: (),
+                    opaque,
+                    foreign,
+                    name,
+                    pointer,
+                    ty: ty_diag,
+                    sugg,
+                },
+                _ if self_ty.is_primitive() => errors::OnlyCurrentTraits::Primitive {
+                    span: sp,
+                    note: (),
+                    opaque,
+                    foreign,
+                    name,
+                    pointer,
+                    ty: ty_diag,
+                    sugg,
+                },
+                _ => errors::OnlyCurrentTraits::Arbitrary {
+                    span: sp,
+                    note: (),
+                    opaque,
+                    foreign,
+                    name,
+                    pointer,
+                    ty: ty_diag,
+                    sugg,
+                },
+            };
+            tcx.sess.emit_err(err_struct)
         }
         traits::OrphanCheckErr::UncoveredTy(param_ty, local_type) => {
             let mut sp = sp;
@@ -399,85 +433,18 @@ fn emit_orphan_check_error<'tcx>(
             }
 
             match local_type {
-                Some(local_type) => struct_span_err!(
-                    tcx.sess,
-                    sp,
-                    E0210,
-                    "type parameter `{}` must be covered by another type \
-                    when it appears before the first local type (`{}`)",
+                Some(local_type) => tcx.sess.emit_err(errors::TyParamFirstLocal {
+                    span: sp,
+                    note: (),
                     param_ty,
-                    local_type
-                )
-                .span_label(
-                    sp,
-                    format!(
-                        "type parameter `{param_ty}` must be covered by another type \
-                    when it appears before the first local type (`{local_type}`)"
-                    ),
-                )
-                .note(
-                    "implementing a foreign trait is only possible if at \
-                        least one of the types for which it is implemented is local, \
-                        and no uncovered type parameters appear before that first \
-                        local type",
-                )
-                .note(
-                    "in this case, 'before' refers to the following order: \
-                        `impl<..> ForeignTrait<T1, ..., Tn> for T0`, \
-                        where `T0` is the first and `Tn` is the last",
-                )
-                .emit(),
-                None => struct_span_err!(
-                    tcx.sess,
-                    sp,
-                    E0210,
-                    "type parameter `{}` must be used as the type parameter for some \
-                    local type (e.g., `MyStruct<{}>`)",
-                    param_ty,
-                    param_ty
-                )
-                .span_label(
-                    sp,
-                    format!(
-                        "type parameter `{param_ty}` must be used as the type parameter for some \
-                    local type",
-                    ),
-                )
-                .note(
-                    "implementing a foreign trait is only possible if at \
-                        least one of the types for which it is implemented is local",
-                )
-                .note(
-                    "only traits defined in the current crate can be \
-                        implemented for a type parameter",
-                )
-                .emit(),
+                    local_type,
+                }),
+                None => tcx.sess.emit_err(errors::TyParamSome { span: sp, note: (), param_ty }),
             }
         }
     })
 }
 
-fn emit_newtype_suggestion_for_raw_ptr(
-    full_impl_span: Span,
-    self_ty: Ty<'_>,
-    self_ty_span: Span,
-    ptr_ty: &ty::TypeAndMut<'_>,
-    diag: &mut Diagnostic,
-) {
-    if !self_ty.has_param() {
-        let mut_key = ptr_ty.mutbl.prefix_str();
-        let msg_sugg = "consider introducing a new wrapper type".to_owned();
-        let sugg = vec![
-            (
-                full_impl_span.shrink_to_lo(),
-                format!("struct WrapperType(*{}{});\n\n", mut_key, ptr_ty.ty),
-            ),
-            (self_ty_span, "WrapperType".to_owned()),
-        ];
-        diag.multipart_suggestion(msg_sugg, sugg, rustc_errors::Applicability::MaybeIncorrect);
-    }
-}
-
 /// Lint impls of auto traits if they are likely to have
 /// unsound or surprising effects on auto impls.
 fn lint_auto_trait_impl<'tcx>(
diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs
index 640138a3e5e..9636c614446 100644
--- a/compiler/rustc_hir_analysis/src/collect.rs
+++ b/compiler/rustc_hir_analysis/src/collect.rs
@@ -14,14 +14,11 @@
 //! At present, however, we do run collection across all items in the
 //! crate as a kind of pass. This should eventually be factored away.
 
-use crate::astconv::AstConv;
-use crate::check::intrinsic::intrinsic_operation_unsafety;
-use crate::errors;
-use hir::def::DefKind;
 use rustc_data_structures::captures::Captures;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_errors::{Applicability, DiagnosticBuilder, ErrorGuaranteed, StashKey};
 use rustc_hir as hir;
+use rustc_hir::def::DefKind;
 use rustc_hir::def_id::{DefId, LocalDefId, LocalModDefId};
 use rustc_hir::intravisit::{self, Visitor};
 use rustc_hir::{GenericParamKind, Node};
@@ -40,6 +37,11 @@ use rustc_trait_selection::traits::ObligationCtxt;
 use std::iter;
 use std::ops::Bound;
 
+use crate::astconv::AstConv;
+use crate::check::intrinsic::intrinsic_operation_unsafety;
+use crate::errors;
+pub use type_of::test_opaque_hidden_types;
+
 mod generics_of;
 mod item_bounds;
 mod predicates_of;
diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs
index 47a412c2110..d7bd2a7b17f 100644
--- a/compiler/rustc_hir_analysis/src/collect/type_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs
@@ -11,6 +11,7 @@ use rustc_span::{Span, DUMMY_SP};
 
 use super::ItemCtxt;
 use super::{bad_placeholder, is_suggestable_infer_ty};
+pub use opaque::test_opaque_hidden_types;
 
 mod opaque;
 
diff --git a/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs b/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs
index 0544c5ca866..e8d5264c2b8 100644
--- a/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs
+++ b/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs
@@ -1,12 +1,25 @@
 use rustc_errors::StashKey;
-use rustc_hir::def_id::LocalDefId;
+use rustc_hir::def::DefKind;
+use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID};
 use rustc_hir::intravisit::{self, Visitor};
 use rustc_hir::{self as hir, def, Expr, ImplItem, Item, Node, TraitItem};
 use rustc_middle::hir::nested_filter;
 use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt};
-use rustc_span::DUMMY_SP;
+use rustc_span::{sym, DUMMY_SP};
 
-use crate::errors::{TaitForwardCompat, UnconstrainedOpaqueType};
+use crate::errors::{TaitForwardCompat, TypeOf, UnconstrainedOpaqueType};
+
+pub fn test_opaque_hidden_types(tcx: TyCtxt<'_>) {
+    if tcx.has_attr(CRATE_DEF_ID, sym::rustc_hidden_type_of_opaques) {
+        for id in tcx.hir().items() {
+            if matches!(tcx.def_kind(id.owner_id), DefKind::OpaqueTy) {
+                let type_of = tcx.type_of(id.owner_id).instantiate_identity();
+
+                tcx.sess.emit_err(TypeOf { span: tcx.def_span(id.owner_id), type_of });
+            }
+        }
+    }
+}
 
 /// Checks "defining uses" of opaque `impl Trait` types to ensure that they meet the restrictions
 /// laid for "higher-order pattern unification".
diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs
index 1120585f1aa..6a2db1d0627 100644
--- a/compiler/rustc_hir_analysis/src/errors.rs
+++ b/compiler/rustc_hir_analysis/src/errors.rs
@@ -467,6 +467,14 @@ pub(crate) struct VariancesOf {
     pub variances_of: String,
 }
 
+#[derive(Diagnostic)]
+#[diag(hir_analysis_type_of)]
+pub(crate) struct TypeOf<'tcx> {
+    #[primary_span]
+    pub span: Span,
+    pub type_of: Ty<'tcx>,
+}
+
 #[derive(Diagnostic)]
 #[diag(hir_analysis_pass_to_variadic_function, code = "E0617")]
 pub(crate) struct PassToVariadicFunction<'tcx, 'a> {
@@ -675,7 +683,6 @@ pub(crate) struct SIMDFFIHighlyExperimental {
 }
 
 #[derive(Diagnostic)]
-
 pub enum ImplNotMarkedDefault {
     #[diag(hir_analysis_impl_not_marked_default, code = "E0520")]
     #[note]
@@ -1151,3 +1158,174 @@ pub struct ImplForTyRequires {
     pub trait_name: String,
     pub ty: String,
 }
+
+#[derive(Diagnostic)]
+#[diag(hir_analysis_traits_with_defualt_impl, code = "E0321")]
+#[note]
+pub struct TraitsWithDefaultImpl<'a> {
+    #[primary_span]
+    pub span: Span,
+    pub traits: String,
+    pub problematic_kind: &'a str,
+    pub self_ty: Ty<'a>,
+}
+
+#[derive(Diagnostic)]
+#[diag(hir_analysis_cross_crate_traits, code = "E0321")]
+pub struct CrossCrateTraits<'a> {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+    pub traits: String,
+    pub self_ty: Ty<'a>,
+}
+
+#[derive(Diagnostic)]
+#[diag(hir_analysis_cross_crate_traits_defined, code = "E0321")]
+pub struct CrossCrateTraitsDefined {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+    pub traits: String,
+}
+
+#[derive(Diagnostic)]
+#[diag(hir_analysis_ty_param_first_local, code = "E0210")]
+#[note]
+pub struct TyParamFirstLocal<'a> {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+    #[note(hir_analysis_case_note)]
+    pub note: (),
+    pub param_ty: Ty<'a>,
+    pub local_type: Ty<'a>,
+}
+
+#[derive(Diagnostic)]
+#[diag(hir_analysis_ty_param_some, code = "E0210")]
+#[note]
+pub struct TyParamSome<'a> {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+    #[note(hir_analysis_only_note)]
+    pub note: (),
+    pub param_ty: Ty<'a>,
+}
+
+#[derive(Diagnostic)]
+pub enum OnlyCurrentTraits<'a> {
+    #[diag(hir_analysis_only_current_traits_outside, code = "E0117")]
+    Outside {
+        #[primary_span]
+        #[label(hir_analysis_only_current_traits_label)]
+        span: Span,
+        #[note(hir_analysis_only_current_traits_note)]
+        note: (),
+        #[subdiagnostic]
+        opaque: Vec<OnlyCurrentTraitsOpaque>,
+        #[subdiagnostic]
+        foreign: Vec<OnlyCurrentTraitsForeign>,
+        #[subdiagnostic]
+        name: Vec<OnlyCurrentTraitsName<'a>>,
+        #[subdiagnostic]
+        pointer: Vec<OnlyCurrentTraitsPointer<'a>>,
+        #[subdiagnostic]
+        ty: Vec<OnlyCurrentTraitsTy<'a>>,
+        #[subdiagnostic]
+        sugg: Option<OnlyCurrentTraitsPointerSugg<'a>>,
+    },
+    #[diag(hir_analysis_only_current_traits_primitive, code = "E0117")]
+    Primitive {
+        #[primary_span]
+        #[label(hir_analysis_only_current_traits_label)]
+        span: Span,
+        #[note(hir_analysis_only_current_traits_note)]
+        note: (),
+        #[subdiagnostic]
+        opaque: Vec<OnlyCurrentTraitsOpaque>,
+        #[subdiagnostic]
+        foreign: Vec<OnlyCurrentTraitsForeign>,
+        #[subdiagnostic]
+        name: Vec<OnlyCurrentTraitsName<'a>>,
+        #[subdiagnostic]
+        pointer: Vec<OnlyCurrentTraitsPointer<'a>>,
+        #[subdiagnostic]
+        ty: Vec<OnlyCurrentTraitsTy<'a>>,
+        #[subdiagnostic]
+        sugg: Option<OnlyCurrentTraitsPointerSugg<'a>>,
+    },
+    #[diag(hir_analysis_only_current_traits_arbitrary, code = "E0117")]
+    Arbitrary {
+        #[primary_span]
+        #[label(hir_analysis_only_current_traits_label)]
+        span: Span,
+        #[note(hir_analysis_only_current_traits_note)]
+        note: (),
+        #[subdiagnostic]
+        opaque: Vec<OnlyCurrentTraitsOpaque>,
+        #[subdiagnostic]
+        foreign: Vec<OnlyCurrentTraitsForeign>,
+        #[subdiagnostic]
+        name: Vec<OnlyCurrentTraitsName<'a>>,
+        #[subdiagnostic]
+        pointer: Vec<OnlyCurrentTraitsPointer<'a>>,
+        #[subdiagnostic]
+        ty: Vec<OnlyCurrentTraitsTy<'a>>,
+        #[subdiagnostic]
+        sugg: Option<OnlyCurrentTraitsPointerSugg<'a>>,
+    },
+}
+
+#[derive(Subdiagnostic)]
+#[label(hir_analysis_only_current_traits_opaque)]
+pub struct OnlyCurrentTraitsOpaque {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(Subdiagnostic)]
+#[label(hir_analysis_only_current_traits_foreign)]
+pub struct OnlyCurrentTraitsForeign {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(Subdiagnostic)]
+#[label(hir_analysis_only_current_traits_name)]
+pub struct OnlyCurrentTraitsName<'a> {
+    #[primary_span]
+    pub span: Span,
+    pub name: &'a str,
+}
+
+#[derive(Subdiagnostic)]
+#[label(hir_analysis_only_current_traits_pointer)]
+pub struct OnlyCurrentTraitsPointer<'a> {
+    #[primary_span]
+    pub span: Span,
+    pub pointer: Ty<'a>,
+}
+
+#[derive(Subdiagnostic)]
+#[label(hir_analysis_only_current_traits_ty)]
+pub struct OnlyCurrentTraitsTy<'a> {
+    #[primary_span]
+    pub span: Span,
+    pub ty: Ty<'a>,
+}
+
+#[derive(Subdiagnostic)]
+#[multipart_suggestion(
+    hir_analysis_only_current_traits_pointer_sugg,
+    applicability = "maybe-incorrect"
+)]
+pub struct OnlyCurrentTraitsPointerSugg<'a> {
+    #[suggestion_part(code = "WrapperType")]
+    pub wrapper_span: Span,
+    #[suggestion_part(code = "struct WrapperType(*{mut_key}{ptr_ty});\n\n")]
+    pub struct_span: Span,
+    pub mut_key: &'a str,
+    pub ptr_ty: Ty<'a>,
+}
diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs
index 88f3db03a4e..0622aa2ee80 100644
--- a/compiler/rustc_hir_analysis/src/lib.rs
+++ b/compiler/rustc_hir_analysis/src/lib.rs
@@ -214,6 +214,10 @@ pub fn check_crate(tcx: TyCtxt<'_>) -> Result<(), ErrorGuaranteed> {
         tcx.hir().for_each_module(|module| tcx.ensure().check_mod_item_types(module))
     });
 
+    if tcx.features().rustc_attrs {
+        tcx.sess.track_errors(|| collect::test_opaque_hidden_types(tcx))?;
+    }
+
     // Freeze definitions as we don't add new ones at this point. This improves performance by
     // allowing lock-free access to them.
     tcx.untracked().definitions.freeze();
diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs
index 65ec2f232ae..f379e8477e3 100644
--- a/compiler/rustc_hir_typeck/src/demand.rs
+++ b/compiler/rustc_hir_typeck/src/demand.rs
@@ -58,7 +58,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             || self.suggest_into(err, expr, expr_ty, expected)
             || self.suggest_floating_point_literal(err, expr, expected)
             || self.suggest_null_ptr_for_literal_zero_given_to_ptr_arg(err, expr, expected)
-            || self.suggest_coercing_result_via_try_operator(err, expr, expected, expr_ty);
+            || self.suggest_coercing_result_via_try_operator(err, expr, expected, expr_ty)
+            || self.suggest_missing_unwrap_expect(err, expr, expected, expr_ty);
 
         if !suggested {
             self.note_source_of_type_mismatch_constraint(
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
index 04220397872..13aa6454bc3 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
@@ -6,6 +6,7 @@ use crate::method::probe::{IsSuggestion, Mode, ProbeScope};
 use rustc_ast::util::parser::{ExprPrecedence, PREC_POSTFIX};
 use rustc_errors::{Applicability, Diagnostic, MultiSpan};
 use rustc_hir as hir;
+use rustc_hir::def::Res;
 use rustc_hir::def::{CtorKind, CtorOf, DefKind};
 use rustc_hir::lang_items::LangItem;
 use rustc_hir::{
@@ -1738,4 +1739,83 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             // If the field is hygienic it must come from the same syntax context.
             && self.tcx.def_ident_span(field.did).unwrap().normalize_to_macros_2_0().eq_ctxt(span)
     }
+
+    pub(crate) fn suggest_missing_unwrap_expect(
+        &self,
+        err: &mut Diagnostic,
+        expr: &hir::Expr<'tcx>,
+        expected: Ty<'tcx>,
+        found: Ty<'tcx>,
+    ) -> bool {
+        let ty::Adt(adt, args) = found.kind() else { return false };
+        let ret_ty_matches = |diagnostic_item| {
+            if let Some(ret_ty) = self
+                    .ret_coercion
+                    .as_ref()
+                    .map(|c| self.resolve_vars_if_possible(c.borrow().expected_ty()))
+                    && let ty::Adt(kind, _) = ret_ty.kind()
+                    && self.tcx.get_diagnostic_item(diagnostic_item) == Some(kind.did())
+                {
+                    true
+                } else {
+                    false
+                }
+        };
+
+        // don't suggest anything like `Ok(ok_val).unwrap()` , `Some(some_val).unwrap()`,
+        // `None.unwrap()` etc.
+        let is_ctor = matches!(
+            expr.kind,
+            hir::ExprKind::Call(
+                hir::Expr {
+                    kind: hir::ExprKind::Path(hir::QPath::Resolved(
+                        None,
+                        hir::Path { res: Res::Def(hir::def::DefKind::Ctor(_, _), _), .. },
+                    )),
+                    ..
+                },
+                ..,
+            ) | hir::ExprKind::Path(hir::QPath::Resolved(
+                None,
+                hir::Path { res: Res::Def(hir::def::DefKind::Ctor(_, _), _), .. },
+            )),
+        );
+
+        let (article, kind, variant, sugg_operator) =
+            if self.tcx.is_diagnostic_item(sym::Result, adt.did()) {
+                ("a", "Result", "Err", ret_ty_matches(sym::Result))
+            } else if self.tcx.is_diagnostic_item(sym::Option, adt.did()) {
+                ("an", "Option", "None", ret_ty_matches(sym::Option))
+            } else {
+                return false;
+            };
+        if is_ctor || !self.can_coerce(args.type_at(0), expected) {
+            return false;
+        }
+
+        let (msg, sugg) = if sugg_operator {
+            (
+                format!(
+                    "use the `?` operator to extract the `{found}` value, propagating \
+                            {article} `{kind}::{variant}` value to the caller"
+                ),
+                "?",
+            )
+        } else {
+            (
+                format!(
+                    "consider using `{kind}::expect` to unwrap the `{found}` value, \
+                                panicking if the value is {article} `{kind}::{variant}`"
+                ),
+                ".expect(\"REASON\")",
+            )
+        };
+        err.span_suggestion_verbose(
+            expr.span.shrink_to_hi(),
+            msg,
+            sugg,
+            Applicability::HasPlaceholders,
+        );
+        return true;
+    }
 }
diff --git a/compiler/rustc_infer/src/infer/canonical/mod.rs b/compiler/rustc_infer/src/infer/canonical/mod.rs
index 41787ee2942..280dcae3451 100644
--- a/compiler/rustc_infer/src/infer/canonical/mod.rs
+++ b/compiler/rustc_infer/src/infer/canonical/mod.rs
@@ -152,7 +152,7 @@ impl<'tcx> InferCtxt<'tcx> {
                 )
                 .into(),
             CanonicalVarKind::Effect => {
-                let vid = self.inner.borrow_mut().effect_unification_table().new_key(None);
+                let vid = self.inner.borrow_mut().effect_unification_table().new_key(None).vid;
                 ty::Const::new_infer(self.tcx, ty::InferConst::EffectVar(vid), self.tcx.types.bool)
                     .into()
             }
diff --git a/compiler/rustc_infer/src/infer/combine.rs b/compiler/rustc_infer/src/infer/combine.rs
index ee13eb0271e..2a9e20b9f8f 100644
--- a/compiler/rustc_infer/src/infer/combine.rs
+++ b/compiler/rustc_infer/src/infer/combine.rs
@@ -320,7 +320,7 @@ impl<'tcx> InferCtxt<'tcx> {
     #[instrument(level = "debug", skip(self))]
     fn unify_const_variable(
         &self,
-        target_vid: ty::ConstVid<'tcx>,
+        target_vid: ty::ConstVid,
         ct: ty::Const<'tcx>,
         param_env: ty::ParamEnv<'tcx>,
     ) -> RelateResult<'tcx, ty::Const<'tcx>> {
@@ -381,7 +381,7 @@ impl<'tcx> InferCtxt<'tcx> {
     fn unify_effect_variable(
         &self,
         vid_is_expected: bool,
-        vid: ty::EffectVid<'tcx>,
+        vid: ty::EffectVid,
         val: EffectVarValue<'tcx>,
     ) -> RelateResult<'tcx, ty::Const<'tcx>> {
         self.inner
diff --git a/compiler/rustc_infer/src/infer/freshen.rs b/compiler/rustc_infer/src/infer/freshen.rs
index 0596ce373cf..35204478c54 100644
--- a/compiler/rustc_infer/src/infer/freshen.rs
+++ b/compiler/rustc_infer/src/infer/freshen.rs
@@ -42,7 +42,7 @@ pub struct TypeFreshener<'a, 'tcx> {
     ty_freshen_count: u32,
     const_freshen_count: u32,
     ty_freshen_map: FxHashMap<ty::InferTy, Ty<'tcx>>,
-    const_freshen_map: FxHashMap<ty::InferConst<'tcx>, ty::Const<'tcx>>,
+    const_freshen_map: FxHashMap<ty::InferConst, ty::Const<'tcx>>,
 }
 
 impl<'a, 'tcx> TypeFreshener<'a, 'tcx> {
@@ -79,12 +79,12 @@ impl<'a, 'tcx> TypeFreshener<'a, 'tcx> {
     fn freshen_const<F>(
         &mut self,
         opt_ct: Option<ty::Const<'tcx>>,
-        key: ty::InferConst<'tcx>,
+        key: ty::InferConst,
         freshener: F,
         ty: Ty<'tcx>,
     ) -> ty::Const<'tcx>
     where
-        F: FnOnce(u32) -> ty::InferConst<'tcx>,
+        F: FnOnce(u32) -> ty::InferConst,
     {
         if let Some(ct) = opt_ct {
             return ct.fold_with(self);
diff --git a/compiler/rustc_infer/src/infer/fudge.rs b/compiler/rustc_infer/src/infer/fudge.rs
index 2f371c4fe31..7e878ac06c7 100644
--- a/compiler/rustc_infer/src/infer/fudge.rs
+++ b/compiler/rustc_infer/src/infer/fudge.rs
@@ -1,3 +1,4 @@
+use rustc_middle::infer::unify_key::ConstVidKey;
 use rustc_middle::ty::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable};
 use rustc_middle::ty::{self, ConstVid, FloatVid, IntVid, RegionVid, Ty, TyCtxt, TyVid};
 
@@ -23,14 +24,14 @@ where
 }
 
 fn const_vars_since_snapshot<'tcx>(
-    table: &mut UnificationTable<'_, 'tcx, ConstVid<'tcx>>,
+    table: &mut UnificationTable<'_, 'tcx, ConstVidKey<'tcx>>,
     snapshot_var_len: usize,
-) -> (Range<ConstVid<'tcx>>, Vec<ConstVariableOrigin>) {
+) -> (Range<ConstVid>, Vec<ConstVariableOrigin>) {
     let range = vars_since_snapshot(table, snapshot_var_len);
     (
-        range.start..range.end,
-        (range.start.index..range.end.index)
-            .map(|index| table.probe_value(ConstVid::from_index(index)).origin)
+        range.start.vid..range.end.vid,
+        (range.start.index()..range.end.index())
+            .map(|index| table.probe_value(ConstVid::from_u32(index)).origin)
             .collect(),
     )
 }
@@ -172,7 +173,7 @@ pub struct InferenceFudger<'a, 'tcx> {
     int_vars: Range<IntVid>,
     float_vars: Range<FloatVid>,
     region_vars: (Range<RegionVid>, Vec<RegionVariableOrigin>),
-    const_vars: (Range<ConstVid<'tcx>>, Vec<ConstVariableOrigin>),
+    const_vars: (Range<ConstVid>, Vec<ConstVariableOrigin>),
 }
 
 impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for InferenceFudger<'a, 'tcx> {
@@ -235,7 +236,7 @@ impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for InferenceFudger<'a, 'tcx> {
             if self.const_vars.0.contains(&vid) {
                 // This variable was created during the fudging.
                 // Recreate it with a fresh variable here.
-                let idx = (vid.index - self.const_vars.0.start.index) as usize;
+                let idx = (vid.index() - self.const_vars.0.start.index()) as usize;
                 let origin = self.const_vars.1[idx];
                 self.infcx.next_const_var(ct.ty(), origin)
             } else {
diff --git a/compiler/rustc_infer/src/infer/generalize.rs b/compiler/rustc_infer/src/infer/generalize.rs
index c1e65ffe0a6..17fe3aa7b44 100644
--- a/compiler/rustc_infer/src/infer/generalize.rs
+++ b/compiler/rustc_infer/src/infer/generalize.rs
@@ -17,7 +17,7 @@ pub(super) fn generalize<'tcx, D: GeneralizerDelegate<'tcx>, T: Into<Term<'tcx>>
     infcx: &InferCtxt<'tcx>,
     delegate: &mut D,
     term: T,
-    for_vid: impl Into<ty::TermVid<'tcx>>,
+    for_vid: impl Into<ty::TermVid>,
     ambient_variance: ty::Variance,
 ) -> RelateResult<'tcx, Generalization<T>> {
     let (for_universe, root_vid) = match for_vid.into() {
@@ -27,7 +27,7 @@ pub(super) fn generalize<'tcx, D: GeneralizerDelegate<'tcx>, T: Into<Term<'tcx>>
         ),
         ty::TermVid::Const(ct_vid) => (
             infcx.probe_const_var(ct_vid).unwrap_err(),
-            ty::TermVid::Const(infcx.inner.borrow_mut().const_unification_table().find(ct_vid)),
+            ty::TermVid::Const(infcx.inner.borrow_mut().const_unification_table().find(ct_vid).vid),
         ),
     };
 
@@ -127,7 +127,7 @@ struct Generalizer<'me, 'tcx, D> {
     /// The vid of the type variable that is in the process of being
     /// instantiated. If we find this within the value we are folding,
     /// that means we would have created a cyclic value.
-    root_vid: ty::TermVid<'tcx>,
+    root_vid: ty::TermVid,
 
     /// The universe of the type variable that is in the process of being
     /// instantiated. If we find anything that this universe cannot name,
@@ -376,7 +376,7 @@ where
                 // `vid` are related and we'd be inferring an infinitely
                 // deep const.
                 if ty::TermVid::Const(
-                    self.infcx.inner.borrow_mut().const_unification_table().find(vid),
+                    self.infcx.inner.borrow_mut().const_unification_table().find(vid).vid,
                 ) == self.root_vid
                 {
                     return Err(self.cyclic_term_error());
@@ -394,10 +394,14 @@ where
                         if self.for_universe.can_name(universe) {
                             Ok(c)
                         } else {
-                            let new_var_id = variable_table.new_key(ConstVarValue {
-                                origin: var_value.origin,
-                                val: ConstVariableValue::Unknown { universe: self.for_universe },
-                            });
+                            let new_var_id = variable_table
+                                .new_key(ConstVarValue {
+                                    origin: var_value.origin,
+                                    val: ConstVariableValue::Unknown {
+                                        universe: self.for_universe,
+                                    },
+                                })
+                                .vid;
                             Ok(ty::Const::new_var(self.tcx(), new_var_id, c.ty()))
                         }
                     }
diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs
index 8ffcf1fce9c..4ee897ffe98 100644
--- a/compiler/rustc_infer/src/infer/mod.rs
+++ b/compiler/rustc_infer/src/infer/mod.rs
@@ -6,7 +6,9 @@ pub use self::RegionVariableOrigin::*;
 pub use self::SubregionOrigin::*;
 pub use self::ValuePairs::*;
 pub use combine::ObligationEmittingRelation;
+use rustc_data_structures::captures::Captures;
 use rustc_data_structures::undo_log::UndoLogs;
+use rustc_middle::infer::unify_key::{ConstVidKey, EffectVidKey};
 
 use self::opaque_types::OpaqueTypeStorage;
 pub(crate) use self::undo_log::{InferCtxtUndoLogs, Snapshot, UndoLog};
@@ -40,7 +42,6 @@ use rustc_span::{Span, DUMMY_SP};
 
 use std::cell::{Cell, RefCell};
 use std::fmt;
-use std::marker::PhantomData;
 
 use self::combine::CombineFields;
 use self::error_reporting::TypeErrCtxt;
@@ -85,7 +86,7 @@ pub struct InferOk<'tcx, T> {
 pub type InferResult<'tcx, T> = Result<InferOk<'tcx, T>, TypeError<'tcx>>;
 
 pub type UnitResult<'tcx> = RelateResult<'tcx, ()>; // "unify result"
-pub type FixupResult<'tcx, T> = Result<T, FixupError<'tcx>>; // "fixup result"
+pub type FixupResult<T> = Result<T, FixupError>; // "fixup result"
 
 pub(crate) type UnificationTable<'a, 'tcx, T> = ut::UnificationTable<
     ut::InPlace<T, &'a mut ut::UnificationStorage<T>, &'a mut InferCtxtUndoLogs<'tcx>>,
@@ -108,7 +109,7 @@ pub struct InferCtxtInner<'tcx> {
     type_variable_storage: type_variable::TypeVariableStorage<'tcx>,
 
     /// Map from const parameter variable to the kind of const it represents.
-    const_unification_storage: ut::UnificationTableStorage<ty::ConstVid<'tcx>>,
+    const_unification_storage: ut::UnificationTableStorage<ConstVidKey<'tcx>>,
 
     /// Map from integral variable to the kind of integer it represents.
     int_unification_storage: ut::UnificationTableStorage<ty::IntVid>,
@@ -117,7 +118,7 @@ pub struct InferCtxtInner<'tcx> {
     float_unification_storage: ut::UnificationTableStorage<ty::FloatVid>,
 
     /// Map from effect variable to the effect param it represents.
-    effect_unification_storage: ut::UnificationTableStorage<ty::EffectVid<'tcx>>,
+    effect_unification_storage: ut::UnificationTableStorage<EffectVidKey<'tcx>>,
 
     /// Tracks the set of region variables and the constraints between them.
     ///
@@ -224,11 +225,11 @@ impl<'tcx> InferCtxtInner<'tcx> {
     }
 
     #[inline]
-    fn const_unification_table(&mut self) -> UnificationTable<'_, 'tcx, ty::ConstVid<'tcx>> {
+    fn const_unification_table(&mut self) -> UnificationTable<'_, 'tcx, ConstVidKey<'tcx>> {
         self.const_unification_storage.with_log(&mut self.undo_log)
     }
 
-    fn effect_unification_table(&mut self) -> UnificationTable<'_, 'tcx, ty::EffectVid<'tcx>> {
+    fn effect_unification_table(&mut self) -> UnificationTable<'_, 'tcx, EffectVidKey<'tcx>> {
         self.effect_unification_storage.with_log(&mut self.undo_log)
     }
 
@@ -341,7 +342,9 @@ pub struct InferCtxt<'tcx> {
     next_trait_solver: bool,
 }
 
-impl<'tcx> ty::InferCtxtLike<TyCtxt<'tcx>> for InferCtxt<'tcx> {
+impl<'tcx> ty::InferCtxtLike for InferCtxt<'tcx> {
+    type Interner = TyCtxt<'tcx>;
+
     fn universe_of_ty(&self, ty: ty::InferTy) -> Option<ty::UniverseIndex> {
         use InferTy::*;
         match ty {
@@ -357,7 +360,7 @@ impl<'tcx> ty::InferCtxtLike<TyCtxt<'tcx>> for InferCtxt<'tcx> {
         }
     }
 
-    fn universe_of_ct(&self, ct: ty::InferConst<'tcx>) -> Option<ty::UniverseIndex> {
+    fn universe_of_ct(&self, ct: ty::InferConst) -> Option<ty::UniverseIndex> {
         use ty::InferConst::*;
         match ct {
             // Same issue as with `universe_of_ty`
@@ -546,11 +549,11 @@ pub enum NllRegionVariableOrigin {
 
 // FIXME(eddyb) investigate overlap between this and `TyOrConstInferVar`.
 #[derive(Copy, Clone, Debug)]
-pub enum FixupError<'tcx> {
+pub enum FixupError {
     UnresolvedIntTy(IntVid),
     UnresolvedFloatTy(FloatVid),
     UnresolvedTy(TyVid),
-    UnresolvedConst(ConstVid<'tcx>),
+    UnresolvedConst(ConstVid),
 }
 
 /// See the `region_obligations` field for more information.
@@ -561,7 +564,7 @@ pub struct RegionObligation<'tcx> {
     pub origin: SubregionOrigin<'tcx>,
 }
 
-impl<'tcx> fmt::Display for FixupError<'tcx> {
+impl fmt::Display for FixupError {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         use self::FixupError::*;
 
@@ -792,7 +795,7 @@ impl<'tcx> InferCtxt<'tcx> {
         let mut table = inner.effect_unification_table();
 
         (0..table.len())
-            .map(|i| ty::EffectVid { index: i as u32, phantom: PhantomData })
+            .map(|i| ty::EffectVid::from_usize(i))
             .filter(|&vid| table.probe_value(vid).is_none())
             .map(|v| {
                 ty::Const::new_infer(self.tcx, ty::InferConst::EffectVar(v), self.tcx.types.bool)
@@ -1070,15 +1073,20 @@ impl<'tcx> InferCtxt<'tcx> {
             .inner
             .borrow_mut()
             .const_unification_table()
-            .new_key(ConstVarValue { origin, val: ConstVariableValue::Unknown { universe } });
+            .new_key(ConstVarValue { origin, val: ConstVariableValue::Unknown { universe } })
+            .vid;
         ty::Const::new_var(self.tcx, vid, ty)
     }
 
-    pub fn next_const_var_id(&self, origin: ConstVariableOrigin) -> ConstVid<'tcx> {
-        self.inner.borrow_mut().const_unification_table().new_key(ConstVarValue {
-            origin,
-            val: ConstVariableValue::Unknown { universe: self.universe() },
-        })
+    pub fn next_const_var_id(&self, origin: ConstVariableOrigin) -> ConstVid {
+        self.inner
+            .borrow_mut()
+            .const_unification_table()
+            .new_key(ConstVarValue {
+                origin,
+                val: ConstVariableValue::Unknown { universe: self.universe() },
+            })
+            .vid
     }
 
     fn next_int_var_id(&self) -> IntVid {
@@ -1192,11 +1200,15 @@ impl<'tcx> InferCtxt<'tcx> {
                     ),
                     span,
                 };
-                let const_var_id =
-                    self.inner.borrow_mut().const_unification_table().new_key(ConstVarValue {
+                let const_var_id = self
+                    .inner
+                    .borrow_mut()
+                    .const_unification_table()
+                    .new_key(ConstVarValue {
                         origin,
                         val: ConstVariableValue::Unknown { universe: self.universe() },
-                    });
+                    })
+                    .vid;
                 ty::Const::new_var(
                     self.tcx,
                     const_var_id,
@@ -1211,7 +1223,7 @@ impl<'tcx> InferCtxt<'tcx> {
     }
 
     pub fn var_for_effect(&self, param: &ty::GenericParamDef) -> GenericArg<'tcx> {
-        let effect_vid = self.inner.borrow_mut().effect_unification_table().new_key(None);
+        let effect_vid = self.inner.borrow_mut().effect_unification_table().new_key(None).vid;
         let ty = self
             .tcx
             .type_of(param.def_id)
@@ -1331,12 +1343,12 @@ impl<'tcx> InferCtxt<'tcx> {
         self.inner.borrow_mut().type_variables().root_var(var)
     }
 
-    pub fn root_const_var(&self, var: ty::ConstVid<'tcx>) -> ty::ConstVid<'tcx> {
-        self.inner.borrow_mut().const_unification_table().find(var)
+    pub fn root_const_var(&self, var: ty::ConstVid) -> ty::ConstVid {
+        self.inner.borrow_mut().const_unification_table().find(var).vid
     }
 
-    pub fn root_effect_var(&self, var: ty::EffectVid<'tcx>) -> ty::EffectVid<'tcx> {
-        self.inner.borrow_mut().effect_unification_table().find(var)
+    pub fn root_effect_var(&self, var: ty::EffectVid) -> ty::EffectVid {
+        self.inner.borrow_mut().effect_unification_table().find(var).vid
     }
 
     /// Resolves an int var to a rigid int type, if it was constrained to one,
@@ -1400,17 +1412,14 @@ impl<'tcx> InferCtxt<'tcx> {
         value.visit_with(&mut resolve::UnresolvedTypeOrConstFinder::new(self)).break_value()
     }
 
-    pub fn probe_const_var(
-        &self,
-        vid: ty::ConstVid<'tcx>,
-    ) -> Result<ty::Const<'tcx>, ty::UniverseIndex> {
+    pub fn probe_const_var(&self, vid: ty::ConstVid) -> Result<ty::Const<'tcx>, ty::UniverseIndex> {
         match self.inner.borrow_mut().const_unification_table().probe_value(vid).val {
             ConstVariableValue::Known { value } => Ok(value),
             ConstVariableValue::Unknown { universe } => Err(universe),
         }
     }
 
-    pub fn probe_effect_var(&self, vid: EffectVid<'tcx>) -> Option<EffectVarValue<'tcx>> {
+    pub fn probe_effect_var(&self, vid: EffectVid) -> Option<EffectVarValue<'tcx>> {
         self.inner.borrow_mut().effect_unification_table().probe_value(vid)
     }
 
@@ -1421,7 +1430,7 @@ impl<'tcx> InferCtxt<'tcx> {
     ///
     /// This method is idempotent, but it not typically not invoked
     /// except during the writeback phase.
-    pub fn fully_resolve<T: TypeFoldable<TyCtxt<'tcx>>>(&self, value: T) -> FixupResult<'tcx, T> {
+    pub fn fully_resolve<T: TypeFoldable<TyCtxt<'tcx>>>(&self, value: T) -> FixupResult<T> {
         match resolve::fully_resolve(self, value) {
             Ok(value) => {
                 if value.has_non_region_infer() {
@@ -1645,11 +1654,11 @@ impl<'tcx> InferCtxt<'tcx> {
     #[inline]
     pub fn is_ty_infer_var_definitely_unchanged<'a>(
         &'a self,
-    ) -> (impl Fn(TyOrConstInferVar<'tcx>) -> bool + 'a) {
+    ) -> (impl Fn(TyOrConstInferVar) -> bool + Captures<'tcx> + 'a) {
         // This hoists the borrow/release out of the loop body.
         let inner = self.inner.try_borrow();
 
-        return move |infer_var: TyOrConstInferVar<'tcx>| match (infer_var, &inner) {
+        return move |infer_var: TyOrConstInferVar| match (infer_var, &inner) {
             (TyOrConstInferVar::Ty(ty_var), Ok(inner)) => {
                 use self::type_variable::TypeVariableValue;
 
@@ -1672,7 +1681,7 @@ impl<'tcx> InferCtxt<'tcx> {
     /// inference variables), and it handles both `Ty` and `ty::Const` without
     /// having to resort to storing full `GenericArg`s in `stalled_on`.
     #[inline(always)]
-    pub fn ty_or_const_infer_var_changed(&self, infer_var: TyOrConstInferVar<'tcx>) -> bool {
+    pub fn ty_or_const_infer_var_changed(&self, infer_var: TyOrConstInferVar) -> bool {
         match infer_var {
             TyOrConstInferVar::Ty(v) => {
                 use self::type_variable::TypeVariableValue;
@@ -1779,7 +1788,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
 /// Helper for [InferCtxt::ty_or_const_infer_var_changed] (see comment on that), currently
 /// used only for `traits::fulfill`'s list of `stalled_on` inference variables.
 #[derive(Copy, Clone, Debug)]
-pub enum TyOrConstInferVar<'tcx> {
+pub enum TyOrConstInferVar {
     /// Equivalent to `ty::Infer(ty::TyVar(_))`.
     Ty(TyVid),
     /// Equivalent to `ty::Infer(ty::IntVar(_))`.
@@ -1788,12 +1797,12 @@ pub enum TyOrConstInferVar<'tcx> {
     TyFloat(FloatVid),
 
     /// Equivalent to `ty::ConstKind::Infer(ty::InferConst::Var(_))`.
-    Const(ConstVid<'tcx>),
+    Const(ConstVid),
     /// Equivalent to `ty::ConstKind::Infer(ty::InferConst::EffectVar(_))`.
-    Effect(EffectVid<'tcx>),
+    Effect(EffectVid),
 }
 
-impl<'tcx> TyOrConstInferVar<'tcx> {
+impl<'tcx> TyOrConstInferVar {
     /// Tries to extract an inference variable from a type or a constant, returns `None`
     /// for types other than `ty::Infer(_)` (or `InferTy::Fresh*`) and
     /// for constants other than `ty::ConstKind::Infer(_)` (or `InferConst::Fresh`).
diff --git a/compiler/rustc_infer/src/infer/resolve.rs b/compiler/rustc_infer/src/infer/resolve.rs
index 3c41e8b3783..18a9cb6b44b 100644
--- a/compiler/rustc_infer/src/infer/resolve.rs
+++ b/compiler/rustc_infer/src/infer/resolve.rs
@@ -192,7 +192,7 @@ impl<'a, 'tcx> TypeVisitor<TyCtxt<'tcx>> for UnresolvedTypeOrConstFinder<'a, 'tc
 /// Full type resolution replaces all type and region variables with
 /// their concrete results. If any variable cannot be replaced (never unified, etc)
 /// then an `Err` result is returned.
-pub fn fully_resolve<'tcx, T>(infcx: &InferCtxt<'tcx>, value: T) -> FixupResult<'tcx, T>
+pub fn fully_resolve<'tcx, T>(infcx: &InferCtxt<'tcx>, value: T) -> FixupResult<T>
 where
     T: TypeFoldable<TyCtxt<'tcx>>,
 {
@@ -206,7 +206,7 @@ struct FullTypeResolver<'a, 'tcx> {
 }
 
 impl<'a, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for FullTypeResolver<'a, 'tcx> {
-    type Error = FixupError<'tcx>;
+    type Error = FixupError;
 
     fn interner(&self) -> TyCtxt<'tcx> {
         self.infcx.tcx
diff --git a/compiler/rustc_infer/src/infer/undo_log.rs b/compiler/rustc_infer/src/infer/undo_log.rs
index 79144b3e643..5655730518e 100644
--- a/compiler/rustc_infer/src/infer/undo_log.rs
+++ b/compiler/rustc_infer/src/infer/undo_log.rs
@@ -3,7 +3,7 @@ use std::marker::PhantomData;
 use rustc_data_structures::snapshot_vec as sv;
 use rustc_data_structures::undo_log::{Rollback, UndoLogs};
 use rustc_data_structures::unify as ut;
-use rustc_middle::infer::unify_key::RegionVidKey;
+use rustc_middle::infer::unify_key::{ConstVidKey, EffectVidKey, RegionVidKey};
 use rustc_middle::ty::{self, OpaqueHiddenType, OpaqueTypeKey};
 
 use crate::{
@@ -21,10 +21,10 @@ pub struct Snapshot<'tcx> {
 pub(crate) enum UndoLog<'tcx> {
     OpaqueTypes(OpaqueTypeKey<'tcx>, Option<OpaqueHiddenType<'tcx>>),
     TypeVariables(type_variable::UndoLog<'tcx>),
-    ConstUnificationTable(sv::UndoLog<ut::Delegate<ty::ConstVid<'tcx>>>),
+    ConstUnificationTable(sv::UndoLog<ut::Delegate<ConstVidKey<'tcx>>>),
     IntUnificationTable(sv::UndoLog<ut::Delegate<ty::IntVid>>),
     FloatUnificationTable(sv::UndoLog<ut::Delegate<ty::FloatVid>>),
-    EffectUnificationTable(sv::UndoLog<ut::Delegate<ty::EffectVid<'tcx>>>),
+    EffectUnificationTable(sv::UndoLog<ut::Delegate<EffectVidKey<'tcx>>>),
     RegionConstraintCollector(region_constraints::UndoLog<'tcx>),
     RegionUnificationTable(sv::UndoLog<ut::Delegate<RegionVidKey<'tcx>>>),
     ProjectionCache(traits::UndoLog<'tcx>),
@@ -56,9 +56,9 @@ impl_from! {
     IntUnificationTable(sv::UndoLog<ut::Delegate<ty::IntVid>>),
 
     FloatUnificationTable(sv::UndoLog<ut::Delegate<ty::FloatVid>>),
-    EffectUnificationTable(sv::UndoLog<ut::Delegate<ty::EffectVid<'tcx>>>),
+    EffectUnificationTable(sv::UndoLog<ut::Delegate<EffectVidKey<'tcx>>>),
 
-    ConstUnificationTable(sv::UndoLog<ut::Delegate<ty::ConstVid<'tcx>>>),
+    ConstUnificationTable(sv::UndoLog<ut::Delegate<ConstVidKey<'tcx>>>),
 
     RegionUnificationTable(sv::UndoLog<ut::Delegate<RegionVidKey<'tcx>>>),
     ProjectionCache(traits::UndoLog<'tcx>),
diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs
index 7a7e9024bd8..998e2686005 100644
--- a/compiler/rustc_interface/src/passes.rs
+++ b/compiler/rustc_interface/src/passes.rs
@@ -775,12 +775,16 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) -> Result<()> {
     rustc_hir_analysis::check_crate(tcx)?;
 
     sess.time("MIR_borrow_checking", || {
-        tcx.hir().par_body_owners(|def_id| tcx.ensure().mir_borrowck(def_id));
+        tcx.hir().par_body_owners(|def_id| {
+            // Run THIR unsafety check because it's responsible for stealing
+            // and deallocating THIR when enabled.
+            tcx.ensure().thir_check_unsafety(def_id);
+            tcx.ensure().mir_borrowck(def_id)
+        });
     });
 
     sess.time("MIR_effect_checking", || {
         for def_id in tcx.hir().body_owners() {
-            tcx.ensure().thir_check_unsafety(def_id);
             if !tcx.sess.opts.unstable_opts.thir_unsafeck {
                 rustc_mir_transform::check_unsafety::check_unsafety(tcx, def_id);
             }
diff --git a/compiler/rustc_middle/src/infer/unify_key.rs b/compiler/rustc_middle/src/infer/unify_key.rs
index 7ca9647590a..041a63776d1 100644
--- a/compiler/rustc_middle/src/infer/unify_key.rs
+++ b/compiler/rustc_middle/src/infer/unify_key.rs
@@ -141,18 +141,30 @@ pub struct ConstVarValue<'tcx> {
     pub val: ConstVariableValue<'tcx>,
 }
 
-impl<'tcx> UnifyKey for ty::ConstVid<'tcx> {
+#[derive(PartialEq, Copy, Clone, Debug)]
+pub struct ConstVidKey<'tcx> {
+    pub vid: ty::ConstVid,
+    pub phantom: PhantomData<ty::Const<'tcx>>,
+}
+
+impl<'tcx> From<ty::ConstVid> for ConstVidKey<'tcx> {
+    fn from(vid: ty::ConstVid) -> Self {
+        ConstVidKey { vid, phantom: PhantomData }
+    }
+}
+
+impl<'tcx> UnifyKey for ConstVidKey<'tcx> {
     type Value = ConstVarValue<'tcx>;
     #[inline]
     fn index(&self) -> u32 {
-        self.index
+        self.vid.as_u32()
     }
     #[inline]
     fn from_index(i: u32) -> Self {
-        ty::ConstVid { index: i, phantom: PhantomData }
+        ConstVidKey::from(ty::ConstVid::from_u32(i))
     }
     fn tag() -> &'static str {
-        "ConstVid"
+        "ConstVidKey"
     }
 }
 
@@ -224,17 +236,29 @@ impl<'tcx> UnifyValue for EffectVarValue<'tcx> {
     }
 }
 
-impl<'tcx> UnifyKey for ty::EffectVid<'tcx> {
+#[derive(PartialEq, Copy, Clone, Debug)]
+pub struct EffectVidKey<'tcx> {
+    pub vid: ty::EffectVid,
+    pub phantom: PhantomData<EffectVarValue<'tcx>>,
+}
+
+impl<'tcx> From<ty::EffectVid> for EffectVidKey<'tcx> {
+    fn from(vid: ty::EffectVid) -> Self {
+        EffectVidKey { vid, phantom: PhantomData }
+    }
+}
+
+impl<'tcx> UnifyKey for EffectVidKey<'tcx> {
     type Value = Option<EffectVarValue<'tcx>>;
     #[inline]
     fn index(&self) -> u32 {
-        self.index
+        self.vid.as_u32()
     }
     #[inline]
     fn from_index(i: u32) -> Self {
-        ty::EffectVid { index: i, phantom: PhantomData }
+        EffectVidKey::from(ty::EffectVid::from_u32(i))
     }
     fn tag() -> &'static str {
-        "EffectVid"
+        "EffectVidKey"
     }
 }
diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs
index 20e3349073d..f1747356139 100644
--- a/compiler/rustc_middle/src/thir.rs
+++ b/compiler/rustc_middle/src/thir.rs
@@ -636,7 +636,8 @@ impl<'tcx> Pat<'tcx> {
             Wild | Range(..) | Binding { subpattern: None, .. } | Constant { .. } | Error(_) => {}
             AscribeUserType { subpattern, .. }
             | Binding { subpattern: Some(subpattern), .. }
-            | Deref { subpattern } => subpattern.walk_(it),
+            | Deref { subpattern }
+            | InlineConstant { subpattern, .. } => subpattern.walk_(it),
             Leaf { subpatterns } | Variant { subpatterns, .. } => {
                 subpatterns.iter().for_each(|field| field.pattern.walk_(it))
             }
@@ -764,6 +765,22 @@ pub enum PatKind<'tcx> {
         value: mir::Const<'tcx>,
     },
 
+    /// Inline constant found while lowering a pattern.
+    InlineConstant {
+        /// [LocalDefId] of the constant, we need this so that we have a
+        /// reference that can be used by unsafety checking to visit nested
+        /// unevaluated constants.
+        def: LocalDefId,
+        /// If the inline constant is used in a range pattern, this subpattern
+        /// represents the range (if both ends are inline constants, there will
+        /// be multiple InlineConstant wrappers).
+        ///
+        /// Otherwise, the actual pattern that the constant lowered to. As with
+        /// other constants, inline constants are matched structurally where
+        /// possible.
+        subpattern: Box<Pat<'tcx>>,
+    },
+
     Range(Box<PatRange<'tcx>>),
 
     /// Matches against a slice, checking the length and extracting elements.
@@ -924,6 +941,9 @@ impl<'tcx> fmt::Display for Pat<'tcx> {
                 write!(f, "{subpattern}")
             }
             PatKind::Constant { value } => write!(f, "{value}"),
+            PatKind::InlineConstant { def: _, ref subpattern } => {
+                write!(f, "{} (from inline const)", subpattern)
+            }
             PatKind::Range(box PatRange { lo, hi, end }) => {
                 write!(f, "{lo}")?;
                 write!(f, "{end}")?;
diff --git a/compiler/rustc_middle/src/thir/visit.rs b/compiler/rustc_middle/src/thir/visit.rs
index afb58438519..d03d92c3a4b 100644
--- a/compiler/rustc_middle/src/thir/visit.rs
+++ b/compiler/rustc_middle/src/thir/visit.rs
@@ -233,16 +233,17 @@ pub fn walk_pat<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, pat: &Pat<'
             }
         }
         Constant { value: _ } => {}
+        InlineConstant { def: _, subpattern } => visitor.visit_pat(subpattern),
         Range(_) => {}
         Slice { prefix, slice, suffix } | Array { prefix, slice, suffix } => {
             for subpattern in prefix.iter() {
-                visitor.visit_pat(&subpattern);
+                visitor.visit_pat(subpattern);
             }
             if let Some(pat) = slice {
-                visitor.visit_pat(&pat);
+                visitor.visit_pat(pat);
             }
             for subpattern in suffix.iter() {
-                visitor.visit_pat(&subpattern);
+                visitor.visit_pat(subpattern);
             }
         }
         Or { pats } => {
diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs
index 2518f0cf2e9..cfacccd2679 100644
--- a/compiler/rustc_middle/src/ty/consts.rs
+++ b/compiler/rustc_middle/src/ty/consts.rs
@@ -57,7 +57,7 @@ impl<'tcx> Const<'tcx> {
     }
 
     #[inline]
-    pub fn new_var(tcx: TyCtxt<'tcx>, infer: ty::ConstVid<'tcx>, ty: Ty<'tcx>) -> Const<'tcx> {
+    pub fn new_var(tcx: TyCtxt<'tcx>, infer: ty::ConstVid, ty: Ty<'tcx>) -> Const<'tcx> {
         Const::new(tcx, ty::ConstKind::Infer(ty::InferConst::Var(infer)), ty)
     }
 
@@ -67,7 +67,7 @@ impl<'tcx> Const<'tcx> {
     }
 
     #[inline]
-    pub fn new_infer(tcx: TyCtxt<'tcx>, infer: ty::InferConst<'tcx>, ty: Ty<'tcx>) -> Const<'tcx> {
+    pub fn new_infer(tcx: TyCtxt<'tcx>, infer: ty::InferConst, ty: Ty<'tcx>) -> Const<'tcx> {
         Const::new(tcx, ty::ConstKind::Infer(infer), ty)
     }
 
diff --git a/compiler/rustc_middle/src/ty/consts/kind.rs b/compiler/rustc_middle/src/ty/consts/kind.rs
index 749b54ca0be..4af841fcf9a 100644
--- a/compiler/rustc_middle/src/ty/consts/kind.rs
+++ b/compiler/rustc_middle/src/ty/consts/kind.rs
@@ -80,19 +80,19 @@ static_assert_size!(super::ConstKind<'_>, 32);
 
 /// An inference variable for a const, for use in const generics.
 #[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, TyEncodable, TyDecodable, Hash)]
-pub enum InferConst<'tcx> {
+pub enum InferConst {
     /// Infer the value of the const.
-    Var(ty::ConstVid<'tcx>),
+    Var(ty::ConstVid),
     /// Infer the value of the effect.
     ///
     /// For why this is separate from the `Var` variant above, see the
     /// documentation on `EffectVid`.
-    EffectVar(ty::EffectVid<'tcx>),
+    EffectVar(ty::EffectVid),
     /// A fresh const variable. See `infer::freshen` for more details.
     Fresh(u32),
 }
 
-impl<CTX> HashStable<CTX> for InferConst<'_> {
+impl<CTX> HashStable<CTX> for InferConst {
     fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) {
         match self {
             InferConst::Var(_) | InferConst::EffectVar(_) => {
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index 561699d3170..3c8bac2a9d3 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -100,7 +100,7 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
     type PolyFnSig = PolyFnSig<'tcx>;
     type AllocId = crate::mir::interpret::AllocId;
     type Const = ty::Const<'tcx>;
-    type InferConst = ty::InferConst<'tcx>;
+    type InferConst = ty::InferConst;
     type AliasConst = ty::UnevaluatedConst<'tcx>;
     type PlaceholderConst = ty::PlaceholderConst<'tcx>;
     type ParamConst = ty::ParamConst;
diff --git a/compiler/rustc_middle/src/ty/list.rs b/compiler/rustc_middle/src/ty/list.rs
index 7a32cfb1085..4f9c9d85763 100644
--- a/compiler/rustc_middle/src/ty/list.rs
+++ b/compiler/rustc_middle/src/ty/list.rs
@@ -1,7 +1,7 @@
 use crate::arena::Arena;
 use rustc_data_structures::aligned::{align_of, Aligned};
 use rustc_serialize::{Encodable, Encoder};
-use rustc_type_ir::{InferCtxtLike, OptWithInfcx};
+use rustc_type_ir::{InferCtxtLike, WithInfcx};
 use std::alloc::Layout;
 use std::cmp::Ordering;
 use std::fmt;
@@ -121,8 +121,8 @@ impl<T: fmt::Debug> fmt::Debug for List<T> {
     }
 }
 impl<'tcx, T: super::DebugWithInfcx<TyCtxt<'tcx>>> super::DebugWithInfcx<TyCtxt<'tcx>> for List<T> {
-    fn fmt<InfCtx: InferCtxtLike<TyCtxt<'tcx>>>(
-        this: OptWithInfcx<'_, TyCtxt<'tcx>, InfCtx, &Self>,
+    fn fmt<Infcx: InferCtxtLike<Interner = TyCtxt<'tcx>>>(
+        this: WithInfcx<'_, Infcx, &Self>,
         f: &mut core::fmt::Formatter<'_>,
     ) -> core::fmt::Result {
         fmt::Debug::fmt(&this.map(|this| this.as_slice()), f)
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index 9b0ceb23e3e..769b374c793 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -54,7 +54,7 @@ use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use rustc_span::{ExpnId, ExpnKind, Span};
 use rustc_target::abi::{Align, FieldIdx, Integer, IntegerType, VariantIdx};
 pub use rustc_target::abi::{ReprFlags, ReprOptions};
-pub use rustc_type_ir::{DebugWithInfcx, InferCtxtLike, OptWithInfcx};
+pub use rustc_type_ir::{DebugWithInfcx, InferCtxtLike, WithInfcx};
 pub use vtable::*;
 
 use std::fmt::Debug;
@@ -1084,19 +1084,19 @@ impl ParamTerm {
 }
 
 #[derive(Copy, Clone, Eq, PartialEq, Debug)]
-pub enum TermVid<'tcx> {
+pub enum TermVid {
     Ty(ty::TyVid),
-    Const(ty::ConstVid<'tcx>),
+    Const(ty::ConstVid),
 }
 
-impl From<ty::TyVid> for TermVid<'_> {
+impl From<ty::TyVid> for TermVid {
     fn from(value: ty::TyVid) -> Self {
         TermVid::Ty(value)
     }
 }
 
-impl<'tcx> From<ty::ConstVid<'tcx>> for TermVid<'tcx> {
-    fn from(value: ty::ConstVid<'tcx>) -> Self {
+impl From<ty::ConstVid> for TermVid {
+    fn from(value: ty::ConstVid) -> Self {
         TermVid::Const(value)
     }
 }
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index 316370977a4..22648d853f4 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -1194,7 +1194,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
         None
     }
 
-    fn const_infer_name(&self, _: ty::ConstVid<'tcx>) -> Option<Symbol> {
+    fn const_infer_name(&self, _: ty::ConstVid) -> Option<Symbol> {
         None
     }
 
@@ -1742,7 +1742,7 @@ pub struct FmtPrinterData<'a, 'tcx> {
     pub region_highlight_mode: RegionHighlightMode<'tcx>,
 
     pub ty_infer_name_resolver: Option<Box<dyn Fn(ty::TyVid) -> Option<Symbol> + 'a>>,
-    pub const_infer_name_resolver: Option<Box<dyn Fn(ty::ConstVid<'tcx>) -> Option<Symbol> + 'a>>,
+    pub const_infer_name_resolver: Option<Box<dyn Fn(ty::ConstVid) -> Option<Symbol> + 'a>>,
 }
 
 impl<'a, 'tcx> Deref for FmtPrinter<'a, 'tcx> {
@@ -2082,7 +2082,7 @@ impl<'tcx> PrettyPrinter<'tcx> for FmtPrinter<'_, 'tcx> {
         self.printed_type_count = 0;
     }
 
-    fn const_infer_name(&self, id: ty::ConstVid<'tcx>) -> Option<Symbol> {
+    fn const_infer_name(&self, id: ty::ConstVid) -> Option<Symbol> {
         self.0.const_infer_name_resolver.as_ref().and_then(|func| func(id))
     }
 
diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs
index bf2e61b23b2..967f62cdbca 100644
--- a/compiler/rustc_middle/src/ty/structural_impls.rs
+++ b/compiler/rustc_middle/src/ty/structural_impls.rs
@@ -10,7 +10,7 @@ use crate::ty::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor};
 use crate::ty::{self, AliasTy, InferConst, Lift, Term, TermKind, Ty, TyCtxt};
 use rustc_hir::def::Namespace;
 use rustc_target::abi::TyAndLayout;
-use rustc_type_ir::{ConstKind, DebugWithInfcx, InferCtxtLike, OptWithInfcx};
+use rustc_type_ir::{ConstKind, DebugWithInfcx, InferCtxtLike, WithInfcx};
 
 use std::fmt::{self, Debug};
 use std::ops::ControlFlow;
@@ -87,12 +87,12 @@ impl fmt::Debug for ty::FreeRegion {
 
 impl<'tcx> fmt::Debug for ty::FnSig<'tcx> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        OptWithInfcx::new_no_ctx(self).fmt(f)
+        WithInfcx::with_no_infcx(self).fmt(f)
     }
 }
 impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for ty::FnSig<'tcx> {
-    fn fmt<InfCtx: InferCtxtLike<TyCtxt<'tcx>>>(
-        this: OptWithInfcx<'_, TyCtxt<'tcx>, InfCtx, &Self>,
+    fn fmt<Infcx: InferCtxtLike<Interner = TyCtxt<'tcx>>>(
+        this: WithInfcx<'_, Infcx, &Self>,
         f: &mut core::fmt::Formatter<'_>,
     ) -> core::fmt::Result {
         let sig = this.data;
@@ -128,18 +128,6 @@ impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for ty::FnSig<'tcx> {
     }
 }
 
-impl<'tcx> fmt::Debug for ty::ConstVid<'tcx> {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(f, "?{}c", self.index)
-    }
-}
-
-impl fmt::Debug for ty::EffectVid<'_> {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(f, "?{}e", self.index)
-    }
-}
-
 impl<'tcx> fmt::Debug for ty::TraitRef<'tcx> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         with_no_trimmed_paths!(fmt::Display::fmt(self, f))
@@ -147,8 +135,8 @@ impl<'tcx> fmt::Debug for ty::TraitRef<'tcx> {
 }
 
 impl<'tcx> ty::DebugWithInfcx<TyCtxt<'tcx>> for Ty<'tcx> {
-    fn fmt<InfCtx: InferCtxtLike<TyCtxt<'tcx>>>(
-        this: OptWithInfcx<'_, TyCtxt<'tcx>, InfCtx, &Self>,
+    fn fmt<Infcx: InferCtxtLike<Interner = TyCtxt<'tcx>>>(
+        this: WithInfcx<'_, Infcx, &Self>,
         f: &mut core::fmt::Formatter<'_>,
     ) -> core::fmt::Result {
         this.data.fmt(f)
@@ -236,12 +224,12 @@ impl<'tcx> fmt::Debug for ty::PredicateKind<'tcx> {
 
 impl<'tcx> fmt::Debug for AliasTy<'tcx> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        OptWithInfcx::new_no_ctx(self).fmt(f)
+        WithInfcx::with_no_infcx(self).fmt(f)
     }
 }
 impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for AliasTy<'tcx> {
-    fn fmt<InfCtx: InferCtxtLike<TyCtxt<'tcx>>>(
-        this: OptWithInfcx<'_, TyCtxt<'tcx>, InfCtx, &Self>,
+    fn fmt<Infcx: InferCtxtLike<Interner = TyCtxt<'tcx>>>(
+        this: WithInfcx<'_, Infcx, &Self>,
         f: &mut core::fmt::Formatter<'_>,
     ) -> core::fmt::Result {
         f.debug_struct("AliasTy")
@@ -251,7 +239,7 @@ impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for AliasTy<'tcx> {
     }
 }
 
-impl<'tcx> fmt::Debug for ty::InferConst<'tcx> {
+impl fmt::Debug for ty::InferConst {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         match self {
             InferConst::Var(var) => write!(f, "{var:?}"),
@@ -260,17 +248,17 @@ impl<'tcx> fmt::Debug for ty::InferConst<'tcx> {
         }
     }
 }
-impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for ty::InferConst<'tcx> {
-    fn fmt<InfCtx: InferCtxtLike<TyCtxt<'tcx>>>(
-        this: OptWithInfcx<'_, TyCtxt<'tcx>, InfCtx, &Self>,
+impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for ty::InferConst {
+    fn fmt<Infcx: InferCtxtLike<Interner = TyCtxt<'tcx>>>(
+        this: WithInfcx<'_, Infcx, &Self>,
         f: &mut core::fmt::Formatter<'_>,
     ) -> core::fmt::Result {
         use ty::InferConst::*;
-        match this.infcx.and_then(|infcx| infcx.universe_of_ct(*this.data)) {
+        match this.infcx.universe_of_ct(*this.data) {
             None => write!(f, "{:?}", this.data),
             Some(universe) => match *this.data {
-                Var(vid) => write!(f, "?{}_{}c", vid.index, universe.index()),
-                EffectVar(vid) => write!(f, "?{}_{}e", vid.index, universe.index()),
+                Var(vid) => write!(f, "?{}_{}c", vid.index(), universe.index()),
+                EffectVar(vid) => write!(f, "?{}_{}e", vid.index(), universe.index()),
                 Fresh(_) => {
                     unreachable!()
                 }
@@ -281,12 +269,12 @@ impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for ty::InferConst<'tcx> {
 
 impl<'tcx> fmt::Debug for ty::consts::Expr<'tcx> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        OptWithInfcx::new_no_ctx(self).fmt(f)
+        WithInfcx::with_no_infcx(self).fmt(f)
     }
 }
 impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for ty::consts::Expr<'tcx> {
-    fn fmt<InfCtx: InferCtxtLike<TyCtxt<'tcx>>>(
-        this: OptWithInfcx<'_, TyCtxt<'tcx>, InfCtx, &Self>,
+    fn fmt<Infcx: InferCtxtLike<Interner = TyCtxt<'tcx>>>(
+        this: WithInfcx<'_, Infcx, &Self>,
         f: &mut core::fmt::Formatter<'_>,
     ) -> core::fmt::Result {
         match this.data {
@@ -314,12 +302,12 @@ impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for ty::consts::Expr<'tcx> {
 
 impl<'tcx> fmt::Debug for ty::UnevaluatedConst<'tcx> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        OptWithInfcx::new_no_ctx(self).fmt(f)
+        WithInfcx::with_no_infcx(self).fmt(f)
     }
 }
 impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for ty::UnevaluatedConst<'tcx> {
-    fn fmt<InfCtx: InferCtxtLike<TyCtxt<'tcx>>>(
-        this: OptWithInfcx<'_, TyCtxt<'tcx>, InfCtx, &Self>,
+    fn fmt<Infcx: InferCtxtLike<Interner = TyCtxt<'tcx>>>(
+        this: WithInfcx<'_, Infcx, &Self>,
         f: &mut core::fmt::Formatter<'_>,
     ) -> core::fmt::Result {
         f.debug_struct("UnevaluatedConst")
@@ -331,12 +319,12 @@ impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for ty::UnevaluatedConst<'tcx> {
 
 impl<'tcx> fmt::Debug for ty::Const<'tcx> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        OptWithInfcx::new_no_ctx(self).fmt(f)
+        WithInfcx::with_no_infcx(self).fmt(f)
     }
 }
 impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for ty::Const<'tcx> {
-    fn fmt<InfCtx: InferCtxtLike<TyCtxt<'tcx>>>(
-        this: OptWithInfcx<'_, TyCtxt<'tcx>, InfCtx, &Self>,
+    fn fmt<Infcx: InferCtxtLike<Interner = TyCtxt<'tcx>>>(
+        this: WithInfcx<'_, Infcx, &Self>,
         f: &mut core::fmt::Formatter<'_>,
     ) -> core::fmt::Result {
         // If this is a value, we spend some effort to make it look nice.
@@ -392,8 +380,8 @@ impl<'tcx> fmt::Debug for GenericArg<'tcx> {
     }
 }
 impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for GenericArg<'tcx> {
-    fn fmt<InfCtx: InferCtxtLike<TyCtxt<'tcx>>>(
-        this: OptWithInfcx<'_, TyCtxt<'tcx>, InfCtx, &Self>,
+    fn fmt<Infcx: InferCtxtLike<Interner = TyCtxt<'tcx>>>(
+        this: WithInfcx<'_, Infcx, &Self>,
         f: &mut core::fmt::Formatter<'_>,
     ) -> core::fmt::Result {
         match this.data.unpack() {
@@ -410,8 +398,8 @@ impl<'tcx> fmt::Debug for Region<'tcx> {
     }
 }
 impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for Region<'tcx> {
-    fn fmt<InfCtx: InferCtxtLike<TyCtxt<'tcx>>>(
-        this: OptWithInfcx<'_, TyCtxt<'tcx>, InfCtx, &Self>,
+    fn fmt<Infcx: InferCtxtLike<Interner = TyCtxt<'tcx>>>(
+        this: WithInfcx<'_, Infcx, &Self>,
         f: &mut core::fmt::Formatter<'_>,
     ) -> core::fmt::Result {
         write!(f, "{:?}", &this.map(|data| data.kind()))
@@ -419,11 +407,11 @@ impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for Region<'tcx> {
 }
 
 impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for ty::RegionVid {
-    fn fmt<InfCtx: InferCtxtLike<TyCtxt<'tcx>>>(
-        this: OptWithInfcx<'_, TyCtxt<'tcx>, InfCtx, &Self>,
+    fn fmt<Infcx: InferCtxtLike<Interner = TyCtxt<'tcx>>>(
+        this: WithInfcx<'_, Infcx, &Self>,
         f: &mut core::fmt::Formatter<'_>,
     ) -> core::fmt::Result {
-        match this.infcx.and_then(|infcx| infcx.universe_of_lt(*this.data)) {
+        match this.infcx.universe_of_lt(*this.data) {
             Some(universe) => write!(f, "'?{}_{}", this.data.index(), universe.index()),
             None => write!(f, "{:?}", this.data),
         }
@@ -431,8 +419,8 @@ impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for ty::RegionVid {
 }
 
 impl<'tcx, T: DebugWithInfcx<TyCtxt<'tcx>>> DebugWithInfcx<TyCtxt<'tcx>> for ty::Binder<'tcx, T> {
-    fn fmt<InfCtx: InferCtxtLike<TyCtxt<'tcx>>>(
-        this: OptWithInfcx<'_, TyCtxt<'tcx>, InfCtx, &Self>,
+    fn fmt<Infcx: InferCtxtLike<Interner = TyCtxt<'tcx>>>(
+        this: WithInfcx<'_, Infcx, &Self>,
         f: &mut core::fmt::Formatter<'_>,
     ) -> core::fmt::Result {
         f.debug_tuple("Binder")
@@ -862,7 +850,7 @@ impl<'tcx> TypeSuperVisitable<TyCtxt<'tcx>> for ty::Const<'tcx> {
     }
 }
 
-impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for InferConst<'tcx> {
+impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for InferConst {
     fn try_fold_with<F: FallibleTypeFolder<TyCtxt<'tcx>>>(
         self,
         _folder: &mut F,
@@ -871,7 +859,7 @@ impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for InferConst<'tcx> {
     }
 }
 
-impl<'tcx> TypeVisitable<TyCtxt<'tcx>> for InferConst<'tcx> {
+impl<'tcx> TypeVisitable<TyCtxt<'tcx>> for InferConst {
     fn visit_with<V: TypeVisitor<TyCtxt<'tcx>>>(
         &self,
         _visitor: &mut V,
diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs
index 46aa5d950cb..53260a3996c 100644
--- a/compiler/rustc_middle/src/ty/sty.rs
+++ b/compiler/rustc_middle/src/ty/sty.rs
@@ -29,7 +29,6 @@ use std::assert_matches::debug_assert_matches;
 use std::borrow::Cow;
 use std::cmp::Ordering;
 use std::fmt;
-use std::marker::PhantomData;
 use std::ops::{ControlFlow, Deref, Range};
 use ty::util::IntTypeExt;
 
@@ -683,8 +682,8 @@ pub enum ExistentialPredicate<'tcx> {
 }
 
 impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for ExistentialPredicate<'tcx> {
-    fn fmt<InfCtx: rustc_type_ir::InferCtxtLike<TyCtxt<'tcx>>>(
-        this: rustc_type_ir::OptWithInfcx<'_, TyCtxt<'tcx>, InfCtx, &Self>,
+    fn fmt<Infcx: rustc_type_ir::InferCtxtLike<Interner = TyCtxt<'tcx>>>(
+        this: rustc_type_ir::WithInfcx<'_, Infcx, &Self>,
         f: &mut core::fmt::Formatter<'_>,
     ) -> core::fmt::Result {
         fmt::Debug::fmt(&this.data, f)
@@ -1583,26 +1582,22 @@ impl fmt::Debug for EarlyBoundRegion {
     }
 }
 
-/// A **`const`** **v**ariable **ID**.
-#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
-#[derive(HashStable, TyEncodable, TyDecodable)]
-pub struct ConstVid<'tcx> {
-    pub index: u32,
-    pub phantom: PhantomData<&'tcx ()>,
+rustc_index::newtype_index! {
+    /// A **`const`** **v**ariable **ID**.
+    #[debug_format = "?{}c"]
+    pub struct ConstVid {}
 }
 
-/// An **effect** **v**ariable **ID**.
-///
-/// Handling effect infer variables happens separately from const infer variables
-/// because we do not want to reuse any of the const infer machinery. If we try to
-/// relate an effect variable with a normal one, we would ICE, which can catch bugs
-/// where we are not correctly using the effect var for an effect param. Fallback
-/// is also implemented on top of having separate effect and normal const variables.
-#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
-#[derive(TyEncodable, TyDecodable)]
-pub struct EffectVid<'tcx> {
-    pub index: u32,
-    pub phantom: PhantomData<&'tcx ()>,
+rustc_index::newtype_index! {
+    /// An **effect** **v**ariable **ID**.
+    ///
+    /// Handling effect infer variables happens separately from const infer variables
+    /// because we do not want to reuse any of the const infer machinery. If we try to
+    /// relate an effect variable with a normal one, we would ICE, which can catch bugs
+    /// where we are not correctly using the effect var for an effect param. Fallback
+    /// is also implemented on top of having separate effect and normal const variables.
+    #[debug_format = "?{}e"]
+    pub struct EffectVid {}
 }
 
 rustc_index::newtype_index! {
diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs
index 24c6e0eae36..1cf8c202ea4 100644
--- a/compiler/rustc_mir_build/src/build/matches/mod.rs
+++ b/compiler/rustc_mir_build/src/build/matches/mod.rs
@@ -847,6 +847,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 self.visit_primary_bindings(subpattern, subpattern_user_ty, f)
             }
 
+            PatKind::InlineConstant { ref subpattern, .. } => {
+                self.visit_primary_bindings(subpattern, pattern_user_ty.clone(), f)
+            }
+
             PatKind::Leaf { ref subpatterns } => {
                 for subpattern in subpatterns {
                     let subpattern_user_ty = pattern_user_ty.clone().leaf(subpattern.field);
diff --git a/compiler/rustc_mir_build/src/build/matches/simplify.rs b/compiler/rustc_mir_build/src/build/matches/simplify.rs
index f340feb40d4..32573b4d53a 100644
--- a/compiler/rustc_mir_build/src/build/matches/simplify.rs
+++ b/compiler/rustc_mir_build/src/build/matches/simplify.rs
@@ -204,6 +204,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 Err(match_pair)
             }
 
+            PatKind::InlineConstant { subpattern: ref pattern, def: _ } => {
+                candidate.match_pairs.push(MatchPair::new(match_pair.place, pattern, self));
+
+                Ok(())
+            }
+
             PatKind::Range(box PatRange { lo, hi, end }) => {
                 let (range, bias) = match *lo.ty().kind() {
                     ty::Char => {
@@ -229,8 +235,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                     // correct the comparison. This is achieved by XORing with a bias (see
                     // pattern/_match.rs for another pertinent example of this pattern).
                     //
-                    // Also, for performance, it's important to only do the second `try_to_bits` if
-                    // necessary.
+                    // Also, for performance, it's important to only do the second
+                    // `try_to_bits` if necessary.
                     let lo = lo.try_to_bits(sz).unwrap() ^ bias;
                     if lo <= min {
                         let hi = hi.try_to_bits(sz).unwrap() ^ bias;
diff --git a/compiler/rustc_mir_build/src/build/matches/test.rs b/compiler/rustc_mir_build/src/build/matches/test.rs
index 30ce37a7ac1..5e7db7413df 100644
--- a/compiler/rustc_mir_build/src/build/matches/test.rs
+++ b/compiler/rustc_mir_build/src/build/matches/test.rs
@@ -73,6 +73,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             PatKind::Or { .. } => bug!("or-patterns should have already been handled"),
 
             PatKind::AscribeUserType { .. }
+            | PatKind::InlineConstant { .. }
             | PatKind::Array { .. }
             | PatKind::Wild
             | PatKind::Binding { .. }
@@ -111,6 +112,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             | PatKind::Or { .. }
             | PatKind::Binding { .. }
             | PatKind::AscribeUserType { .. }
+            | PatKind::InlineConstant { .. }
             | PatKind::Leaf { .. }
             | PatKind::Deref { .. }
             | PatKind::Error(_) => {
diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs
index 8a3b67b8f03..1f817633a2a 100644
--- a/compiler/rustc_mir_build/src/build/mod.rs
+++ b/compiler/rustc_mir_build/src/build/mod.rs
@@ -53,10 +53,7 @@ pub(crate) fn closure_saved_names_of_captured_variables<'tcx>(
 }
 
 /// Construct the MIR for a given `DefId`.
-fn mir_build(tcx: TyCtxt<'_>, def: LocalDefId) -> Body<'_> {
-    // Ensure unsafeck and abstract const building is ran before we steal the THIR.
-    tcx.ensure_with_value()
-        .thir_check_unsafety(tcx.typeck_root_def_id(def.to_def_id()).expect_local());
+fn mir_build<'tcx>(tcx: TyCtxt<'tcx>, def: LocalDefId) -> Body<'tcx> {
     tcx.ensure_with_value().thir_abstract_const(def);
     if let Err(e) = tcx.check_match(def) {
         return construct_error(tcx, def, e);
@@ -65,20 +62,27 @@ fn mir_build(tcx: TyCtxt<'_>, def: LocalDefId) -> Body<'_> {
     let body = match tcx.thir_body(def) {
         Err(error_reported) => construct_error(tcx, def, error_reported),
         Ok((thir, expr)) => {
-            // We ran all queries that depended on THIR at the beginning
-            // of `mir_build`, so now we can steal it
-            let thir = thir.steal();
+            let build_mir = |thir: &Thir<'tcx>| match thir.body_type {
+                thir::BodyTy::Fn(fn_sig) => construct_fn(tcx, def, thir, expr, fn_sig),
+                thir::BodyTy::Const(ty) => construct_const(tcx, def, thir, expr, ty),
+            };
 
-            tcx.ensure().check_match(def);
             // this must run before MIR dump, because
             // "not all control paths return a value" is reported here.
             //
             // maybe move the check to a MIR pass?
             tcx.ensure().check_liveness(def);
 
-            match thir.body_type {
-                thir::BodyTy::Fn(fn_sig) => construct_fn(tcx, def, &thir, expr, fn_sig),
-                thir::BodyTy::Const(ty) => construct_const(tcx, def, &thir, expr, ty),
+            if tcx.sess.opts.unstable_opts.thir_unsafeck {
+                // Don't steal here if THIR unsafeck is being used. Instead
+                // steal in unsafeck. This is so that pattern inline constants
+                // can be evaluated as part of building the THIR of the parent
+                // function without a cycle.
+                build_mir(&thir.borrow())
+            } else {
+                // We ran all queries that depended on THIR at the beginning
+                // of `mir_build`, so now we can steal it
+                build_mir(&thir.steal())
             }
         }
     };
diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs
index 00d2afce8c6..3265f92e514 100644
--- a/compiler/rustc_mir_build/src/check_unsafety.rs
+++ b/compiler/rustc_mir_build/src/check_unsafety.rs
@@ -124,7 +124,9 @@ impl<'tcx> UnsafetyVisitor<'_, 'tcx> {
     /// Handle closures/coroutines/inline-consts, which is unsafecked with their parent body.
     fn visit_inner_body(&mut self, def: LocalDefId) {
         if let Ok((inner_thir, expr)) = self.tcx.thir_body(def) {
-            let inner_thir = &inner_thir.borrow();
+            // Runs all other queries that depend on THIR.
+            self.tcx.ensure_with_value().mir_built(def);
+            let inner_thir = &inner_thir.steal();
             let hir_context = self.tcx.hir().local_def_id_to_hir_id(def);
             let mut inner_visitor = UnsafetyVisitor { thir: inner_thir, hir_context, ..*self };
             inner_visitor.visit_expr(&inner_thir[expr]);
@@ -224,6 +226,7 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
                 PatKind::Wild |
                 // these just wrap other patterns
                 PatKind::Or { .. } |
+                PatKind::InlineConstant { .. } |
                 PatKind::AscribeUserType { .. } |
                 PatKind::Error(_) => {}
             }
@@ -277,6 +280,9 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
                 visit::walk_pat(self, pat);
                 self.inside_adt = old_inside_adt;
             }
+            PatKind::InlineConstant { def, .. } => {
+                self.visit_inner_body(*def);
+            }
             _ => {
                 visit::walk_pat(self, pat);
             }
@@ -788,7 +794,9 @@ pub fn thir_check_unsafety(tcx: TyCtxt<'_>, def: LocalDefId) {
     }
 
     let Ok((thir, expr)) = tcx.thir_body(def) else { return };
-    let thir = &thir.borrow();
+    // Runs all other queries that depend on THIR.
+    tcx.ensure_with_value().mir_built(def);
+    let thir = &thir.steal();
     // If `thir` is empty, a type error occurred, skip this body.
     if thir.exprs.is_empty() {
         return;
diff --git a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs
index 86018340a69..2255220808e 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs
@@ -1326,7 +1326,8 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> {
         let ctor;
         let fields;
         match &pat.kind {
-            PatKind::AscribeUserType { subpattern, .. } => return mkpat(subpattern),
+            PatKind::AscribeUserType { subpattern, .. }
+            | PatKind::InlineConstant { subpattern, .. } => return mkpat(subpattern),
             PatKind::Binding { subpattern: Some(subpat), .. } => return mkpat(subpat),
             PatKind::Binding { subpattern: None, .. } | PatKind::Wild => {
                 ctor = Wildcard;
diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
index 76ed6d2b6d7..dd71ab1f8e5 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
@@ -27,6 +27,7 @@ use rustc_middle::ty::{
     self, AdtDef, CanonicalUserTypeAnnotation, GenericArg, GenericArgsRef, Region, Ty, TyCtxt,
     TypeVisitableExt, UserType,
 };
+use rustc_span::def_id::LocalDefId;
 use rustc_span::{ErrorGuaranteed, Span, Symbol};
 use rustc_target::abi::{FieldIdx, Integer};
 
@@ -88,15 +89,21 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
     fn lower_pattern_range_endpoint(
         &mut self,
         expr: Option<&'tcx hir::Expr<'tcx>>,
-    ) -> Result<(Option<mir::Const<'tcx>>, Option<Ascription<'tcx>>), ErrorGuaranteed> {
+    ) -> Result<
+        (Option<mir::Const<'tcx>>, Option<Ascription<'tcx>>, Option<LocalDefId>),
+        ErrorGuaranteed,
+    > {
         match expr {
-            None => Ok((None, None)),
+            None => Ok((None, None, None)),
             Some(expr) => {
-                let (kind, ascr) = match self.lower_lit(expr) {
-                    PatKind::AscribeUserType { ascription, subpattern: box Pat { kind, .. } } => {
-                        (kind, Some(ascription))
+                let (kind, ascr, inline_const) = match self.lower_lit(expr) {
+                    PatKind::InlineConstant { subpattern, def } => {
+                        (subpattern.kind, None, Some(def))
                     }
-                    kind => (kind, None),
+                    PatKind::AscribeUserType { ascription, subpattern: box Pat { kind, .. } } => {
+                        (kind, Some(ascription), None)
+                    }
+                    kind => (kind, None, None),
                 };
                 let value = if let PatKind::Constant { value } = kind {
                     value
@@ -106,7 +113,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
                     );
                     return Err(self.tcx.sess.delay_span_bug(expr.span, msg));
                 };
-                Ok((Some(value), ascr))
+                Ok((Some(value), ascr, inline_const))
             }
         }
     }
@@ -177,8 +184,8 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
             return Err(self.tcx.sess.delay_span_bug(span, msg));
         }
 
-        let (lo, lo_ascr) = self.lower_pattern_range_endpoint(lo_expr)?;
-        let (hi, hi_ascr) = self.lower_pattern_range_endpoint(hi_expr)?;
+        let (lo, lo_ascr, lo_inline) = self.lower_pattern_range_endpoint(lo_expr)?;
+        let (hi, hi_ascr, hi_inline) = self.lower_pattern_range_endpoint(hi_expr)?;
 
         let lo = lo.unwrap_or_else(|| {
             // Unwrap is ok because the type is known to be numeric.
@@ -237,6 +244,12 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
                 };
             }
         }
+        for inline_const in [lo_inline, hi_inline] {
+            if let Some(def) = inline_const {
+                kind =
+                    PatKind::InlineConstant { def, subpattern: Box::new(Pat { span, ty, kind }) };
+            }
+        }
         Ok(kind)
     }
 
@@ -599,11 +612,9 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
         // const eval path below.
         // FIXME: investigate the performance impact of removing this.
         let lit_input = match expr.kind {
-            hir::ExprKind::Lit(ref lit) => Some(LitToConstInput { lit: &lit.node, ty, neg: false }),
-            hir::ExprKind::Unary(hir::UnOp::Neg, ref expr) => match expr.kind {
-                hir::ExprKind::Lit(ref lit) => {
-                    Some(LitToConstInput { lit: &lit.node, ty, neg: true })
-                }
+            hir::ExprKind::Lit(lit) => Some(LitToConstInput { lit: &lit.node, ty, neg: false }),
+            hir::ExprKind::Unary(hir::UnOp::Neg, expr) => match expr.kind {
+                hir::ExprKind::Lit(lit) => Some(LitToConstInput { lit: &lit.node, ty, neg: true }),
                 _ => None,
             },
             _ => None,
@@ -633,13 +644,13 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
         if let Ok(Some(valtree)) =
             self.tcx.const_eval_resolve_for_typeck(self.param_env, ct, Some(span))
         {
-            self.const_to_pat(
+            let subpattern = self.const_to_pat(
                 Const::Ty(ty::Const::new_value(self.tcx, valtree, ty)),
                 id,
                 span,
                 None,
-            )
-            .kind
+            );
+            PatKind::InlineConstant { subpattern, def: def_id }
         } else {
             // If that fails, convert it to an opaque constant pattern.
             match tcx.const_eval_resolve(self.param_env, uneval, Some(span)) {
@@ -822,6 +833,9 @@ impl<'tcx> PatternFoldable<'tcx> for PatKind<'tcx> {
                 PatKind::Deref { subpattern: subpattern.fold_with(folder) }
             }
             PatKind::Constant { value } => PatKind::Constant { value },
+            PatKind::InlineConstant { def, subpattern: ref pattern } => {
+                PatKind::InlineConstant { def, subpattern: pattern.fold_with(folder) }
+            }
             PatKind::Range(ref range) => PatKind::Range(range.clone()),
             PatKind::Slice { ref prefix, ref slice, ref suffix } => PatKind::Slice {
                 prefix: prefix.fold_with(folder),
diff --git a/compiler/rustc_mir_build/src/thir/print.rs b/compiler/rustc_mir_build/src/thir/print.rs
index c957611b975..c3b2309b7cd 100644
--- a/compiler/rustc_mir_build/src/thir/print.rs
+++ b/compiler/rustc_mir_build/src/thir/print.rs
@@ -692,7 +692,7 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> {
             }
             PatKind::Deref { subpattern } => {
                 print_indented!(self, "Deref { ", depth_lvl + 1);
-                print_indented!(self, "subpattern: ", depth_lvl + 2);
+                print_indented!(self, "subpattern:", depth_lvl + 2);
                 self.print_pat(subpattern, depth_lvl + 2);
                 print_indented!(self, "}", depth_lvl + 1);
             }
@@ -701,6 +701,13 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> {
                 print_indented!(self, format!("value: {:?}", value), depth_lvl + 2);
                 print_indented!(self, "}", depth_lvl + 1);
             }
+            PatKind::InlineConstant { def, subpattern } => {
+                print_indented!(self, "InlineConstant {", depth_lvl + 1);
+                print_indented!(self, format!("def: {:?}", def), depth_lvl + 2);
+                print_indented!(self, "subpattern:", depth_lvl + 2);
+                self.print_pat(subpattern, depth_lvl + 2);
+                print_indented!(self, "}", depth_lvl + 1);
+            }
             PatKind::Range(pat_range) => {
                 print_indented!(self, format!("Range ( {:?} )", pat_range), depth_lvl + 1);
             }
diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
index 85a0be8a44c..2c29978173f 100644
--- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
+++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
@@ -2,13 +2,13 @@
 //!
 //! Currently, this pass only propagates scalar values.
 
-use rustc_const_eval::interpret::{ImmTy, Immediate, InterpCx, OpTy, Projectable};
+use rustc_const_eval::interpret::{ImmTy, Immediate, InterpCx, OpTy, PlaceTy, Projectable};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_hir::def::DefKind;
 use rustc_middle::mir::interpret::{AllocId, ConstAllocation, InterpResult, Scalar};
 use rustc_middle::mir::visit::{MutVisitor, PlaceContext, Visitor};
 use rustc_middle::mir::*;
-use rustc_middle::ty::layout::TyAndLayout;
+use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_mir_dataflow::value_analysis::{
     Map, PlaceIndex, State, TrackElem, ValueAnalysis, ValueAnalysisWrapper, ValueOrPlace,
@@ -16,8 +16,9 @@ use rustc_mir_dataflow::value_analysis::{
 use rustc_mir_dataflow::{lattice::FlatSet, Analysis, Results, ResultsVisitor};
 use rustc_span::def_id::DefId;
 use rustc_span::DUMMY_SP;
-use rustc_target::abi::{FieldIdx, VariantIdx};
+use rustc_target::abi::{Abi, FieldIdx, Size, VariantIdx, FIRST_VARIANT};
 
+use crate::const_prop::throw_machine_stop_str;
 use crate::MirPass;
 
 // These constants are somewhat random guesses and have not been optimized.
@@ -553,18 +554,153 @@ impl<'tcx, 'locals> Collector<'tcx, 'locals> {
 
     fn try_make_constant(
         &self,
+        ecx: &mut InterpCx<'tcx, 'tcx, DummyMachine>,
         place: Place<'tcx>,
         state: &State<FlatSet<Scalar>>,
         map: &Map,
     ) -> Option<Const<'tcx>> {
-        let FlatSet::Elem(Scalar::Int(value)) = state.get(place.as_ref(), &map) else {
-            return None;
-        };
         let ty = place.ty(self.local_decls, self.patch.tcx).ty;
-        Some(Const::Val(ConstValue::Scalar(value.into()), ty))
+        let layout = ecx.layout_of(ty).ok()?;
+
+        if layout.is_zst() {
+            return Some(Const::zero_sized(ty));
+        }
+
+        if layout.is_unsized() {
+            return None;
+        }
+
+        let place = map.find(place.as_ref())?;
+        if layout.abi.is_scalar()
+            && let Some(value) = propagatable_scalar(place, state, map)
+        {
+            return Some(Const::Val(ConstValue::Scalar(value), ty));
+        }
+
+        if matches!(layout.abi, Abi::Scalar(..) | Abi::ScalarPair(..)) {
+            let alloc_id = ecx
+                .intern_with_temp_alloc(layout, |ecx, dest| {
+                    try_write_constant(ecx, dest, place, ty, state, map)
+                })
+                .ok()?;
+            return Some(Const::Val(ConstValue::Indirect { alloc_id, offset: Size::ZERO }, ty));
+        }
+
+        None
     }
 }
 
+fn propagatable_scalar(
+    place: PlaceIndex,
+    state: &State<FlatSet<Scalar>>,
+    map: &Map,
+) -> Option<Scalar> {
+    if let FlatSet::Elem(value) = state.get_idx(place, map) && value.try_to_int().is_ok() {
+        // Do not attempt to propagate pointers, as we may fail to preserve their identity.
+        Some(value)
+    } else {
+        None
+    }
+}
+
+#[instrument(level = "trace", skip(ecx, state, map))]
+fn try_write_constant<'tcx>(
+    ecx: &mut InterpCx<'_, 'tcx, DummyMachine>,
+    dest: &PlaceTy<'tcx>,
+    place: PlaceIndex,
+    ty: Ty<'tcx>,
+    state: &State<FlatSet<Scalar>>,
+    map: &Map,
+) -> InterpResult<'tcx> {
+    let layout = ecx.layout_of(ty)?;
+
+    // Fast path for ZSTs.
+    if layout.is_zst() {
+        return Ok(());
+    }
+
+    // Fast path for scalars.
+    if layout.abi.is_scalar()
+        && let Some(value) = propagatable_scalar(place, state, map)
+    {
+        return ecx.write_immediate(Immediate::Scalar(value), dest);
+    }
+
+    match ty.kind() {
+        // ZSTs. Nothing to do.
+        ty::FnDef(..) => {}
+
+        // Those are scalars, must be handled above.
+        ty::Bool | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Char => throw_machine_stop_str!("primitive type with provenance"),
+
+        ty::Tuple(elem_tys) => {
+            for (i, elem) in elem_tys.iter().enumerate() {
+                let Some(field) = map.apply(place, TrackElem::Field(FieldIdx::from_usize(i))) else {
+                    throw_machine_stop_str!("missing field in tuple")
+                };
+                let field_dest = ecx.project_field(dest, i)?;
+                try_write_constant(ecx, &field_dest, field, elem, state, map)?;
+            }
+        }
+
+        ty::Adt(def, args) => {
+            if def.is_union() {
+                throw_machine_stop_str!("cannot propagate unions")
+            }
+
+            let (variant_idx, variant_def, variant_place, variant_dest) = if def.is_enum() {
+                let Some(discr) = map.apply(place, TrackElem::Discriminant) else {
+                    throw_machine_stop_str!("missing discriminant for enum")
+                };
+                let FlatSet::Elem(Scalar::Int(discr)) = state.get_idx(discr, map) else {
+                    throw_machine_stop_str!("discriminant with provenance")
+                };
+                let discr_bits = discr.assert_bits(discr.size());
+                let Some((variant, _)) = def.discriminants(*ecx.tcx).find(|(_, var)| discr_bits == var.val) else {
+                    throw_machine_stop_str!("illegal discriminant for enum")
+                };
+                let Some(variant_place) = map.apply(place, TrackElem::Variant(variant)) else {
+                    throw_machine_stop_str!("missing variant for enum")
+                };
+                let variant_dest = ecx.project_downcast(dest, variant)?;
+                (variant, def.variant(variant), variant_place, variant_dest)
+            } else {
+                (FIRST_VARIANT, def.non_enum_variant(), place, dest.clone())
+            };
+
+            for (i, field) in variant_def.fields.iter_enumerated() {
+                let ty = field.ty(*ecx.tcx, args);
+                let Some(field) = map.apply(variant_place, TrackElem::Field(i)) else {
+                    throw_machine_stop_str!("missing field in ADT")
+                };
+                let field_dest = ecx.project_field(&variant_dest, i.as_usize())?;
+                try_write_constant(ecx, &field_dest, field, ty, state, map)?;
+            }
+            ecx.write_discriminant(variant_idx, dest)?;
+        }
+
+        // Unsupported for now.
+        ty::Array(_, _)
+
+        // Do not attempt to support indirection in constants.
+        | ty::Ref(..) | ty::RawPtr(..) | ty::FnPtr(..) | ty::Str | ty::Slice(_)
+
+        | ty::Never
+        | ty::Foreign(..)
+        | ty::Alias(..)
+        | ty::Param(_)
+        | ty::Bound(..)
+        | ty::Placeholder(..)
+        | ty::Closure(..)
+        | ty::Coroutine(..)
+        | ty::Dynamic(..) => throw_machine_stop_str!("unsupported type"),
+
+        ty::Error(_) | ty::Infer(..) | ty::CoroutineWitness(..) => bug!(),
+    }
+
+    Ok(())
+}
+
 impl<'mir, 'tcx>
     ResultsVisitor<'mir, 'tcx, Results<'tcx, ValueAnalysisWrapper<ConstAnalysis<'_, 'tcx>>>>
     for Collector<'tcx, '_>
@@ -580,8 +716,13 @@ impl<'mir, 'tcx>
     ) {
         match &statement.kind {
             StatementKind::Assign(box (_, rvalue)) => {
-                OperandCollector { state, visitor: self, map: &results.analysis.0.map }
-                    .visit_rvalue(rvalue, location);
+                OperandCollector {
+                    state,
+                    visitor: self,
+                    ecx: &mut results.analysis.0.ecx,
+                    map: &results.analysis.0.map,
+                }
+                .visit_rvalue(rvalue, location);
             }
             _ => (),
         }
@@ -599,7 +740,12 @@ impl<'mir, 'tcx>
                 // Don't overwrite the assignment if it already uses a constant (to keep the span).
             }
             StatementKind::Assign(box (place, _)) => {
-                if let Some(value) = self.try_make_constant(place, state, &results.analysis.0.map) {
+                if let Some(value) = self.try_make_constant(
+                    &mut results.analysis.0.ecx,
+                    place,
+                    state,
+                    &results.analysis.0.map,
+                ) {
                     self.patch.assignments.insert(location, value);
                 }
             }
@@ -614,8 +760,13 @@ impl<'mir, 'tcx>
         terminator: &'mir Terminator<'tcx>,
         location: Location,
     ) {
-        OperandCollector { state, visitor: self, map: &results.analysis.0.map }
-            .visit_terminator(terminator, location);
+        OperandCollector {
+            state,
+            visitor: self,
+            ecx: &mut results.analysis.0.ecx,
+            map: &results.analysis.0.map,
+        }
+        .visit_terminator(terminator, location);
     }
 }
 
@@ -670,6 +821,7 @@ impl<'tcx> MutVisitor<'tcx> for Patch<'tcx> {
 struct OperandCollector<'tcx, 'map, 'locals, 'a> {
     state: &'a State<FlatSet<Scalar>>,
     visitor: &'a mut Collector<'tcx, 'locals>,
+    ecx: &'map mut InterpCx<'tcx, 'tcx, DummyMachine>,
     map: &'map Map,
 }
 
@@ -682,7 +834,7 @@ impl<'tcx> Visitor<'tcx> for OperandCollector<'tcx, '_, '_, '_> {
         location: Location,
     ) {
         if let PlaceElem::Index(local) = elem
-            && let Some(value) = self.visitor.try_make_constant(local.into(), self.state, self.map)
+            && let Some(value) = self.visitor.try_make_constant(self.ecx, local.into(), self.state, self.map)
         {
             self.visitor.patch.before_effect.insert((location, local.into()), value);
         }
@@ -690,7 +842,9 @@ impl<'tcx> Visitor<'tcx> for OperandCollector<'tcx, '_, '_, '_> {
 
     fn visit_operand(&mut self, operand: &Operand<'tcx>, location: Location) {
         if let Some(place) = operand.place() {
-            if let Some(value) = self.visitor.try_make_constant(place, self.state, self.map) {
+            if let Some(value) =
+                self.visitor.try_make_constant(self.ecx, place, self.state, self.map)
+            {
                 self.visitor.patch.before_effect.insert((location, place), value);
             } else if !place.projection.is_empty() {
                 // Try to propagate into `Index` projections.
@@ -713,7 +867,7 @@ impl<'mir, 'tcx: 'mir> rustc_const_eval::interpret::Machine<'mir, 'tcx> for Dumm
     }
 
     fn enforce_validity(_ecx: &InterpCx<'mir, 'tcx, Self>, _layout: TyAndLayout<'tcx>) -> bool {
-        unimplemented!()
+        false
     }
 
     fn before_access_global(
@@ -725,13 +879,13 @@ impl<'mir, 'tcx: 'mir> rustc_const_eval::interpret::Machine<'mir, 'tcx> for Dumm
         is_write: bool,
     ) -> InterpResult<'tcx> {
         if is_write {
-            crate::const_prop::throw_machine_stop_str!("can't write to global");
+            throw_machine_stop_str!("can't write to global");
         }
 
         // If the static allocation is mutable, then we can't const prop it as its content
         // might be different at runtime.
         if alloc.inner().mutability.is_mut() {
-            crate::const_prop::throw_machine_stop_str!("can't access mutable globals in ConstProp");
+            throw_machine_stop_str!("can't access mutable globals in ConstProp");
         }
 
         Ok(())
@@ -781,7 +935,7 @@ impl<'mir, 'tcx: 'mir> rustc_const_eval::interpret::Machine<'mir, 'tcx> for Dumm
         _left: &rustc_const_eval::interpret::ImmTy<'tcx, Self::Provenance>,
         _right: &rustc_const_eval::interpret::ImmTy<'tcx, Self::Provenance>,
     ) -> interpret::InterpResult<'tcx, (ImmTy<'tcx, Self::Provenance>, bool)> {
-        crate::const_prop::throw_machine_stop_str!("can't do pointer arithmetic");
+        throw_machine_stop_str!("can't do pointer arithmetic");
     }
 
     fn expose_ptr(
diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs
index 462e7e85c65..84933588f17 100644
--- a/compiler/rustc_session/src/config.rs
+++ b/compiler/rustc_session/src/config.rs
@@ -169,6 +169,9 @@ pub enum MirSpanview {
 pub enum InstrumentCoverage {
     /// Default `-C instrument-coverage` or `-C instrument-coverage=statement`
     All,
+    /// Additionally, instrument branches and output branch coverage.
+    /// `-Zunstable-options -C instrument-coverage=branch`
+    Branch,
     /// `-Zunstable-options -C instrument-coverage=except-unused-generics`
     ExceptUnusedGenerics,
     /// `-Zunstable-options -C instrument-coverage=except-unused-functions`
@@ -2747,7 +2750,10 @@ pub fn build_session_options(
         }
         (Some(InstrumentCoverage::Off | InstrumentCoverage::All), _) => {}
         (Some(_), _) if !unstable_opts.unstable_options => {
-            handler.early_error("`-C instrument-coverage=except-*` requires `-Z unstable-options`");
+            handler.early_error(
+                "`-C instrument-coverage=branch` and `-C instrument-coverage=except-*` \
+                require `-Z unstable-options`",
+            );
         }
         (None, None) => {}
         (None, ic) => {
diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs
index c090bcaf9d8..77aaf951f0d 100644
--- a/compiler/rustc_session/src/options.rs
+++ b/compiler/rustc_session/src/options.rs
@@ -389,7 +389,7 @@ mod desc {
     pub const parse_mir_spanview: &str = "`statement` (default), `terminator`, or `block`";
     pub const parse_dump_mono_stats: &str = "`markdown` (default) or `json`";
     pub const parse_instrument_coverage: &str =
-        "`all` (default), `except-unused-generics`, `except-unused-functions`, or `off`";
+        "`all` (default), `branch`, `except-unused-generics`, `except-unused-functions`, or `off`";
     pub const parse_instrument_xray: &str = "either a boolean (`yes`, `no`, `on`, `off`, etc), or a comma separated list of settings: `always` or `never` (mutually exclusive), `ignore-loops`, `instruction-threshold=N`, `skip-entry`, `skip-exit`";
     pub const parse_unpretty: &str = "`string` or `string=string`";
     pub const parse_treat_err_as_bug: &str = "either no value or a non-negative number";
@@ -931,6 +931,7 @@ mod parse {
 
         *slot = Some(match v {
             "all" => InstrumentCoverage::All,
+            "branch" => InstrumentCoverage::Branch,
             "except-unused-generics" | "except_unused_generics" => {
                 InstrumentCoverage::ExceptUnusedGenerics
             }
@@ -1356,6 +1357,7 @@ options! {
         reports (note, the compiler build config must include `profiler = true`); \
         implies `-C symbol-mangling-version=v0`. Optional values are:
         `=all` (implicit value)
+        `=branch`
         `=except-unused-generics`
         `=except-unused-functions`
         `=off` (default)"),
@@ -1597,6 +1599,7 @@ options! {
         reports (note, the compiler build config must include `profiler = true`); \
         implies `-C symbol-mangling-version=v0`. Optional values are:
         `=all` (implicit value)
+        `=branch`
         `=except-unused-generics`
         `=except-unused-functions`
         `=off` (default)"),
diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs
index 79307498165..94fe38b72ad 100644
--- a/compiler/rustc_session/src/session.rs
+++ b/compiler/rustc_session/src/session.rs
@@ -702,6 +702,10 @@ impl Session {
         self.opts.cg.instrument_coverage() != InstrumentCoverage::Off
     }
 
+    pub fn instrument_coverage_branch(&self) -> bool {
+        self.opts.cg.instrument_coverage() == InstrumentCoverage::Branch
+    }
+
     pub fn instrument_coverage_except_unused_generics(&self) -> bool {
         self.opts.cg.instrument_coverage() == InstrumentCoverage::ExceptUnusedGenerics
     }
diff --git a/compiler/rustc_smir/Cargo.toml b/compiler/rustc_smir/Cargo.toml
index 41c7d3a8594..47dd7372f3d 100644
--- a/compiler/rustc_smir/Cargo.toml
+++ b/compiler/rustc_smir/Cargo.toml
@@ -9,6 +9,7 @@ rustc_hir = { path = "../rustc_hir" }
 rustc_middle = { path = "../rustc_middle" }
 rustc_span = { path = "../rustc_span" }
 rustc_target = { path = "../rustc_target" }
+scoped-tls = "1.0"
 stable_mir = {path = "../stable_mir" }
 tracing = "0.1"
 
diff --git a/compiler/rustc_smir/src/rustc_internal/mod.rs b/compiler/rustc_smir/src/rustc_internal/mod.rs
index f7e519570fa..d3ea8cdc699 100644
--- a/compiler/rustc_smir/src/rustc_internal/mod.rs
+++ b/compiler/rustc_smir/src/rustc_internal/mod.rs
@@ -3,7 +3,7 @@
 //! For that, we define APIs that will temporarily be public to 3P that exposes rustc internal APIs
 //! until stable MIR is complete.
 
-use crate::rustc_smir::Tables;
+use crate::rustc_smir::{Stable, Tables, TablesWrapper};
 use rustc_data_structures::fx;
 use rustc_data_structures::fx::FxIndexMap;
 use rustc_middle::mir::interpret::AllocId;
@@ -11,13 +11,24 @@ use rustc_middle::ty;
 use rustc_middle::ty::TyCtxt;
 use rustc_span::def_id::{CrateNum, DefId};
 use rustc_span::Span;
+use scoped_tls::scoped_thread_local;
 use stable_mir::ty::IndexedVal;
+use std::cell::Cell;
+use std::cell::RefCell;
 use std::fmt::Debug;
 use std::hash::Hash;
 use std::ops::Index;
 
 mod internal;
 
+pub fn stable<'tcx, S: Stable<'tcx>>(item: &S) -> S::T {
+    with_tables(|tables| item.stable(tables))
+}
+
+pub fn internal<'tcx, S: RustcInternal<'tcx>>(item: &S) -> S::T {
+    with_tables(|tables| item.internal(tables))
+}
+
 impl<'tcx> Index<stable_mir::DefId> for Tables<'tcx> {
     type Output = DefId;
 
@@ -125,18 +136,41 @@ pub fn crate_num(item: &stable_mir::Crate) -> CrateNum {
     item.id.into()
 }
 
+// A thread local variable that stores a pointer to the tables mapping between TyCtxt
+// datastructures and stable MIR datastructures
+scoped_thread_local! (static TLV: Cell<*const ()>);
+
+pub(crate) fn init<'tcx>(tables: &TablesWrapper<'tcx>, f: impl FnOnce()) {
+    assert!(!TLV.is_set());
+    let ptr = tables as *const _ as *const ();
+    TLV.set(&Cell::new(ptr), || {
+        f();
+    });
+}
+
+/// Loads the current context and calls a function with it.
+/// Do not nest these, as that will ICE.
+pub(crate) fn with_tables<'tcx, R>(f: impl FnOnce(&mut Tables<'tcx>) -> R) -> R {
+    assert!(TLV.is_set());
+    TLV.with(|tlv| {
+        let ptr = tlv.get();
+        assert!(!ptr.is_null());
+        let wrapper = ptr as *const TablesWrapper<'tcx>;
+        let mut tables = unsafe { (*wrapper).0.borrow_mut() };
+        f(&mut *tables)
+    })
+}
+
 pub fn run(tcx: TyCtxt<'_>, f: impl FnOnce()) {
-    stable_mir::run(
-        Tables {
-            tcx,
-            def_ids: IndexMap::default(),
-            alloc_ids: IndexMap::default(),
-            spans: IndexMap::default(),
-            types: vec![],
-            instances: IndexMap::default(),
-        },
-        f,
-    );
+    let tables = TablesWrapper(RefCell::new(Tables {
+        tcx,
+        def_ids: IndexMap::default(),
+        alloc_ids: IndexMap::default(),
+        spans: IndexMap::default(),
+        types: vec![],
+        instances: IndexMap::default(),
+    }));
+    stable_mir::run(&tables, || init(&tables, f));
 }
 
 #[macro_export]
@@ -251,7 +285,7 @@ impl<K: PartialEq + Hash + Eq, V: Copy + Debug + PartialEq + IndexedVal> Index<V
 /// Trait used to translate a stable construct to its rustc counterpart.
 ///
 /// This is basically a mirror of [crate::rustc_smir::Stable].
-pub(crate) trait RustcInternal<'tcx> {
+pub trait RustcInternal<'tcx> {
     type T;
     fn internal(&self, tables: &mut Tables<'tcx>) -> Self::T;
 }
diff --git a/compiler/rustc_smir/src/rustc_smir/mod.rs b/compiler/rustc_smir/src/rustc_smir/mod.rs
index d5379797f1c..d5a5f800a40 100644
--- a/compiler/rustc_smir/src/rustc_smir/mod.rs
+++ b/compiler/rustc_smir/src/rustc_smir/mod.rs
@@ -23,27 +23,31 @@ use stable_mir::ty::{
     FloatTy, GenericParamDef, IntTy, LineInfo, Movability, RigidTy, Span, TyKind, UintTy,
 };
 use stable_mir::{self, opaque, Context, Filename};
+use std::cell::RefCell;
 use tracing::debug;
 
 mod alloc;
 mod builder;
 
-impl<'tcx> Context for Tables<'tcx> {
+impl<'tcx> Context for TablesWrapper<'tcx> {
     fn local_crate(&self) -> stable_mir::Crate {
-        smir_crate(self.tcx, LOCAL_CRATE)
+        let tables = self.0.borrow();
+        smir_crate(tables.tcx, LOCAL_CRATE)
     }
 
     fn external_crates(&self) -> Vec<stable_mir::Crate> {
-        self.tcx.crates(()).iter().map(|crate_num| smir_crate(self.tcx, *crate_num)).collect()
+        let tables = self.0.borrow();
+        tables.tcx.crates(()).iter().map(|crate_num| smir_crate(tables.tcx, *crate_num)).collect()
     }
 
     fn find_crates(&self, name: &str) -> Vec<stable_mir::Crate> {
+        let tables = self.0.borrow();
         let crates: Vec<stable_mir::Crate> = [LOCAL_CRATE]
             .iter()
-            .chain(self.tcx.crates(()).iter())
+            .chain(tables.tcx.crates(()).iter())
             .map(|crate_num| {
-                let crate_name = self.tcx.crate_name(*crate_num).to_string();
-                (name == crate_name).then(|| smir_crate(self.tcx, *crate_num))
+                let crate_name = tables.tcx.crate_name(*crate_num).to_string();
+                (name == crate_name).then(|| smir_crate(tables.tcx, *crate_num))
             })
             .into_iter()
             .filter_map(|c| c)
@@ -52,163 +56,197 @@ impl<'tcx> Context for Tables<'tcx> {
     }
 
     fn name_of_def_id(&self, def_id: stable_mir::DefId) -> String {
-        self.tcx.def_path_str(self[def_id])
+        let tables = self.0.borrow();
+        tables.tcx.def_path_str(tables[def_id])
     }
 
     fn span_to_string(&self, span: stable_mir::ty::Span) -> String {
-        self.tcx.sess.source_map().span_to_diagnostic_string(self[span])
+        let tables = self.0.borrow();
+        tables.tcx.sess.source_map().span_to_diagnostic_string(tables[span])
     }
 
     fn get_filename(&self, span: &Span) -> Filename {
+        let tables = self.0.borrow();
         opaque(
-            &self
+            &tables
                 .tcx
                 .sess
                 .source_map()
-                .span_to_filename(self[*span])
+                .span_to_filename(tables[*span])
                 .display(rustc_span::FileNameDisplayPreference::Local)
                 .to_string(),
         )
     }
 
     fn get_lines(&self, span: &Span) -> LineInfo {
-        let lines = &self.tcx.sess.source_map().span_to_location_info(self[*span]);
+        let tables = self.0.borrow();
+        let lines = &tables.tcx.sess.source_map().span_to_location_info(tables[*span]);
         LineInfo { start_line: lines.1, start_col: lines.2, end_line: lines.3, end_col: lines.4 }
     }
 
-    fn def_kind(&mut self, def_id: stable_mir::DefId) -> stable_mir::DefKind {
-        self.tcx.def_kind(self[def_id]).stable(self)
+    fn def_kind(&self, def_id: stable_mir::DefId) -> stable_mir::DefKind {
+        let mut tables = self.0.borrow_mut();
+        tables.tcx.def_kind(tables[def_id]).stable(&mut *tables)
     }
 
-    fn span_of_an_item(&mut self, def_id: stable_mir::DefId) -> Span {
-        self.tcx.def_span(self[def_id]).stable(self)
+    fn span_of_an_item(&self, def_id: stable_mir::DefId) -> Span {
+        let mut tables = self.0.borrow_mut();
+        tables.tcx.def_span(tables[def_id]).stable(&mut *tables)
     }
 
-    fn all_local_items(&mut self) -> stable_mir::CrateItems {
-        self.tcx.mir_keys(()).iter().map(|item| self.crate_item(item.to_def_id())).collect()
+    fn all_local_items(&self) -> stable_mir::CrateItems {
+        let mut tables = self.0.borrow_mut();
+        tables.tcx.mir_keys(()).iter().map(|item| tables.crate_item(item.to_def_id())).collect()
     }
 
-    fn entry_fn(&mut self) -> Option<stable_mir::CrateItem> {
-        Some(self.crate_item(self.tcx.entry_fn(())?.0))
+    fn entry_fn(&self) -> Option<stable_mir::CrateItem> {
+        let mut tables = self.0.borrow_mut();
+        let tcx = tables.tcx;
+        Some(tables.crate_item(tcx.entry_fn(())?.0))
     }
 
-    fn all_trait_decls(&mut self) -> stable_mir::TraitDecls {
-        self.tcx
+    fn all_trait_decls(&self) -> stable_mir::TraitDecls {
+        let mut tables = self.0.borrow_mut();
+        tables
+            .tcx
             .traits(LOCAL_CRATE)
             .iter()
-            .map(|trait_def_id| self.trait_def(*trait_def_id))
+            .map(|trait_def_id| tables.trait_def(*trait_def_id))
             .collect()
     }
 
-    fn trait_decl(&mut self, trait_def: &stable_mir::ty::TraitDef) -> stable_mir::ty::TraitDecl {
-        let def_id = self[trait_def.0];
-        let trait_def = self.tcx.trait_def(def_id);
-        trait_def.stable(self)
+    fn trait_decl(&self, trait_def: &stable_mir::ty::TraitDef) -> stable_mir::ty::TraitDecl {
+        let mut tables = self.0.borrow_mut();
+        let def_id = tables[trait_def.0];
+        let trait_def = tables.tcx.trait_def(def_id);
+        trait_def.stable(&mut *tables)
     }
 
-    fn all_trait_impls(&mut self) -> stable_mir::ImplTraitDecls {
-        self.tcx
+    fn all_trait_impls(&self) -> stable_mir::ImplTraitDecls {
+        let mut tables = self.0.borrow_mut();
+        tables
+            .tcx
             .trait_impls_in_crate(LOCAL_CRATE)
             .iter()
-            .map(|impl_def_id| self.impl_def(*impl_def_id))
+            .map(|impl_def_id| tables.impl_def(*impl_def_id))
             .collect()
     }
 
-    fn trait_impl(&mut self, impl_def: &stable_mir::ty::ImplDef) -> stable_mir::ty::ImplTrait {
-        let def_id = self[impl_def.0];
-        let impl_trait = self.tcx.impl_trait_ref(def_id).unwrap();
-        impl_trait.stable(self)
+    fn trait_impl(&self, impl_def: &stable_mir::ty::ImplDef) -> stable_mir::ty::ImplTrait {
+        let mut tables = self.0.borrow_mut();
+        let def_id = tables[impl_def.0];
+        let impl_trait = tables.tcx.impl_trait_ref(def_id).unwrap();
+        impl_trait.stable(&mut *tables)
     }
 
-    fn mir_body(&mut self, item: stable_mir::DefId) -> stable_mir::mir::Body {
-        let def_id = self[item];
-        self.tcx.instance_mir(ty::InstanceDef::Item(def_id)).stable(self)
+    fn mir_body(&self, item: stable_mir::DefId) -> stable_mir::mir::Body {
+        let mut tables = self.0.borrow_mut();
+        let def_id = tables[item];
+        tables.tcx.instance_mir(ty::InstanceDef::Item(def_id)).stable(&mut tables)
     }
 
-    fn ty_kind(&mut self, ty: stable_mir::ty::Ty) -> TyKind {
-        self.types[ty.0].clone().stable(self)
+    fn ty_kind(&self, ty: stable_mir::ty::Ty) -> TyKind {
+        let mut tables = self.0.borrow_mut();
+        tables.types[ty.0].clone().stable(&mut *tables)
     }
 
-    fn mk_ty(&mut self, kind: TyKind) -> stable_mir::ty::Ty {
-        let n = self.types.len();
-        self.types.push(MaybeStable::Stable(kind));
+    fn mk_ty(&self, kind: TyKind) -> stable_mir::ty::Ty {
+        let mut tables = self.0.borrow_mut();
+        let n = tables.types.len();
+        tables.types.push(MaybeStable::Stable(kind));
         stable_mir::ty::Ty(n)
     }
 
-    fn generics_of(&mut self, def_id: stable_mir::DefId) -> stable_mir::ty::Generics {
-        let def_id = self[def_id];
-        let generics = self.tcx.generics_of(def_id);
-        generics.stable(self)
+    fn generics_of(&self, def_id: stable_mir::DefId) -> stable_mir::ty::Generics {
+        let mut tables = self.0.borrow_mut();
+        let def_id = tables[def_id];
+        let generics = tables.tcx.generics_of(def_id);
+        generics.stable(&mut *tables)
     }
 
-    fn predicates_of(&mut self, def_id: stable_mir::DefId) -> stable_mir::ty::GenericPredicates {
-        let def_id = self[def_id];
-        let ty::GenericPredicates { parent, predicates } = self.tcx.predicates_of(def_id);
+    fn predicates_of(&self, def_id: stable_mir::DefId) -> stable_mir::ty::GenericPredicates {
+        let mut tables = self.0.borrow_mut();
+        let def_id = tables[def_id];
+        let ty::GenericPredicates { parent, predicates } = tables.tcx.predicates_of(def_id);
         stable_mir::ty::GenericPredicates {
-            parent: parent.map(|did| self.trait_def(did)),
+            parent: parent.map(|did| tables.trait_def(did)),
             predicates: predicates
                 .iter()
                 .map(|(clause, span)| {
-                    (clause.as_predicate().kind().skip_binder().stable(self), span.stable(self))
+                    (
+                        clause.as_predicate().kind().skip_binder().stable(&mut *tables),
+                        span.stable(&mut *tables),
+                    )
                 })
                 .collect(),
         }
     }
 
     fn explicit_predicates_of(
-        &mut self,
+        &self,
         def_id: stable_mir::DefId,
     ) -> stable_mir::ty::GenericPredicates {
-        let def_id = self[def_id];
-        let ty::GenericPredicates { parent, predicates } = self.tcx.explicit_predicates_of(def_id);
+        let mut tables = self.0.borrow_mut();
+        let def_id = tables[def_id];
+        let ty::GenericPredicates { parent, predicates } =
+            tables.tcx.explicit_predicates_of(def_id);
         stable_mir::ty::GenericPredicates {
-            parent: parent.map(|did| self.trait_def(did)),
+            parent: parent.map(|did| tables.trait_def(did)),
             predicates: predicates
                 .iter()
                 .map(|(clause, span)| {
-                    (clause.as_predicate().kind().skip_binder().stable(self), span.stable(self))
+                    (
+                        clause.as_predicate().kind().skip_binder().stable(&mut *tables),
+                        span.stable(&mut *tables),
+                    )
                 })
                 .collect(),
         }
     }
 
-    fn instance_body(&mut self, def: InstanceDef) -> Body {
-        let instance = self.instances[def];
-        builder::BodyBuilder::new(self.tcx, instance).build(self)
+    fn instance_body(&self, def: InstanceDef) -> Body {
+        let mut tables = self.0.borrow_mut();
+        let instance = tables.instances[def];
+        builder::BodyBuilder::new(tables.tcx, instance).build(&mut *tables)
     }
 
-    fn instance_ty(&mut self, def: InstanceDef) -> stable_mir::ty::Ty {
-        let instance = self.instances[def];
-        let ty = instance.ty(self.tcx, ParamEnv::empty());
-        self.intern_ty(ty)
+    fn instance_ty(&self, def: InstanceDef) -> stable_mir::ty::Ty {
+        let mut tables = self.0.borrow_mut();
+        let instance = tables.instances[def];
+        let ty = instance.ty(tables.tcx, ParamEnv::empty());
+        tables.intern_ty(ty)
     }
 
-    fn instance_def_id(&mut self, def: InstanceDef) -> stable_mir::DefId {
-        let def_id = self.instances[def].def_id();
-        self.create_def_id(def_id)
+    fn instance_def_id(&self, def: InstanceDef) -> stable_mir::DefId {
+        let mut tables = self.0.borrow_mut();
+        let def_id = tables.instances[def].def_id();
+        tables.create_def_id(def_id)
     }
 
-    fn mono_instance(&mut self, item: stable_mir::CrateItem) -> stable_mir::mir::mono::Instance {
-        let def_id = self[item.0];
-        Instance::mono(self.tcx, def_id).stable(self)
+    fn mono_instance(&self, item: stable_mir::CrateItem) -> stable_mir::mir::mono::Instance {
+        let mut tables = self.0.borrow_mut();
+        let def_id = tables[item.0];
+        Instance::mono(tables.tcx, def_id).stable(&mut *tables)
     }
 
     fn requires_monomorphization(&self, def_id: stable_mir::DefId) -> bool {
-        let def_id = self[def_id];
-        let generics = self.tcx.generics_of(def_id);
-        let result = generics.requires_monomorphization(self.tcx);
+        let tables = self.0.borrow();
+        let def_id = tables[def_id];
+        let generics = tables.tcx.generics_of(def_id);
+        let result = generics.requires_monomorphization(tables.tcx);
         result
     }
 
     fn resolve_instance(
-        &mut self,
+        &self,
         def: stable_mir::ty::FnDef,
         args: &stable_mir::ty::GenericArgs,
     ) -> Option<stable_mir::mir::mono::Instance> {
-        let def_id = def.0.internal(self);
-        let args_ref = args.internal(self);
-        match Instance::resolve(self.tcx, ParamEnv::reveal_all(), def_id, args_ref) {
-            Ok(Some(instance)) => Some(instance.stable(self)),
+        let mut tables = self.0.borrow_mut();
+        let def_id = def.0.internal(&mut *tables);
+        let args_ref = args.internal(&mut *tables);
+        match Instance::resolve(tables.tcx, ParamEnv::reveal_all(), def_id, args_ref) {
+            Ok(Some(instance)) => Some(instance.stable(&mut *tables)),
             Ok(None) | Err(_) => None,
         }
     }
@@ -241,13 +279,15 @@ impl<S, R: PartialEq> PartialEq<R> for MaybeStable<S, R> {
     }
 }
 
+pub(crate) struct TablesWrapper<'tcx>(pub(crate) RefCell<Tables<'tcx>>);
+
 pub struct Tables<'tcx> {
-    pub tcx: TyCtxt<'tcx>,
-    pub def_ids: IndexMap<DefId, stable_mir::DefId>,
-    pub alloc_ids: IndexMap<AllocId, stable_mir::AllocId>,
-    pub spans: IndexMap<rustc_span::Span, Span>,
-    pub types: Vec<MaybeStable<TyKind, Ty<'tcx>>>,
-    pub instances: IndexMap<ty::Instance<'tcx>, InstanceDef>,
+    pub(crate) tcx: TyCtxt<'tcx>,
+    pub(crate) def_ids: IndexMap<DefId, stable_mir::DefId>,
+    pub(crate) alloc_ids: IndexMap<AllocId, stable_mir::AllocId>,
+    pub(crate) spans: IndexMap<rustc_span::Span, Span>,
+    pub(crate) types: Vec<MaybeStable<TyKind, Ty<'tcx>>>,
+    pub(crate) instances: IndexMap<ty::Instance<'tcx>, InstanceDef>,
 }
 
 impl<'tcx> Tables<'tcx> {
@@ -270,7 +310,7 @@ fn smir_crate(tcx: TyCtxt<'_>, crate_num: CrateNum) -> stable_mir::Crate {
 }
 
 /// Trait used to convert between an internal MIR type to a Stable MIR type.
-pub(crate) trait Stable<'tcx> {
+pub trait Stable<'tcx> {
     /// The stable representation of the type implementing Stable.
     type T;
     /// Converts an object to the equivalent Stable MIR representation.
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 5b58cf8b6d6..d3205f8eca1 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -957,6 +957,7 @@ symbols! {
         log_syntax,
         logf32,
         logf64,
+        loongarch_target_feature,
         loop_break_value,
         lt,
         macro_at_most_once_rep,
@@ -1369,6 +1370,7 @@ symbols! {
         rustc_evaluate_where_clauses,
         rustc_expected_cgu_reuse,
         rustc_has_incoherent_inherent_impls,
+        rustc_hidden_type_of_opaques,
         rustc_host,
         rustc_if_this_changed,
         rustc_inherit_overflow_checks,
diff --git a/compiler/rustc_trait_selection/src/solve/canonicalize.rs b/compiler/rustc_trait_selection/src/solve/canonicalize.rs
index 19f0c9fe826..377ae1b4e85 100644
--- a/compiler/rustc_trait_selection/src/solve/canonicalize.rs
+++ b/compiler/rustc_trait_selection/src/solve/canonicalize.rs
@@ -224,12 +224,20 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for Canonicalizer<'_, 'tcx> {
         let kind = match *r {
             ty::ReLateBound(..) => return r,
 
-            ty::ReStatic => match self.canonicalize_mode {
+            // We may encounter `ReStatic` in item signatures or the hidden type
+            // of an opaque. `ReErased` should only be encountered in the hidden
+            // type of an opaque for regions that are ignored for the purposes of
+            // captures.
+            //
+            // FIXME: We should investigate the perf implications of not uniquifying
+            // `ReErased`. We may be able to short-circuit registering region
+            // obligations if we encounter a `ReErased` on one side, for example.
+            ty::ReStatic | ty::ReErased => match self.canonicalize_mode {
                 CanonicalizeMode::Input => CanonicalVarKind::Region(ty::UniverseIndex::ROOT),
                 CanonicalizeMode::Response { .. } => return r,
             },
 
-            ty::ReErased | ty::ReFree(_) | ty::ReEarlyBound(_) => match self.canonicalize_mode {
+            ty::ReFree(_) | ty::ReEarlyBound(_) => match self.canonicalize_mode {
                 CanonicalizeMode::Input => CanonicalVarKind::Region(ty::UniverseIndex::ROOT),
                 CanonicalizeMode::Response { .. } => bug!("unexpected region in response: {r:?}"),
             },
diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs
index 55b5604b16b..fb9cf51b513 100644
--- a/compiler/rustc_trait_selection/src/traits/fulfill.rs
+++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs
@@ -1,4 +1,5 @@
 use crate::infer::{InferCtxt, TyOrConstInferVar};
+use rustc_data_structures::captures::Captures;
 use rustc_data_structures::obligation_forest::ProcessResult;
 use rustc_data_structures::obligation_forest::{Error, ForestObligation, Outcome};
 use rustc_data_structures::obligation_forest::{ObligationForest, ObligationProcessor};
@@ -68,7 +69,7 @@ pub struct PendingPredicateObligation<'tcx> {
     // should mostly optimize for reading speed, while modifying is not as relevant.
     //
     // For whatever reason using a boxed slice is slower than using a `Vec` here.
-    pub stalled_on: Vec<TyOrConstInferVar<'tcx>>,
+    pub stalled_on: Vec<TyOrConstInferVar>,
 }
 
 // `PendingPredicateObligation` is used a lot. Make sure it doesn't unintentionally get bigger.
@@ -669,7 +670,7 @@ impl<'a, 'tcx> FulfillProcessor<'a, 'tcx> {
         &mut self,
         obligation: &PredicateObligation<'tcx>,
         trait_obligation: PolyTraitObligation<'tcx>,
-        stalled_on: &mut Vec<TyOrConstInferVar<'tcx>>,
+        stalled_on: &mut Vec<TyOrConstInferVar>,
     ) -> ProcessResult<PendingPredicateObligation<'tcx>, FulfillmentErrorCode<'tcx>> {
         let infcx = self.selcx.infcx;
         if obligation.predicate.is_global() && !self.selcx.is_intercrate() {
@@ -722,7 +723,7 @@ impl<'a, 'tcx> FulfillProcessor<'a, 'tcx> {
         &mut self,
         obligation: &PredicateObligation<'tcx>,
         project_obligation: PolyProjectionObligation<'tcx>,
-        stalled_on: &mut Vec<TyOrConstInferVar<'tcx>>,
+        stalled_on: &mut Vec<TyOrConstInferVar>,
     ) -> ProcessResult<PendingPredicateObligation<'tcx>, FulfillmentErrorCode<'tcx>> {
         let tcx = self.selcx.tcx();
 
@@ -775,7 +776,7 @@ impl<'a, 'tcx> FulfillProcessor<'a, 'tcx> {
 fn args_infer_vars<'a, 'tcx>(
     selcx: &SelectionContext<'a, 'tcx>,
     args: ty::Binder<'tcx, GenericArgsRef<'tcx>>,
-) -> impl Iterator<Item = TyOrConstInferVar<'tcx>> {
+) -> impl Iterator<Item = TyOrConstInferVar> + Captures<'tcx> {
     selcx
         .infcx
         .resolve_vars_if_possible(args)
diff --git a/compiler/rustc_type_ir/src/const_kind.rs b/compiler/rustc_type_ir/src/const_kind.rs
index f84841c9f64..fbd403c82c6 100644
--- a/compiler/rustc_type_ir/src/const_kind.rs
+++ b/compiler/rustc_type_ir/src/const_kind.rs
@@ -5,8 +5,8 @@ use std::fmt;
 use std::hash;
 
 use crate::{
-    DebruijnIndex, DebugWithInfcx, HashStableContext, InferCtxtLike, Interner, OptWithInfcx,
-    TyDecoder, TyEncoder,
+    DebruijnIndex, DebugWithInfcx, HashStableContext, InferCtxtLike, Interner, TyDecoder,
+    TyEncoder, WithInfcx,
 };
 
 use self::ConstKind::*;
@@ -231,13 +231,13 @@ impl<I: Interner> Clone for ConstKind<I> {
 
 impl<I: Interner> fmt::Debug for ConstKind<I> {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-        OptWithInfcx::new_no_ctx(self).fmt(f)
+        WithInfcx::with_no_infcx(self).fmt(f)
     }
 }
 
 impl<I: Interner> DebugWithInfcx<I> for ConstKind<I> {
-    fn fmt<InfCtx: InferCtxtLike<I>>(
-        this: OptWithInfcx<'_, I, InfCtx, &Self>,
+    fn fmt<Infcx: InferCtxtLike<Interner = I>>(
+        this: WithInfcx<'_, Infcx, &Self>,
         f: &mut core::fmt::Formatter<'_>,
     ) -> core::fmt::Result {
         use ConstKind::*;
diff --git a/compiler/rustc_type_ir/src/debug.rs b/compiler/rustc_type_ir/src/debug.rs
index 7c6a7846900..4ea3eb3e84f 100644
--- a/compiler/rustc_type_ir/src/debug.rs
+++ b/compiler/rustc_type_ir/src/debug.rs
@@ -3,38 +3,48 @@ use crate::{Interner, UniverseIndex};
 use core::fmt;
 use std::marker::PhantomData;
 
-pub trait InferCtxtLike<I: Interner> {
-    fn universe_of_ty(&self, ty: I::InferTy) -> Option<UniverseIndex>;
+pub trait InferCtxtLike {
+    type Interner: Interner;
 
-    fn universe_of_lt(&self, lt: I::InferRegion) -> Option<UniverseIndex>;
+    fn universe_of_ty(&self, ty: <Self::Interner as Interner>::InferTy) -> Option<UniverseIndex>;
 
-    fn universe_of_ct(&self, ct: I::InferConst) -> Option<UniverseIndex>;
+    fn universe_of_lt(
+        &self,
+        lt: <Self::Interner as Interner>::InferRegion,
+    ) -> Option<UniverseIndex>;
+
+    fn universe_of_ct(&self, ct: <Self::Interner as Interner>::InferConst)
+    -> Option<UniverseIndex>;
 }
 
-impl<I: Interner> InferCtxtLike<I> for core::convert::Infallible {
+pub struct NoInfcx<I>(PhantomData<I>);
+
+impl<I: Interner> InferCtxtLike for NoInfcx<I> {
+    type Interner = I;
+
     fn universe_of_ty(&self, _ty: <I as Interner>::InferTy) -> Option<UniverseIndex> {
-        match *self {}
+        None
     }
 
     fn universe_of_ct(&self, _ct: <I as Interner>::InferConst) -> Option<UniverseIndex> {
-        match *self {}
+        None
     }
 
     fn universe_of_lt(&self, _lt: <I as Interner>::InferRegion) -> Option<UniverseIndex> {
-        match *self {}
+        None
     }
 }
 
 pub trait DebugWithInfcx<I: Interner>: fmt::Debug {
-    fn fmt<InfCtx: InferCtxtLike<I>>(
-        this: OptWithInfcx<'_, I, InfCtx, &Self>,
+    fn fmt<Infcx: InferCtxtLike<Interner = I>>(
+        this: WithInfcx<'_, Infcx, &Self>,
         f: &mut fmt::Formatter<'_>,
     ) -> fmt::Result;
 }
 
 impl<I: Interner, T: DebugWithInfcx<I> + ?Sized> DebugWithInfcx<I> for &'_ T {
-    fn fmt<InfCtx: InferCtxtLike<I>>(
-        this: OptWithInfcx<'_, I, InfCtx, &Self>,
+    fn fmt<Infcx: InferCtxtLike<Interner = I>>(
+        this: WithInfcx<'_, Infcx, &Self>,
         f: &mut fmt::Formatter<'_>,
     ) -> fmt::Result {
         <T as DebugWithInfcx<I>>::fmt(this.map(|&data| data), f)
@@ -42,8 +52,8 @@ impl<I: Interner, T: DebugWithInfcx<I> + ?Sized> DebugWithInfcx<I> for &'_ T {
 }
 
 impl<I: Interner, T: DebugWithInfcx<I>> DebugWithInfcx<I> for [T] {
-    fn fmt<InfCtx: InferCtxtLike<I>>(
-        this: OptWithInfcx<'_, I, InfCtx, &Self>,
+    fn fmt<Infcx: InferCtxtLike<Interner = I>>(
+        this: WithInfcx<'_, Infcx, &Self>,
         f: &mut fmt::Formatter<'_>,
     ) -> fmt::Result {
         match f.alternate() {
@@ -70,46 +80,45 @@ impl<I: Interner, T: DebugWithInfcx<I>> DebugWithInfcx<I> for [T] {
     }
 }
 
-pub struct OptWithInfcx<'a, I: Interner, InfCtx: InferCtxtLike<I>, T> {
+pub struct WithInfcx<'a, Infcx: InferCtxtLike, T> {
     pub data: T,
-    pub infcx: Option<&'a InfCtx>,
-    _interner: PhantomData<I>,
+    pub infcx: &'a Infcx,
 }
 
-impl<I: Interner, InfCtx: InferCtxtLike<I>, T: Copy> Copy for OptWithInfcx<'_, I, InfCtx, T> {}
+impl<Infcx: InferCtxtLike, T: Copy> Copy for WithInfcx<'_, Infcx, T> {}
 
-impl<I: Interner, InfCtx: InferCtxtLike<I>, T: Clone> Clone for OptWithInfcx<'_, I, InfCtx, T> {
+impl<Infcx: InferCtxtLike, T: Clone> Clone for WithInfcx<'_, Infcx, T> {
     fn clone(&self) -> Self {
-        Self { data: self.data.clone(), infcx: self.infcx, _interner: self._interner }
+        Self { data: self.data.clone(), infcx: self.infcx }
     }
 }
 
-impl<'a, I: Interner, T> OptWithInfcx<'a, I, core::convert::Infallible, T> {
-    pub fn new_no_ctx(data: T) -> Self {
-        Self { data, infcx: None, _interner: PhantomData }
+impl<'a, I: Interner, T> WithInfcx<'a, NoInfcx<I>, T> {
+    pub fn with_no_infcx(data: T) -> Self {
+        Self { data, infcx: &NoInfcx(PhantomData) }
     }
 }
 
-impl<'a, I: Interner, InfCtx: InferCtxtLike<I>, T> OptWithInfcx<'a, I, InfCtx, T> {
-    pub fn new(data: T, infcx: &'a InfCtx) -> Self {
-        Self { data, infcx: Some(infcx), _interner: PhantomData }
+impl<'a, Infcx: InferCtxtLike, T> WithInfcx<'a, Infcx, T> {
+    pub fn new(data: T, infcx: &'a Infcx) -> Self {
+        Self { data, infcx }
     }
 
-    pub fn wrap<U>(self, u: U) -> OptWithInfcx<'a, I, InfCtx, U> {
-        OptWithInfcx { data: u, infcx: self.infcx, _interner: PhantomData }
+    pub fn wrap<U>(self, u: U) -> WithInfcx<'a, Infcx, U> {
+        WithInfcx { data: u, infcx: self.infcx }
     }
 
-    pub fn map<U>(self, f: impl FnOnce(T) -> U) -> OptWithInfcx<'a, I, InfCtx, U> {
-        OptWithInfcx { data: f(self.data), infcx: self.infcx, _interner: PhantomData }
+    pub fn map<U>(self, f: impl FnOnce(T) -> U) -> WithInfcx<'a, Infcx, U> {
+        WithInfcx { data: f(self.data), infcx: self.infcx }
     }
 
-    pub fn as_ref(&self) -> OptWithInfcx<'a, I, InfCtx, &T> {
-        OptWithInfcx { data: &self.data, infcx: self.infcx, _interner: PhantomData }
+    pub fn as_ref(&self) -> WithInfcx<'a, Infcx, &T> {
+        WithInfcx { data: &self.data, infcx: self.infcx }
     }
 }
 
-impl<I: Interner, InfCtx: InferCtxtLike<I>, T: DebugWithInfcx<I>> fmt::Debug
-    for OptWithInfcx<'_, I, InfCtx, T>
+impl<Infcx: InferCtxtLike, T: DebugWithInfcx<Infcx::Interner>> fmt::Debug
+    for WithInfcx<'_, Infcx, T>
 {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         DebugWithInfcx::fmt(self.as_ref(), f)
diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs
index d4ca9da96e4..1ff220f3ed6 100644
--- a/compiler/rustc_type_ir/src/lib.rs
+++ b/compiler/rustc_type_ir/src/lib.rs
@@ -34,7 +34,7 @@ mod region_kind;
 
 pub use codec::*;
 pub use const_kind::*;
-pub use debug::{DebugWithInfcx, InferCtxtLike, OptWithInfcx};
+pub use debug::{DebugWithInfcx, InferCtxtLike, WithInfcx};
 pub use flags::*;
 pub use interner::*;
 pub use region_kind::*;
diff --git a/compiler/rustc_type_ir/src/region_kind.rs b/compiler/rustc_type_ir/src/region_kind.rs
index 0006eec4d30..23e575cbc37 100644
--- a/compiler/rustc_type_ir/src/region_kind.rs
+++ b/compiler/rustc_type_ir/src/region_kind.rs
@@ -5,8 +5,8 @@ use std::fmt;
 use std::hash;
 
 use crate::{
-    DebruijnIndex, DebugWithInfcx, HashStableContext, InferCtxtLike, Interner, OptWithInfcx,
-    TyDecoder, TyEncoder,
+    DebruijnIndex, DebugWithInfcx, HashStableContext, InferCtxtLike, Interner, TyDecoder,
+    TyEncoder, WithInfcx,
 };
 
 use self::RegionKind::*;
@@ -274,8 +274,8 @@ impl<I: Interner> hash::Hash for RegionKind<I> {
 }
 
 impl<I: Interner> DebugWithInfcx<I> for RegionKind<I> {
-    fn fmt<InfCtx: InferCtxtLike<I>>(
-        this: OptWithInfcx<'_, I, InfCtx, &Self>,
+    fn fmt<Infcx: InferCtxtLike<Interner = I>>(
+        this: WithInfcx<'_, Infcx, &Self>,
         f: &mut core::fmt::Formatter<'_>,
     ) -> core::fmt::Result {
         match this.data {
@@ -301,7 +301,7 @@ impl<I: Interner> DebugWithInfcx<I> for RegionKind<I> {
 }
 impl<I: Interner> fmt::Debug for RegionKind<I> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        OptWithInfcx::new_no_ctx(self).fmt(f)
+        WithInfcx::with_no_infcx(self).fmt(f)
     }
 }
 
diff --git a/compiler/rustc_type_ir/src/ty_kind.rs b/compiler/rustc_type_ir/src/ty_kind.rs
index 91bfce9a142..9c719d2d978 100644
--- a/compiler/rustc_type_ir/src/ty_kind.rs
+++ b/compiler/rustc_type_ir/src/ty_kind.rs
@@ -11,7 +11,7 @@ use crate::HashStableContext;
 use crate::Interner;
 use crate::TyDecoder;
 use crate::TyEncoder;
-use crate::{DebruijnIndex, DebugWithInfcx, InferCtxtLike, OptWithInfcx};
+use crate::{DebruijnIndex, DebugWithInfcx, InferCtxtLike, WithInfcx};
 
 use self::TyKind::*;
 
@@ -534,8 +534,8 @@ impl<I: Interner> hash::Hash for TyKind<I> {
 }
 
 impl<I: Interner> DebugWithInfcx<I> for TyKind<I> {
-    fn fmt<InfCtx: InferCtxtLike<I>>(
-        this: OptWithInfcx<'_, I, InfCtx, &Self>,
+    fn fmt<Infcx: InferCtxtLike<Interner = I>>(
+        this: WithInfcx<'_, Infcx, &Self>,
         f: &mut core::fmt::Formatter<'_>,
     ) -> fmt::Result {
         match this.data {
@@ -617,7 +617,7 @@ impl<I: Interner> DebugWithInfcx<I> for TyKind<I> {
 // This is manually implemented because a derive would require `I: Debug`
 impl<I: Interner> fmt::Debug for TyKind<I> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        OptWithInfcx::new_no_ctx(self).fmt(f)
+        WithInfcx::with_no_infcx(self).fmt(f)
     }
 }
 
@@ -1239,12 +1239,12 @@ impl fmt::Debug for InferTy {
 }
 
 impl<I: Interner<InferTy = InferTy>> DebugWithInfcx<I> for InferTy {
-    fn fmt<InfCtx: InferCtxtLike<I>>(
-        this: OptWithInfcx<'_, I, InfCtx, &Self>,
+    fn fmt<Infcx: InferCtxtLike<Interner = I>>(
+        this: WithInfcx<'_, Infcx, &Self>,
         f: &mut fmt::Formatter<'_>,
     ) -> fmt::Result {
         use InferTy::*;
-        match this.infcx.and_then(|infcx| infcx.universe_of_ty(*this.data)) {
+        match this.infcx.universe_of_ty(*this.data) {
             None => write!(f, "{:?}", this.data),
             Some(universe) => match *this.data {
                 TyVar(ty_vid) => write!(f, "?{}_{}t", ty_vid.index(), universe.index()),
diff --git a/compiler/stable_mir/src/lib.rs b/compiler/stable_mir/src/lib.rs
index be5ccac78c7..8cacbdbda48 100644
--- a/compiler/stable_mir/src/lib.rs
+++ b/compiler/stable_mir/src/lib.rs
@@ -175,17 +175,17 @@ pub fn trait_impl(trait_impl: &ImplDef) -> ImplTrait {
 }
 
 pub trait Context {
-    fn entry_fn(&mut self) -> Option<CrateItem>;
+    fn entry_fn(&self) -> Option<CrateItem>;
     /// Retrieve all items of the local crate that have a MIR associated with them.
-    fn all_local_items(&mut self) -> CrateItems;
-    fn mir_body(&mut self, item: DefId) -> mir::Body;
-    fn all_trait_decls(&mut self) -> TraitDecls;
-    fn trait_decl(&mut self, trait_def: &TraitDef) -> TraitDecl;
-    fn all_trait_impls(&mut self) -> ImplTraitDecls;
-    fn trait_impl(&mut self, trait_impl: &ImplDef) -> ImplTrait;
-    fn generics_of(&mut self, def_id: DefId) -> Generics;
-    fn predicates_of(&mut self, def_id: DefId) -> GenericPredicates;
-    fn explicit_predicates_of(&mut self, def_id: DefId) -> GenericPredicates;
+    fn all_local_items(&self) -> CrateItems;
+    fn mir_body(&self, item: DefId) -> mir::Body;
+    fn all_trait_decls(&self) -> TraitDecls;
+    fn trait_decl(&self, trait_def: &TraitDef) -> TraitDecl;
+    fn all_trait_impls(&self) -> ImplTraitDecls;
+    fn trait_impl(&self, trait_impl: &ImplDef) -> ImplTrait;
+    fn generics_of(&self, def_id: DefId) -> Generics;
+    fn predicates_of(&self, def_id: DefId) -> GenericPredicates;
+    fn explicit_predicates_of(&self, def_id: DefId) -> GenericPredicates;
     /// Get information about the local crate.
     fn local_crate(&self) -> Crate;
     /// Retrieve a list of all external crates.
@@ -207,61 +207,58 @@ pub trait Context {
     fn get_lines(&self, span: &Span) -> LineInfo;
 
     /// Returns the `kind` of given `DefId`
-    fn def_kind(&mut self, def_id: DefId) -> DefKind;
+    fn def_kind(&self, def_id: DefId) -> DefKind;
 
     /// `Span` of an item
-    fn span_of_an_item(&mut self, def_id: DefId) -> Span;
+    fn span_of_an_item(&self, def_id: DefId) -> Span;
 
     /// Obtain the representation of a type.
-    fn ty_kind(&mut self, ty: Ty) -> TyKind;
+    fn ty_kind(&self, ty: Ty) -> TyKind;
 
     /// Create a new `Ty` from scratch without information from rustc.
-    fn mk_ty(&mut self, kind: TyKind) -> Ty;
+    fn mk_ty(&self, kind: TyKind) -> Ty;
 
     /// Get the body of an Instance.
     /// FIXME: Monomorphize the body.
-    fn instance_body(&mut self, instance: InstanceDef) -> Body;
+    fn instance_body(&self, instance: InstanceDef) -> Body;
 
     /// Get the instance type with generic substitutions applied and lifetimes erased.
-    fn instance_ty(&mut self, instance: InstanceDef) -> Ty;
+    fn instance_ty(&self, instance: InstanceDef) -> Ty;
 
     /// Get the instance.
-    fn instance_def_id(&mut self, instance: InstanceDef) -> DefId;
+    fn instance_def_id(&self, instance: InstanceDef) -> DefId;
 
     /// Convert a non-generic crate item into an instance.
     /// This function will panic if the item is generic.
-    fn mono_instance(&mut self, item: CrateItem) -> Instance;
+    fn mono_instance(&self, item: CrateItem) -> Instance;
 
     /// Item requires monomorphization.
     fn requires_monomorphization(&self, def_id: DefId) -> bool;
 
     /// Resolve an instance from the given function definition and generic arguments.
-    fn resolve_instance(&mut self, def: FnDef, args: &GenericArgs) -> Option<Instance>;
+    fn resolve_instance(&self, def: FnDef, args: &GenericArgs) -> Option<Instance>;
 }
 
 // A thread local variable that stores a pointer to the tables mapping between TyCtxt
 // datastructures and stable MIR datastructures
-scoped_thread_local! (static TLV: Cell<*mut ()>);
+scoped_thread_local! (static TLV: Cell<*const ()>);
 
-pub fn run(mut context: impl Context, f: impl FnOnce()) {
+pub fn run(context: &dyn Context, f: impl FnOnce()) {
     assert!(!TLV.is_set());
-    fn g<'a>(mut context: &mut (dyn Context + 'a), f: impl FnOnce()) {
-        let ptr: *mut () = &mut context as *mut &mut _ as _;
-        TLV.set(&Cell::new(ptr), || {
-            f();
-        });
-    }
-    g(&mut context, f);
+    let ptr: *const () = &context as *const &_ as _;
+    TLV.set(&Cell::new(ptr), || {
+        f();
+    });
 }
 
 /// Loads the current context and calls a function with it.
 /// Do not nest these, as that will ICE.
-pub fn with<R>(f: impl FnOnce(&mut dyn Context) -> R) -> R {
+pub fn with<R>(f: impl FnOnce(&dyn Context) -> R) -> R {
     assert!(TLV.is_set());
     TLV.with(|tlv| {
         let ptr = tlv.get();
         assert!(!ptr.is_null());
-        f(unsafe { *(ptr as *mut &mut dyn Context) })
+        f(unsafe { *(ptr as *const &dyn Context) })
     })
 }
 
diff --git a/library/core/src/ffi/mod.rs b/library/core/src/ffi/mod.rs
index b2c9a0800c9..6908c824f44 100644
--- a/library/core/src/ffi/mod.rs
+++ b/library/core/src/ffi/mod.rs
@@ -6,7 +6,7 @@
 //! match those defined by C, so that code that interacts with C will
 //! refer to the correct types.
 
-#![stable(feature = "", since = "1.30.0")]
+#![stable(feature = "core_ffi", since = "1.30.0")]
 #![allow(non_camel_case_types)]
 
 use crate::fmt;
diff --git a/library/core/src/net/socket_addr.rs b/library/core/src/net/socket_addr.rs
index 8396aecf947..55116285842 100644
--- a/library/core/src/net/socket_addr.rs
+++ b/library/core/src/net/socket_addr.rs
@@ -1,6 +1,4 @@
-use crate::cmp::Ordering;
 use crate::fmt::{self, Write};
-use crate::hash;
 use crate::net::{IpAddr, Ipv4Addr, Ipv6Addr};
 
 use super::display_buffer::DisplayBuffer;
@@ -63,7 +61,7 @@ pub enum SocketAddr {
 /// assert_eq!(socket.ip(), &Ipv4Addr::new(127, 0, 0, 1));
 /// assert_eq!(socket.port(), 8080);
 /// ```
-#[derive(Copy, Clone, Eq, PartialEq)]
+#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct SocketAddrV4 {
     ip: Ipv4Addr,
@@ -96,7 +94,7 @@ pub struct SocketAddrV4 {
 /// assert_eq!(socket.ip(), &Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 1));
 /// assert_eq!(socket.port(), 8080);
 /// ```
-#[derive(Copy, Clone, Eq, PartialEq)]
+#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct SocketAddrV6 {
     ip: Ipv6Addr,
@@ -644,48 +642,3 @@ impl fmt::Debug for SocketAddrV6 {
         fmt::Display::fmt(self, fmt)
     }
 }
-
-#[stable(feature = "socketaddr_ordering", since = "1.45.0")]
-impl PartialOrd for SocketAddrV4 {
-    #[inline]
-    fn partial_cmp(&self, other: &SocketAddrV4) -> Option<Ordering> {
-        Some(self.cmp(other))
-    }
-}
-
-#[stable(feature = "socketaddr_ordering", since = "1.45.0")]
-impl PartialOrd for SocketAddrV6 {
-    #[inline]
-    fn partial_cmp(&self, other: &SocketAddrV6) -> Option<Ordering> {
-        Some(self.cmp(other))
-    }
-}
-
-#[stable(feature = "socketaddr_ordering", since = "1.45.0")]
-impl Ord for SocketAddrV4 {
-    #[inline]
-    fn cmp(&self, other: &SocketAddrV4) -> Ordering {
-        self.ip().cmp(other.ip()).then(self.port().cmp(&other.port()))
-    }
-}
-
-#[stable(feature = "socketaddr_ordering", since = "1.45.0")]
-impl Ord for SocketAddrV6 {
-    #[inline]
-    fn cmp(&self, other: &SocketAddrV6) -> Ordering {
-        self.ip().cmp(other.ip()).then(self.port().cmp(&other.port()))
-    }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl hash::Hash for SocketAddrV4 {
-    fn hash<H: hash::Hasher>(&self, s: &mut H) {
-        (self.port, self.ip).hash(s)
-    }
-}
-#[stable(feature = "rust1", since = "1.0.0")]
-impl hash::Hash for SocketAddrV6 {
-    fn hash<H: hash::Hasher>(&self, s: &mut H) {
-        (self.port, &self.ip, self.flowinfo, self.scope_id).hash(s)
-    }
-}
diff --git a/library/core/src/num/mod.rs b/library/core/src/num/mod.rs
index 8b127132c1c..a6c1adfac65 100644
--- a/library/core/src/num/mod.rs
+++ b/library/core/src/num/mod.rs
@@ -114,7 +114,7 @@ macro_rules! midpoint_impl {
                       without modifying the original"]
         #[inline]
         pub const fn midpoint(self, rhs: $SelfT) -> $SelfT {
-            // Use the well known branchless algorthim from Hacker's Delight to compute
+            // Use the well known branchless algorithm from Hacker's Delight to compute
             // `(a + b) / 2` without overflowing: `((a ^ b) >> 1) + (a & b)`.
             ((self ^ rhs) >> 1) + (self & rhs)
         }
diff --git a/library/core/tests/net/socket_addr.rs b/library/core/tests/net/socket_addr.rs
index 35a69cead48..3d013d37e04 100644
--- a/library/core/tests/net/socket_addr.rs
+++ b/library/core/tests/net/socket_addr.rs
@@ -199,6 +199,9 @@ fn compare() {
     let v6_1 = "[2001:db8:f00::1002]:23456".parse::<SocketAddrV6>().unwrap();
     let v6_2 = "[2001:db8:f00::2001]:12345".parse::<SocketAddrV6>().unwrap();
     let v6_3 = "[2001:db8:f00::2001]:23456".parse::<SocketAddrV6>().unwrap();
+    let v6_4 = "[2001:db8:f00::2001%42]:23456".parse::<SocketAddrV6>().unwrap();
+    let mut v6_5 = "[2001:db8:f00::2001]:23456".parse::<SocketAddrV6>().unwrap();
+    v6_5.set_flowinfo(17);
 
     // equality
     assert_eq!(v4_1, v4_1);
@@ -207,6 +210,8 @@ fn compare() {
     assert_eq!(SocketAddr::V6(v6_1), SocketAddr::V6(v6_1));
     assert!(v4_1 != v4_2);
     assert!(v6_1 != v6_2);
+    assert!(v6_3 != v6_4);
+    assert!(v6_3 != v6_5);
 
     // compare different addresses
     assert!(v4_1 < v4_2);
@@ -226,6 +231,12 @@ fn compare() {
     assert!(v4_3 > v4_1);
     assert!(v6_3 > v6_1);
 
+    // compare the same address with different scope_id
+    assert!(v6_3 < v6_4);
+
+    // compare the same address with different flowinfo
+    assert!(v6_3 < v6_5);
+
     // compare with an inferred right-hand side
     assert_eq!(v4_1, "224.120.45.1:23456".parse().unwrap());
     assert_eq!(v6_1, "[2001:db8:f00::1002]:23456".parse().unwrap());
diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs
index 063464046e0..bca5d859b66 100644
--- a/library/std/src/io/mod.rs
+++ b/library/std/src/io/mod.rs
@@ -1140,10 +1140,10 @@ pub fn read_to_string<R: Read>(mut reader: R) -> Result<String> {
 #[repr(transparent)]
 pub struct IoSliceMut<'a>(sys::io::IoSliceMut<'a>);
 
-#[stable(feature = "iovec-send-sync", since = "1.44.0")]
+#[stable(feature = "iovec_send_sync", since = "1.44.0")]
 unsafe impl<'a> Send for IoSliceMut<'a> {}
 
-#[stable(feature = "iovec-send-sync", since = "1.44.0")]
+#[stable(feature = "iovec_send_sync", since = "1.44.0")]
 unsafe impl<'a> Sync for IoSliceMut<'a> {}
 
 #[stable(feature = "iovec", since = "1.36.0")]
@@ -1283,10 +1283,10 @@ impl<'a> DerefMut for IoSliceMut<'a> {
 #[repr(transparent)]
 pub struct IoSlice<'a>(sys::io::IoSlice<'a>);
 
-#[stable(feature = "iovec-send-sync", since = "1.44.0")]
+#[stable(feature = "iovec_send_sync", since = "1.44.0")]
 unsafe impl<'a> Send for IoSlice<'a> {}
 
-#[stable(feature = "iovec-send-sync", since = "1.44.0")]
+#[stable(feature = "iovec_send_sync", since = "1.44.0")]
 unsafe impl<'a> Sync for IoSlice<'a> {}
 
 #[stable(feature = "iovec", since = "1.36.0")]
diff --git a/library/std/src/sys/unix/mod.rs b/library/std/src/sys/unix/mod.rs
index da05620fd16..4b28f6feba5 100644
--- a/library/std/src/sys/unix/mod.rs
+++ b/library/std/src/sys/unix/mod.rs
@@ -415,7 +415,6 @@ cfg_if::cfg_if! {
     } else if #[cfg(any(target_os = "ios", target_os = "tvos", target_os = "watchos"))] {
         #[link(name = "System")]
         #[link(name = "objc")]
-        #[link(name = "Security", kind = "framework")]
         #[link(name = "Foundation", kind = "framework")]
         extern "C" {}
     } else if #[cfg(target_os = "fuchsia")] {
diff --git a/library/std/src/sys/unix/rand.rs b/library/std/src/sys/unix/rand.rs
index bdf725fbe5a..2825d167742 100644
--- a/library/std/src/sys/unix/rand.rs
+++ b/library/std/src/sys/unix/rand.rs
@@ -151,40 +151,65 @@ mod imp {
     }
 }
 
-#[cfg(target_os = "macos")]
+#[cfg(target_vendor = "apple")]
 mod imp {
-    use crate::fs::File;
-    use crate::io::Read;
-    use crate::sys::os::errno;
-    use crate::sys::weak::weak;
+    use crate::io;
     use libc::{c_int, c_void, size_t};
 
-    fn getentropy_fill_bytes(v: &mut [u8]) -> bool {
-        weak!(fn getentropy(*mut c_void, size_t) -> c_int);
+    #[inline(always)]
+    fn random_failure() -> ! {
+        panic!("unexpected random generation error: {}", io::Error::last_os_error());
+    }
 
-        getentropy
-            .get()
-            .map(|f| {
-                // getentropy(2) permits a maximum buffer size of 256 bytes
-                for s in v.chunks_mut(256) {
-                    let ret = unsafe { f(s.as_mut_ptr() as *mut c_void, s.len()) };
-                    if ret == -1 {
-                        panic!("unexpected getentropy error: {}", errno());
-                    }
-                }
-                true
-            })
-            .unwrap_or(false)
+    #[cfg(target_os = "macos")]
+    fn getentropy_fill_bytes(v: &mut [u8]) {
+        extern "C" {
+            fn getentropy(bytes: *mut c_void, count: size_t) -> c_int;
+        }
+
+        // getentropy(2) permits a maximum buffer size of 256 bytes
+        for s in v.chunks_mut(256) {
+            let ret = unsafe { getentropy(s.as_mut_ptr().cast(), s.len()) };
+            if ret == -1 {
+                random_failure()
+            }
+        }
+    }
+
+    #[cfg(not(target_os = "macos"))]
+    fn ccrandom_fill_bytes(v: &mut [u8]) {
+        extern "C" {
+            fn CCRandomGenerateBytes(bytes: *mut c_void, count: size_t) -> c_int;
+        }
+
+        let ret = unsafe { CCRandomGenerateBytes(v.as_mut_ptr().cast(), v.len()) };
+        if ret == -1 {
+            random_failure()
+        }
     }
 
     pub fn fill_bytes(v: &mut [u8]) {
-        if getentropy_fill_bytes(v) {
-            return;
-        }
+        // All supported versions of macOS (10.12+) support getentropy.
+        //
+        // `getentropy` is measurably faster (via Divan) then the other alternatives so its preferred
+        // when usable.
+        #[cfg(target_os = "macos")]
+        getentropy_fill_bytes(v);
 
-        // for older macos which doesn't support getentropy
-        let mut file = File::open("/dev/urandom").expect("failed to open /dev/urandom");
-        file.read_exact(v).expect("failed to read /dev/urandom")
+        // On Apple platforms, `CCRandomGenerateBytes` and `SecRandomCopyBytes` simply
+        // call into `CCRandomCopyBytes` with `kCCRandomDefault`. `CCRandomCopyBytes`
+        // manages a CSPRNG which is seeded from the kernel's CSPRNG and which runs on
+        // its own thread accessed via GCD. This seems needlessly heavyweight for our purposes
+        // so we only use it on non-Mac OSes where the better entrypoints are blocked.
+        //
+        // `CCRandomGenerateBytes` is used instead of `SecRandomCopyBytes` because the former is accessible
+        // via `libSystem` (libc) while the other needs to link to `Security.framework`.
+        //
+        // Note that while `getentropy` has a available attribute in the macOS headers, the lack
+        // of a header in the iOS (and others) SDK means that its can cause app store rejections.
+        // Just use `CCRandomGenerateBytes` instead.
+        #[cfg(not(target_os = "macos"))]
+        ccrandom_fill_bytes(v);
     }
 }
 
@@ -203,36 +228,6 @@ mod imp {
     }
 }
 
-// On iOS and MacOS `SecRandomCopyBytes` calls `CCRandomCopyBytes` with
-// `kCCRandomDefault`. `CCRandomCopyBytes` manages a CSPRNG which is seeded
-// from `/dev/random` and which runs on its own thread accessed via GCD.
-// This seems needlessly heavyweight for the purposes of generating two u64s
-// once per thread in `hashmap_random_keys`. Therefore `SecRandomCopyBytes` is
-// only used on iOS where direct access to `/dev/urandom` is blocked by the
-// sandbox.
-#[cfg(any(target_os = "ios", target_os = "tvos", target_os = "watchos"))]
-mod imp {
-    use crate::io;
-    use crate::ptr;
-    use libc::{c_int, size_t};
-
-    enum SecRandom {}
-
-    #[allow(non_upper_case_globals)]
-    const kSecRandomDefault: *const SecRandom = ptr::null();
-
-    extern "C" {
-        fn SecRandomCopyBytes(rnd: *const SecRandom, count: size_t, bytes: *mut u8) -> c_int;
-    }
-
-    pub fn fill_bytes(v: &mut [u8]) {
-        let ret = unsafe { SecRandomCopyBytes(kSecRandomDefault, v.len(), v.as_mut_ptr()) };
-        if ret == -1 {
-            panic!("couldn't generate random bytes: {}", io::Error::last_os_error());
-        }
-    }
-}
-
 // FIXME: once the 10.x release becomes the minimum, this can be dropped for simplification.
 #[cfg(target_os = "netbsd")]
 mod imp {
diff --git a/library/std/src/sys/unix/time.rs b/library/std/src/sys/unix/time.rs
index 4fe61b28488..e4540b99413 100644
--- a/library/std/src/sys/unix/time.rs
+++ b/library/std/src/sys/unix/time.rs
@@ -1,8 +1,6 @@
 use crate::fmt;
 use crate::time::Duration;
 
-pub use self::inner::Instant;
-
 const NSEC_PER_SEC: u64 = 1_000_000_000;
 pub const UNIX_EPOCH: SystemTime = SystemTime { t: Timespec::zero() };
 #[allow(dead_code)] // Used for pthread condvar timeouts
@@ -40,6 +38,10 @@ impl SystemTime {
         SystemTime { t: Timespec::new(tv_sec, tv_nsec) }
     }
 
+    pub fn now() -> SystemTime {
+        SystemTime { t: Timespec::now(libc::CLOCK_REALTIME) }
+    }
+
     pub fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> {
         self.t.sub_timespec(&other.t)
     }
@@ -79,6 +81,36 @@ impl Timespec {
         Timespec { tv_sec, tv_nsec: unsafe { Nanoseconds(tv_nsec as u32) } }
     }
 
+    pub fn now(clock: libc::clockid_t) -> Timespec {
+        use crate::mem::MaybeUninit;
+        use crate::sys::cvt;
+
+        // Try to use 64-bit time in preparation for Y2038.
+        #[cfg(all(
+            target_os = "linux",
+            target_env = "gnu",
+            target_pointer_width = "32",
+            not(target_arch = "riscv32")
+        ))]
+        {
+            use crate::sys::weak::weak;
+
+            // __clock_gettime64 was added to 32-bit arches in glibc 2.34,
+            // and it handles both vDSO calls and ENOSYS fallbacks itself.
+            weak!(fn __clock_gettime64(libc::clockid_t, *mut __timespec64) -> libc::c_int);
+
+            if let Some(clock_gettime64) = __clock_gettime64.get() {
+                let mut t = MaybeUninit::uninit();
+                cvt(unsafe { clock_gettime64(clock, t.as_mut_ptr()) }).unwrap();
+                return Timespec::from(unsafe { t.assume_init() });
+            }
+        }
+
+        let mut t = MaybeUninit::uninit();
+        cvt(unsafe { libc::clock_gettime(clock, t.as_mut_ptr()) }).unwrap();
+        Timespec::from(unsafe { t.assume_init() })
+    }
+
     pub fn sub_timespec(&self, other: &Timespec) -> Result<Duration, Duration> {
         if self >= other {
             // NOTE(eddyb) two aspects of this `if`-`else` are required for LLVM
@@ -216,209 +248,59 @@ impl From<__timespec64> for Timespec {
     }
 }
 
-#[cfg(any(
-    all(target_os = "macos", any(not(target_arch = "aarch64"))),
-    target_os = "ios",
-    target_os = "watchos",
-    target_os = "tvos"
-))]
-mod inner {
-    use crate::sync::atomic::{AtomicU64, Ordering};
-    use crate::sys::cvt;
-    use crate::sys_common::mul_div_u64;
-    use crate::time::Duration;
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
+pub struct Instant {
+    t: Timespec,
+}
 
-    use super::{SystemTime, Timespec, NSEC_PER_SEC};
-
-    #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
-    pub struct Instant {
-        t: u64,
-    }
-
-    #[repr(C)]
-    #[derive(Copy, Clone)]
-    struct mach_timebase_info {
-        numer: u32,
-        denom: u32,
-    }
-    type mach_timebase_info_t = *mut mach_timebase_info;
-    type kern_return_t = libc::c_int;
-
-    impl Instant {
-        pub fn now() -> Instant {
-            extern "C" {
-                fn mach_absolute_time() -> u64;
-            }
-            Instant { t: unsafe { mach_absolute_time() } }
-        }
-
-        pub fn checked_sub_instant(&self, other: &Instant) -> Option<Duration> {
-            let diff = self.t.checked_sub(other.t)?;
-            let info = info();
-            let nanos = mul_div_u64(diff, info.numer as u64, info.denom as u64);
-            Some(Duration::new(nanos / NSEC_PER_SEC, (nanos % NSEC_PER_SEC) as u32))
-        }
-
-        pub fn checked_add_duration(&self, other: &Duration) -> Option<Instant> {
-            Some(Instant { t: self.t.checked_add(checked_dur2intervals(other)?)? })
-        }
-
-        pub fn checked_sub_duration(&self, other: &Duration) -> Option<Instant> {
-            Some(Instant { t: self.t.checked_sub(checked_dur2intervals(other)?)? })
-        }
-    }
-
-    impl SystemTime {
-        pub fn now() -> SystemTime {
-            use crate::ptr;
-
-            let mut s = libc::timeval { tv_sec: 0, tv_usec: 0 };
-            cvt(unsafe { libc::gettimeofday(&mut s, ptr::null_mut()) }).unwrap();
-            return SystemTime::from(s);
-        }
-    }
-
-    impl From<libc::timeval> for Timespec {
-        fn from(t: libc::timeval) -> Timespec {
-            Timespec::new(t.tv_sec as i64, 1000 * t.tv_usec as i64)
-        }
-    }
-
-    impl From<libc::timeval> for SystemTime {
-        fn from(t: libc::timeval) -> SystemTime {
-            SystemTime { t: Timespec::from(t) }
-        }
-    }
-
-    fn checked_dur2intervals(dur: &Duration) -> Option<u64> {
-        let nanos =
-            dur.as_secs().checked_mul(NSEC_PER_SEC)?.checked_add(dur.subsec_nanos() as u64)?;
-        let info = info();
-        Some(mul_div_u64(nanos, info.denom as u64, info.numer as u64))
-    }
-
-    fn info() -> mach_timebase_info {
-        // INFO_BITS conceptually is an `Option<mach_timebase_info>`. We can do
-        // this in 64 bits because we know 0 is never a valid value for the
-        // `denom` field.
+impl Instant {
+    pub fn now() -> Instant {
+        // https://www.manpagez.com/man/3/clock_gettime/
         //
-        // Encoding this as a single `AtomicU64` allows us to use `Relaxed`
-        // operations, as we are only interested in the effects on a single
-        // memory location.
-        static INFO_BITS: AtomicU64 = AtomicU64::new(0);
-
-        // If a previous thread has initialized `INFO_BITS`, use it.
-        let info_bits = INFO_BITS.load(Ordering::Relaxed);
-        if info_bits != 0 {
-            return info_from_bits(info_bits);
-        }
-
-        // ... otherwise learn for ourselves ...
-        extern "C" {
-            fn mach_timebase_info(info: mach_timebase_info_t) -> kern_return_t;
-        }
-
-        let mut info = info_from_bits(0);
-        unsafe {
-            mach_timebase_info(&mut info);
-        }
-        INFO_BITS.store(info_to_bits(info), Ordering::Relaxed);
-        info
+        // CLOCK_UPTIME_RAW   clock that increments monotonically, in the same man-
+        //                    ner as CLOCK_MONOTONIC_RAW, but that does not incre-
+        //                    ment while the system is asleep.  The returned value
+        //                    is identical to the result of mach_absolute_time()
+        //                    after the appropriate mach_timebase conversion is
+        //                    applied.
+        //
+        // Instant on macos was historically implemented using mach_absolute_time;
+        // we preserve this value domain out of an abundance of caution.
+        #[cfg(any(
+            target_os = "macos",
+            target_os = "ios",
+            target_os = "watchos",
+            target_os = "tvos"
+        ))]
+        const clock_id: libc::clockid_t = libc::CLOCK_UPTIME_RAW;
+        #[cfg(not(any(
+            target_os = "macos",
+            target_os = "ios",
+            target_os = "watchos",
+            target_os = "tvos"
+        )))]
+        const clock_id: libc::clockid_t = libc::CLOCK_MONOTONIC;
+        Instant { t: Timespec::now(clock_id) }
     }
 
-    #[inline]
-    fn info_to_bits(info: mach_timebase_info) -> u64 {
-        ((info.denom as u64) << 32) | (info.numer as u64)
+    pub fn checked_sub_instant(&self, other: &Instant) -> Option<Duration> {
+        self.t.sub_timespec(&other.t).ok()
     }
 
-    #[inline]
-    fn info_from_bits(bits: u64) -> mach_timebase_info {
-        mach_timebase_info { numer: bits as u32, denom: (bits >> 32) as u32 }
+    pub fn checked_add_duration(&self, other: &Duration) -> Option<Instant> {
+        Some(Instant { t: self.t.checked_add_duration(other)? })
+    }
+
+    pub fn checked_sub_duration(&self, other: &Duration) -> Option<Instant> {
+        Some(Instant { t: self.t.checked_sub_duration(other)? })
     }
 }
 
-#[cfg(not(any(
-    all(target_os = "macos", any(not(target_arch = "aarch64"))),
-    target_os = "ios",
-    target_os = "watchos",
-    target_os = "tvos"
-)))]
-mod inner {
-    use crate::fmt;
-    use crate::mem::MaybeUninit;
-    use crate::sys::cvt;
-    use crate::time::Duration;
-
-    use super::{SystemTime, Timespec};
-
-    #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
-    pub struct Instant {
-        t: Timespec,
-    }
-
-    impl Instant {
-        pub fn now() -> Instant {
-            #[cfg(target_os = "macos")]
-            const clock_id: libc::clockid_t = libc::CLOCK_UPTIME_RAW;
-            #[cfg(not(target_os = "macos"))]
-            const clock_id: libc::clockid_t = libc::CLOCK_MONOTONIC;
-            Instant { t: Timespec::now(clock_id) }
-        }
-
-        pub fn checked_sub_instant(&self, other: &Instant) -> Option<Duration> {
-            self.t.sub_timespec(&other.t).ok()
-        }
-
-        pub fn checked_add_duration(&self, other: &Duration) -> Option<Instant> {
-            Some(Instant { t: self.t.checked_add_duration(other)? })
-        }
-
-        pub fn checked_sub_duration(&self, other: &Duration) -> Option<Instant> {
-            Some(Instant { t: self.t.checked_sub_duration(other)? })
-        }
-    }
-
-    impl fmt::Debug for Instant {
-        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-            f.debug_struct("Instant")
-                .field("tv_sec", &self.t.tv_sec)
-                .field("tv_nsec", &self.t.tv_nsec.0)
-                .finish()
-        }
-    }
-
-    impl SystemTime {
-        pub fn now() -> SystemTime {
-            SystemTime { t: Timespec::now(libc::CLOCK_REALTIME) }
-        }
-    }
-
-    impl Timespec {
-        pub fn now(clock: libc::clockid_t) -> Timespec {
-            // Try to use 64-bit time in preparation for Y2038.
-            #[cfg(all(
-                target_os = "linux",
-                target_env = "gnu",
-                target_pointer_width = "32",
-                not(target_arch = "riscv32")
-            ))]
-            {
-                use crate::sys::weak::weak;
-
-                // __clock_gettime64 was added to 32-bit arches in glibc 2.34,
-                // and it handles both vDSO calls and ENOSYS fallbacks itself.
-                weak!(fn __clock_gettime64(libc::clockid_t, *mut super::__timespec64) -> libc::c_int);
-
-                if let Some(clock_gettime64) = __clock_gettime64.get() {
-                    let mut t = MaybeUninit::uninit();
-                    cvt(unsafe { clock_gettime64(clock, t.as_mut_ptr()) }).unwrap();
-                    return Timespec::from(unsafe { t.assume_init() });
-                }
-            }
-
-            let mut t = MaybeUninit::uninit();
-            cvt(unsafe { libc::clock_gettime(clock, t.as_mut_ptr()) }).unwrap();
-            Timespec::from(unsafe { t.assume_init() })
-        }
+impl fmt::Debug for Instant {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.debug_struct("Instant")
+            .field("tv_sec", &self.t.tv_sec)
+            .field("tv_nsec", &self.t.tv_nsec.0)
+            .finish()
     }
 }
diff --git a/library/std/src/sys/windows/c/windows_sys.lst b/library/std/src/sys/windows/c/windows_sys.lst
index dad4a4223b2..78b1988afeb 100644
--- a/library/std/src/sys/windows/c/windows_sys.lst
+++ b/library/std/src/sys/windows/c/windows_sys.lst
@@ -2505,9 +2505,12 @@ Windows.Win32.System.Threading.CREATE_SEPARATE_WOW_VDM
 Windows.Win32.System.Threading.CREATE_SHARED_WOW_VDM
 Windows.Win32.System.Threading.CREATE_SUSPENDED
 Windows.Win32.System.Threading.CREATE_UNICODE_ENVIRONMENT
+Windows.Win32.System.Threading.CREATE_WAITABLE_TIMER_HIGH_RESOLUTION
+Windows.Win32.System.Threading.CREATE_WAITABLE_TIMER_MANUAL_RESET
 Windows.Win32.System.Threading.CreateEventW
 Windows.Win32.System.Threading.CreateProcessW
 Windows.Win32.System.Threading.CreateThread
+Windows.Win32.System.Threading.CreateWaitableTimerExW
 Windows.Win32.System.Threading.DEBUG_ONLY_THIS_PROCESS
 Windows.Win32.System.Threading.DEBUG_PROCESS
 Windows.Win32.System.Threading.DeleteProcThreadAttributeList
@@ -2544,6 +2547,7 @@ Windows.Win32.System.Threading.REALTIME_PRIORITY_CLASS
 Windows.Win32.System.Threading.ReleaseSRWLockExclusive
 Windows.Win32.System.Threading.ReleaseSRWLockShared
 Windows.Win32.System.Threading.SetThreadStackGuarantee
+Windows.Win32.System.Threading.SetWaitableTimer
 Windows.Win32.System.Threading.Sleep
 Windows.Win32.System.Threading.SleepConditionVariableSRW
 Windows.Win32.System.Threading.SleepEx
@@ -2570,6 +2574,8 @@ Windows.Win32.System.Threading.TerminateProcess
 Windows.Win32.System.Threading.THREAD_CREATE_RUN_IMMEDIATELY
 Windows.Win32.System.Threading.THREAD_CREATE_SUSPENDED
 Windows.Win32.System.Threading.THREAD_CREATION_FLAGS
+Windows.Win32.System.Threading.TIMER_ALL_ACCESS
+Windows.Win32.System.Threading.TIMER_MODIFY_STATE
 Windows.Win32.System.Threading.TLS_OUT_OF_INDEXES
 Windows.Win32.System.Threading.TlsAlloc
 Windows.Win32.System.Threading.TlsFree
diff --git a/library/std/src/sys/windows/c/windows_sys.rs b/library/std/src/sys/windows/c/windows_sys.rs
index 20b44966a39..9ecd45e09ff 100644
--- a/library/std/src/sys/windows/c/windows_sys.rs
+++ b/library/std/src/sys/windows/c/windows_sys.rs
@@ -151,6 +151,15 @@ extern "system" {
     ) -> HANDLE;
 }
 #[link(name = "kernel32")]
+extern "system" {
+    pub fn CreateWaitableTimerExW(
+        lptimerattributes: *const SECURITY_ATTRIBUTES,
+        lptimername: PCWSTR,
+        dwflags: u32,
+        dwdesiredaccess: u32,
+    ) -> HANDLE;
+}
+#[link(name = "kernel32")]
 extern "system" {
     pub fn DeleteFileW(lpfilename: PCWSTR) -> BOOL;
 }
@@ -508,6 +517,17 @@ extern "system" {
     pub fn SetThreadStackGuarantee(stacksizeinbytes: *mut u32) -> BOOL;
 }
 #[link(name = "kernel32")]
+extern "system" {
+    pub fn SetWaitableTimer(
+        htimer: HANDLE,
+        lpduetime: *const i64,
+        lperiod: i32,
+        pfncompletionroutine: PTIMERAPCROUTINE,
+        lpargtocompletionroutine: *const ::core::ffi::c_void,
+        fresume: BOOL,
+    ) -> BOOL;
+}
+#[link(name = "kernel32")]
 extern "system" {
     pub fn Sleep(dwmilliseconds: u32) -> ();
 }
@@ -1165,6 +1185,8 @@ pub const CREATE_SEPARATE_WOW_VDM: PROCESS_CREATION_FLAGS = 2048u32;
 pub const CREATE_SHARED_WOW_VDM: PROCESS_CREATION_FLAGS = 4096u32;
 pub const CREATE_SUSPENDED: PROCESS_CREATION_FLAGS = 4u32;
 pub const CREATE_UNICODE_ENVIRONMENT: PROCESS_CREATION_FLAGS = 1024u32;
+pub const CREATE_WAITABLE_TIMER_HIGH_RESOLUTION: u32 = 2u32;
+pub const CREATE_WAITABLE_TIMER_MANUAL_RESET: u32 = 1u32;
 pub const CSTR_EQUAL: COMPARESTRING_RESULT = 2i32;
 pub const CSTR_GREATER_THAN: COMPARESTRING_RESULT = 3i32;
 pub const CSTR_LESS_THAN: COMPARESTRING_RESULT = 1i32;
@@ -3775,6 +3797,13 @@ pub const PROFILE_SERVER: PROCESS_CREATION_FLAGS = 1073741824u32;
 pub const PROFILE_USER: PROCESS_CREATION_FLAGS = 268435456u32;
 pub const PROGRESS_CONTINUE: u32 = 0u32;
 pub type PSTR = *mut u8;
+pub type PTIMERAPCROUTINE = ::core::option::Option<
+    unsafe extern "system" fn(
+        lpargtocompletionroutine: *const ::core::ffi::c_void,
+        dwtimerlowvalue: u32,
+        dwtimerhighvalue: u32,
+    ) -> (),
+>;
 pub type PWSTR = *mut u16;
 pub const READ_CONTROL: FILE_ACCESS_RIGHTS = 131072u32;
 pub const REALTIME_PRIORITY_CLASS: PROCESS_CREATION_FLAGS = 256u32;
@@ -3922,6 +3951,7 @@ pub type SYMBOLIC_LINK_FLAGS = u32;
 pub const SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE: SYMBOLIC_LINK_FLAGS = 2u32;
 pub const SYMBOLIC_LINK_FLAG_DIRECTORY: SYMBOLIC_LINK_FLAGS = 1u32;
 pub const SYMLINK_FLAG_RELATIVE: u32 = 1u32;
+pub type SYNCHRONIZATION_ACCESS_RIGHTS = u32;
 pub const SYNCHRONIZE: FILE_ACCESS_RIGHTS = 1048576u32;
 #[repr(C)]
 pub struct SYSTEM_INFO {
@@ -3968,6 +3998,8 @@ pub const TCP_NODELAY: i32 = 1i32;
 pub const THREAD_CREATE_RUN_IMMEDIATELY: THREAD_CREATION_FLAGS = 0u32;
 pub const THREAD_CREATE_SUSPENDED: THREAD_CREATION_FLAGS = 4u32;
 pub type THREAD_CREATION_FLAGS = u32;
+pub const TIMER_ALL_ACCESS: SYNCHRONIZATION_ACCESS_RIGHTS = 2031619u32;
+pub const TIMER_MODIFY_STATE: SYNCHRONIZATION_ACCESS_RIGHTS = 2u32;
 #[repr(C)]
 pub struct TIMEVAL {
     pub tv_sec: i32,
diff --git a/library/std/src/sys/windows/thread.rs b/library/std/src/sys/windows/thread.rs
index 4b825d2a9f5..1fe74493519 100644
--- a/library/std/src/sys/windows/thread.rs
+++ b/library/std/src/sys/windows/thread.rs
@@ -12,6 +12,7 @@ use crate::time::Duration;
 
 use core::ffi::c_void;
 
+use super::time::WaitableTimer;
 use super::to_u16s;
 
 pub const DEFAULT_MIN_STACK_SIZE: usize = 2 * 1024 * 1024;
@@ -87,7 +88,17 @@ impl Thread {
     }
 
     pub fn sleep(dur: Duration) {
-        unsafe { c::Sleep(super::dur2timeout(dur)) }
+        fn high_precision_sleep(dur: Duration) -> Result<(), ()> {
+            let timer = WaitableTimer::high_resolution()?;
+            timer.set(dur)?;
+            timer.wait()
+        }
+        // Attempt to use high-precision sleep (Windows 10, version 1803+).
+        // On error fallback to the standard `Sleep` function.
+        // Also preserves the zero duration behaviour of `Sleep`.
+        if dur.is_zero() || high_precision_sleep(dur).is_err() {
+            unsafe { c::Sleep(super::dur2timeout(dur)) }
+        }
     }
 
     pub fn handle(&self) -> &Handle {
diff --git a/library/std/src/sys/windows/time.rs b/library/std/src/sys/windows/time.rs
index b8209a85445..bece48e799f 100644
--- a/library/std/src/sys/windows/time.rs
+++ b/library/std/src/sys/windows/time.rs
@@ -1,11 +1,13 @@
 use crate::cmp::Ordering;
 use crate::fmt;
 use crate::mem;
+use crate::ptr::{null, null_mut};
 use crate::sys::c;
 use crate::sys_common::IntoInner;
 use crate::time::Duration;
 
 use core::hash::{Hash, Hasher};
+use core::ops::Neg;
 
 const NANOS_PER_SEC: u64 = 1_000_000_000;
 const INTERVALS_PER_SEC: u64 = NANOS_PER_SEC / 100;
@@ -222,3 +224,39 @@ mod perf_counter {
         qpc_value
     }
 }
+
+/// A timer you can wait on.
+pub(super) struct WaitableTimer {
+    handle: c::HANDLE,
+}
+impl WaitableTimer {
+    /// Create a high-resolution timer. Will fail before Windows 10, version 1803.
+    pub fn high_resolution() -> Result<Self, ()> {
+        let handle = unsafe {
+            c::CreateWaitableTimerExW(
+                null(),
+                null(),
+                c::CREATE_WAITABLE_TIMER_HIGH_RESOLUTION,
+                c::TIMER_ALL_ACCESS,
+            )
+        };
+        if handle != null_mut() { Ok(Self { handle }) } else { Err(()) }
+    }
+    pub fn set(&self, duration: Duration) -> Result<(), ()> {
+        // Convert the Duration to a format similar to FILETIME.
+        // Negative values are relative times whereas positive values are absolute.
+        // Therefore we negate the relative duration.
+        let time = checked_dur2intervals(&duration).ok_or(())?.neg();
+        let result = unsafe { c::SetWaitableTimer(self.handle, &time, 0, None, null(), c::FALSE) };
+        if result != 0 { Ok(()) } else { Err(()) }
+    }
+    pub fn wait(&self) -> Result<(), ()> {
+        let result = unsafe { c::WaitForSingleObject(self.handle, c::INFINITE) };
+        if result != c::WAIT_FAILED { Ok(()) } else { Err(()) }
+    }
+}
+impl Drop for WaitableTimer {
+    fn drop(&mut self) {
+        unsafe { c::CloseHandle(self.handle) };
+    }
+}
diff --git a/library/std/src/time.rs b/library/std/src/time.rs
index 90ac0098dec..91c010ef2b5 100644
--- a/library/std/src/time.rs
+++ b/library/std/src/time.rs
@@ -111,7 +111,7 @@ pub use core::time::TryFromFloatSecsError;
 /// |-----------|----------------------------------------------------------------------|
 /// | SGX       | [`insecure_time` usercall]. More information on [timekeeping in SGX] |
 /// | UNIX      | [clock_gettime (Monotonic Clock)]                                    |
-/// | Darwin    | [mach_absolute_time]                                                 |
+/// | Darwin    | [clock_gettime (Monotonic Clock)]                                    |
 /// | VXWorks   | [clock_gettime (Monotonic Clock)]                                    |
 /// | SOLID     | `get_tim`                                                            |
 /// | WASI      | [__wasi_clock_time_get (Monotonic Clock)]                            |
@@ -123,7 +123,6 @@ pub use core::time::TryFromFloatSecsError;
 /// [timekeeping in SGX]: https://edp.fortanix.com/docs/concepts/rust-std/#codestdtimecode
 /// [__wasi_clock_time_get (Monotonic Clock)]: https://github.com/WebAssembly/WASI/blob/main/legacy/preview1/docs.md#clock_time_get
 /// [clock_gettime (Monotonic Clock)]: https://linux.die.net/man/3/clock_gettime
-/// [mach_absolute_time]: https://developer.apple.com/library/archive/documentation/Darwin/Conceptual/KernelProgramming/services/services.html
 ///
 /// **Disclaimer:** These system calls might change over time.
 ///
@@ -224,7 +223,7 @@ pub struct Instant(time::Instant);
 /// |-----------|----------------------------------------------------------------------|
 /// | SGX       | [`insecure_time` usercall]. More information on [timekeeping in SGX] |
 /// | UNIX      | [clock_gettime (Realtime Clock)]                                     |
-/// | Darwin    | [gettimeofday]                                                       |
+/// | Darwin    | [clock_gettime (Realtime Clock)]                                     |
 /// | VXWorks   | [clock_gettime (Realtime Clock)]                                     |
 /// | SOLID     | `SOLID_RTC_ReadTime`                                                 |
 /// | WASI      | [__wasi_clock_time_get (Realtime Clock)]                             |
@@ -233,7 +232,6 @@ pub struct Instant(time::Instant);
 /// [currently]: crate::io#platform-specific-behavior
 /// [`insecure_time` usercall]: https://edp.fortanix.com/docs/api/fortanix_sgx_abi/struct.Usercalls.html#method.insecure_time
 /// [timekeeping in SGX]: https://edp.fortanix.com/docs/concepts/rust-std/#codestdtimecode
-/// [gettimeofday]: https://man7.org/linux/man-pages/man2/gettimeofday.2.html
 /// [clock_gettime (Realtime Clock)]: https://linux.die.net/man/3/clock_gettime
 /// [__wasi_clock_time_get (Realtime Clock)]: https://github.com/WebAssembly/WASI/blob/main/legacy/preview1/docs.md#clock_time_get
 /// [GetSystemTimePreciseAsFileTime]: https://docs.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-getsystemtimepreciseasfiletime
diff --git a/src/bootstrap/bootstrap_test.py b/src/bootstrap/bootstrap_test.py
index 7f16cac7890..e6caabec4f6 100644
--- a/src/bootstrap/bootstrap_test.py
+++ b/src/bootstrap/bootstrap_test.py
@@ -103,7 +103,6 @@ class GenerateAndParseConfig(unittest.TestCase):
     """Test that we can serialize and deserialize a config.toml file"""
     def test_no_args(self):
         build = serialize_and_parse([])
-        self.assertEqual(build.get_toml("change-id"), '116998')
         self.assertEqual(build.get_toml("profile"), 'dist')
         self.assertIsNone(build.get_toml("llvm.download-ci-llvm"))
 
diff --git a/src/doc/book b/src/doc/book
index 72187f5cd0b..3dca2fc50b9 160000
--- a/src/doc/book
+++ b/src/doc/book
@@ -1 +1 @@
-Subproject commit 72187f5cd0beaaa9c6f584156bcd88f921871e83
+Subproject commit 3dca2fc50b922a8efb94903b9fee8bb42ab48f38
diff --git a/src/doc/embedded-book b/src/doc/embedded-book
index eac173690b8..22bca3d0f6e 160000
--- a/src/doc/embedded-book
+++ b/src/doc/embedded-book
@@ -1 +1 @@
-Subproject commit eac173690b8cc99094e1d88bd49dd61127fbd285
+Subproject commit 22bca3d0f6e9b9b556689b54ce96f25b46ecd1b3
diff --git a/src/doc/nomicon b/src/doc/nomicon
index ddfa4214487..18422578149 160000
--- a/src/doc/nomicon
+++ b/src/doc/nomicon
@@ -1 +1 @@
-Subproject commit ddfa4214487686e91b21aa29afb972c08a8f0d5b
+Subproject commit 1842257814919fa62e81bdecd5e8f95be2839dbb
diff --git a/src/doc/reference b/src/doc/reference
index 142b2ed77d3..16fd3c06d9e 160000
--- a/src/doc/reference
+++ b/src/doc/reference
@@ -1 +1 @@
-Subproject commit 142b2ed77d33f37a9973772bd95e6144ed9dce43
+Subproject commit 16fd3c06d9e558dae2d52000818274ae70c9e90a
diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example
index 8eb3a01ab74..6709beeb7d0 160000
--- a/src/doc/rust-by-example
+++ b/src/doc/rust-by-example
@@ -1 +1 @@
-Subproject commit 8eb3a01ab74c567b7174784892fb807f2c632d6b
+Subproject commit 6709beeb7d0fbc5ffc91ac4893a24434123b9bfa
diff --git a/src/doc/rustc-dev-guide b/src/doc/rustc-dev-guide
index b98af7d661e..b0ee9ec8fa5 160000
--- a/src/doc/rustc-dev-guide
+++ b/src/doc/rustc-dev-guide
@@ -1 +1 @@
-Subproject commit b98af7d661e4744baab81fb8dc7a049e44a4a998
+Subproject commit b0ee9ec8fa59a6c7620165e061f4747202377a62
diff --git a/src/doc/unstable-book/src/compiler-flags/check-cfg.md b/src/doc/unstable-book/src/compiler-flags/check-cfg.md
index ca18ec567a4..7a3ef5e9e2b 100644
--- a/src/doc/unstable-book/src/compiler-flags/check-cfg.md
+++ b/src/doc/unstable-book/src/compiler-flags/check-cfg.md
@@ -123,7 +123,7 @@ rustc --check-cfg 'cfg(is_embedded, has_feathers, values(any()))' \
 fn do_embedded() {}         // and because names exhaustiveness was not disabled
 
 #[cfg(has_feathers)]        // This is expected as "has_feathers" was provided in cfg()
-fn do_features() {}         // and because names exhaustiveness was not disbaled
+fn do_features() {}         // and because names exhaustiveness was not disabled
 
 #[cfg(has_feathers = "zapping")] // This is expected as "has_feathers" was provided in cfg()
                                  // and because no value checking was enable for "has_feathers"
diff --git a/src/tools/clippy/tests/ui/missing_const_for_fn/auxiliary/helper.rs b/src/tools/clippy/tests/ui/missing_const_for_fn/auxiliary/helper.rs
index 7b9dc76b8f1..775e071147c 100644
--- a/src/tools/clippy/tests/ui/missing_const_for_fn/auxiliary/helper.rs
+++ b/src/tools/clippy/tests/ui/missing_const_for_fn/auxiliary/helper.rs
@@ -1,8 +1,8 @@
 // This file provides a const function that is unstably const forever.
 
 #![feature(staged_api)]
-#![stable(feature = "1", since = "1.0.0")]
+#![stable(feature = "clippytest", since = "1.0.0")]
 
-#[stable(feature = "1", since = "1.0.0")]
+#[stable(feature = "clippytest", since = "1.0.0")]
 #[rustc_const_unstable(feature = "foo", issue = "none")]
 pub const fn unstably_const_fn() {}
diff --git a/src/tools/miri/src/shims/windows/foreign_items.rs b/src/tools/miri/src/shims/windows/foreign_items.rs
index 4ad44adff04..bddc30b8379 100644
--- a/src/tools/miri/src/shims/windows/foreign_items.rs
+++ b/src/tools/miri/src/shims/windows/foreign_items.rs
@@ -272,6 +272,18 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
 
                 this.Sleep(timeout)?;
             }
+            "CreateWaitableTimerExW" => {
+                let [attributes, name, flags, access] =
+                    this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?;
+                this.read_pointer(attributes)?;
+                this.read_pointer(name)?;
+                this.read_scalar(flags)?.to_u32()?;
+                this.read_scalar(access)?.to_u32()?;
+                // Unimplemented. Always return failure.
+                let not_supported = this.eval_windows("c", "ERROR_NOT_SUPPORTED");
+                this.set_last_error(not_supported)?;
+                this.write_null(dest)?;
+            }
 
             // Synchronization primitives
             "AcquireSRWLockExclusive" => {
diff --git a/tests/mir-opt/const_debuginfo.main.ConstDebugInfo.diff b/tests/mir-opt/const_debuginfo.main.ConstDebugInfo.diff
index ed47baa67da..313e5dddbbb 100644
--- a/tests/mir-opt/const_debuginfo.main.ConstDebugInfo.diff
+++ b/tests/mir-opt/const_debuginfo.main.ConstDebugInfo.diff
@@ -41,7 +41,8 @@
 +                             debug ((f: (bool, bool, u32)).2: u32) => const 123_u32;
                               let _10: std::option::Option<u16>;
                               scope 7 {
-                                  debug o => _10;
+-                                 debug o => _10;
++                                 debug o => const Option::<u16>::Some(99_u16);
                                   let _17: u32;
                                   let _18: u32;
                                   scope 8 {
@@ -81,7 +82,7 @@
           _15 = const false;
           _16 = const 123_u32;
           StorageLive(_10);
-          _10 = Option::<u16>::Some(const 99_u16);
+          _10 = const Option::<u16>::Some(99_u16);
           _17 = const 32_u32;
           _18 = const 32_u32;
           StorageLive(_11);
@@ -97,3 +98,7 @@
       }
   }
   
+  ALLOC0 (size: 4, align: 2) {
+      01 00 63 00                                     │ ..c.
+  }
+  
diff --git a/tests/mir-opt/dataflow-const-prop/checked.main.DataflowConstProp.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/checked.main.DataflowConstProp.panic-abort.diff
index 2f1a70f32d0..4569ffe483b 100644
--- a/tests/mir-opt/dataflow-const-prop/checked.main.DataflowConstProp.panic-abort.diff
+++ b/tests/mir-opt/dataflow-const-prop/checked.main.DataflowConstProp.panic-abort.diff
@@ -43,7 +43,7 @@
 -         _6 = CheckedAdd(_4, _5);
 -         assert(!move (_6.1: bool), "attempt to compute `{} + {}`, which would overflow", move _4, move _5) -> [success: bb1, unwind unreachable];
 +         _5 = const 2_i32;
-+         _6 = CheckedAdd(const 1_i32, const 2_i32);
++         _6 = const (3_i32, false);
 +         assert(!const false, "attempt to compute `{} + {}`, which would overflow", const 1_i32, const 2_i32) -> [success: bb1, unwind unreachable];
       }
   
@@ -60,7 +60,7 @@
 -         _10 = CheckedAdd(_9, const 1_i32);
 -         assert(!move (_10.1: bool), "attempt to compute `{} + {}`, which would overflow", move _9, const 1_i32) -> [success: bb2, unwind unreachable];
 +         _9 = const i32::MAX;
-+         _10 = CheckedAdd(const i32::MAX, const 1_i32);
++         _10 = const (i32::MIN, true);
 +         assert(!const true, "attempt to compute `{} + {}`, which would overflow", const i32::MAX, const 1_i32) -> [success: bb2, unwind unreachable];
       }
   
@@ -76,5 +76,13 @@
           StorageDead(_1);
           return;
       }
++ }
++ 
++ ALLOC0 (size: 8, align: 4) {
++     00 00 00 80 01 __ __ __                         │ .....░░░
++ }
++ 
++ ALLOC1 (size: 8, align: 4) {
++     03 00 00 00 00 __ __ __                         │ .....░░░
   }
   
diff --git a/tests/mir-opt/dataflow-const-prop/checked.main.DataflowConstProp.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/checked.main.DataflowConstProp.panic-unwind.diff
index 0d8a9aca3d8..aa7e404eb9f 100644
--- a/tests/mir-opt/dataflow-const-prop/checked.main.DataflowConstProp.panic-unwind.diff
+++ b/tests/mir-opt/dataflow-const-prop/checked.main.DataflowConstProp.panic-unwind.diff
@@ -43,7 +43,7 @@
 -         _6 = CheckedAdd(_4, _5);
 -         assert(!move (_6.1: bool), "attempt to compute `{} + {}`, which would overflow", move _4, move _5) -> [success: bb1, unwind continue];
 +         _5 = const 2_i32;
-+         _6 = CheckedAdd(const 1_i32, const 2_i32);
++         _6 = const (3_i32, false);
 +         assert(!const false, "attempt to compute `{} + {}`, which would overflow", const 1_i32, const 2_i32) -> [success: bb1, unwind continue];
       }
   
@@ -60,7 +60,7 @@
 -         _10 = CheckedAdd(_9, const 1_i32);
 -         assert(!move (_10.1: bool), "attempt to compute `{} + {}`, which would overflow", move _9, const 1_i32) -> [success: bb2, unwind continue];
 +         _9 = const i32::MAX;
-+         _10 = CheckedAdd(const i32::MAX, const 1_i32);
++         _10 = const (i32::MIN, true);
 +         assert(!const true, "attempt to compute `{} + {}`, which would overflow", const i32::MAX, const 1_i32) -> [success: bb2, unwind continue];
       }
   
@@ -76,5 +76,13 @@
           StorageDead(_1);
           return;
       }
++ }
++ 
++ ALLOC0 (size: 8, align: 4) {
++     00 00 00 80 01 __ __ __                         │ .....░░░
++ }
++ 
++ ALLOC1 (size: 8, align: 4) {
++     03 00 00 00 00 __ __ __                         │ .....░░░
   }
   
diff --git a/tests/mir-opt/dataflow-const-prop/checked.rs b/tests/mir-opt/dataflow-const-prop/checked.rs
index b41ac0b3d2a..f7fac8890a0 100644
--- a/tests/mir-opt/dataflow-const-prop/checked.rs
+++ b/tests/mir-opt/dataflow-const-prop/checked.rs
@@ -1,7 +1,7 @@
 // skip-filecheck
-// EMIT_MIR_FOR_EACH_PANIC_STRATEGY
 // unit-test: DataflowConstProp
 // compile-flags: -Coverflow-checks=on
+// EMIT_MIR_FOR_EACH_PANIC_STRATEGY
 
 // EMIT_MIR checked.main.DataflowConstProp.diff
 #[allow(arithmetic_overflow)]
diff --git a/tests/mir-opt/dataflow-const-prop/enum.simple.DataflowConstProp.32bit.diff b/tests/mir-opt/dataflow-const-prop/enum.simple.DataflowConstProp.32bit.diff
index 3946e7c7d96..798b0c041b4 100644
--- a/tests/mir-opt/dataflow-const-prop/enum.simple.DataflowConstProp.32bit.diff
+++ b/tests/mir-opt/dataflow-const-prop/enum.simple.DataflowConstProp.32bit.diff
@@ -23,7 +23,8 @@
   
       bb0: {
           StorageLive(_1);
-          _1 = E::V1(const 0_i32);
+-         _1 = E::V1(const 0_i32);
++         _1 = const E::V1(0_i32);
           StorageLive(_2);
 -         _3 = discriminant(_1);
 -         switchInt(move _3) -> [0: bb3, 1: bb1, otherwise: bb2];
@@ -59,5 +60,9 @@
           StorageDead(_1);
           return;
       }
++ }
++ 
++ ALLOC0 (size: 8, align: 4) {
++     00 00 00 00 00 00 00 00                         │ ........
   }
   
diff --git a/tests/mir-opt/dataflow-const-prop/enum.simple.DataflowConstProp.64bit.diff b/tests/mir-opt/dataflow-const-prop/enum.simple.DataflowConstProp.64bit.diff
index 3946e7c7d96..798b0c041b4 100644
--- a/tests/mir-opt/dataflow-const-prop/enum.simple.DataflowConstProp.64bit.diff
+++ b/tests/mir-opt/dataflow-const-prop/enum.simple.DataflowConstProp.64bit.diff
@@ -23,7 +23,8 @@
   
       bb0: {
           StorageLive(_1);
-          _1 = E::V1(const 0_i32);
+-         _1 = E::V1(const 0_i32);
++         _1 = const E::V1(0_i32);
           StorageLive(_2);
 -         _3 = discriminant(_1);
 -         switchInt(move _3) -> [0: bb3, 1: bb1, otherwise: bb2];
@@ -59,5 +60,9 @@
           StorageDead(_1);
           return;
       }
++ }
++ 
++ ALLOC0 (size: 8, align: 4) {
++     00 00 00 00 00 00 00 00                         │ ........
   }
   
diff --git a/tests/mir-opt/dataflow-const-prop/enum.statics.DataflowConstProp.32bit.diff b/tests/mir-opt/dataflow-const-prop/enum.statics.DataflowConstProp.32bit.diff
index 1348b279330..d502b198239 100644
--- a/tests/mir-opt/dataflow-const-prop/enum.statics.DataflowConstProp.32bit.diff
+++ b/tests/mir-opt/dataflow-const-prop/enum.statics.DataflowConstProp.32bit.diff
@@ -44,7 +44,8 @@
           StorageLive(_1);
           StorageLive(_2);
           _2 = const {ALLOC1: &E};
-          _1 = (*_2);
+-         _1 = (*_2);
++         _1 = const E::V1(0_i32);
           StorageDead(_2);
           StorageLive(_3);
 -         _4 = discriminant(_1);
@@ -110,6 +111,10 @@
           StorageDead(_1);
           return;
       }
++ }
++ 
++ ALLOC3 (size: 8, align: 4) {
++     00 00 00 00 00 00 00 00                         │ ........
   }
   
   ALLOC2 (static: RC, size: 4, align: 4) {
diff --git a/tests/mir-opt/dataflow-const-prop/enum.statics.DataflowConstProp.64bit.diff b/tests/mir-opt/dataflow-const-prop/enum.statics.DataflowConstProp.64bit.diff
index 66929e886d3..5d69572b507 100644
--- a/tests/mir-opt/dataflow-const-prop/enum.statics.DataflowConstProp.64bit.diff
+++ b/tests/mir-opt/dataflow-const-prop/enum.statics.DataflowConstProp.64bit.diff
@@ -44,7 +44,8 @@
           StorageLive(_1);
           StorageLive(_2);
           _2 = const {ALLOC1: &E};
-          _1 = (*_2);
+-         _1 = (*_2);
++         _1 = const E::V1(0_i32);
           StorageDead(_2);
           StorageLive(_3);
 -         _4 = discriminant(_1);
@@ -110,6 +111,10 @@
           StorageDead(_1);
           return;
       }
++ }
++ 
++ ALLOC3 (size: 8, align: 4) {
++     00 00 00 00 00 00 00 00                         │ ........
   }
   
   ALLOC2 (static: RC, size: 8, align: 8) {
diff --git a/tests/mir-opt/dataflow-const-prop/inherit_overflow.main.DataflowConstProp.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/inherit_overflow.main.DataflowConstProp.panic-abort.diff
index 87bb1454c96..2d4591ea2d3 100644
--- a/tests/mir-opt/dataflow-const-prop/inherit_overflow.main.DataflowConstProp.panic-abort.diff
+++ b/tests/mir-opt/dataflow-const-prop/inherit_overflow.main.DataflowConstProp.panic-abort.diff
@@ -23,7 +23,7 @@
           StorageLive(_4);
 -         _4 = CheckedAdd(_2, _3);
 -         assert(!move (_4.1: bool), "attempt to compute `{} + {}`, which would overflow", _2, _3) -> [success: bb1, unwind unreachable];
-+         _4 = CheckedAdd(const u8::MAX, const 1_u8);
++         _4 = const (0_u8, true);
 +         assert(!const true, "attempt to compute `{} + {}`, which would overflow", const u8::MAX, const 1_u8) -> [success: bb1, unwind unreachable];
       }
   
@@ -37,5 +37,9 @@
           _0 = const ();
           return;
       }
++ }
++ 
++ ALLOC0 (size: 2, align: 1) {
++     00 01                                           │ ..
   }
   
diff --git a/tests/mir-opt/dataflow-const-prop/inherit_overflow.main.DataflowConstProp.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/inherit_overflow.main.DataflowConstProp.panic-unwind.diff
index b2f13640a4c..e99ac782a2f 100644
--- a/tests/mir-opt/dataflow-const-prop/inherit_overflow.main.DataflowConstProp.panic-unwind.diff
+++ b/tests/mir-opt/dataflow-const-prop/inherit_overflow.main.DataflowConstProp.panic-unwind.diff
@@ -23,7 +23,7 @@
           StorageLive(_4);
 -         _4 = CheckedAdd(_2, _3);
 -         assert(!move (_4.1: bool), "attempt to compute `{} + {}`, which would overflow", _2, _3) -> [success: bb1, unwind continue];
-+         _4 = CheckedAdd(const u8::MAX, const 1_u8);
++         _4 = const (0_u8, true);
 +         assert(!const true, "attempt to compute `{} + {}`, which would overflow", const u8::MAX, const 1_u8) -> [success: bb1, unwind continue];
       }
   
@@ -37,5 +37,9 @@
           _0 = const ();
           return;
       }
++ }
++ 
++ ALLOC0 (size: 2, align: 1) {
++     00 01                                           │ ..
   }
   
diff --git a/tests/mir-opt/dataflow-const-prop/repr_transparent.main.DataflowConstProp.diff b/tests/mir-opt/dataflow-const-prop/repr_transparent.main.DataflowConstProp.diff
index 4b1a8d932c6..98bd40ab2c3 100644
--- a/tests/mir-opt/dataflow-const-prop/repr_transparent.main.DataflowConstProp.diff
+++ b/tests/mir-opt/dataflow-const-prop/repr_transparent.main.DataflowConstProp.diff
@@ -17,7 +17,8 @@
   
       bb0: {
           StorageLive(_1);
-          _1 = I32(const 0_i32);
+-         _1 = I32(const 0_i32);
++         _1 = const I32(0_i32);
           StorageLive(_2);
           StorageLive(_3);
           StorageLive(_4);
@@ -31,12 +32,20 @@
           StorageDead(_5);
           StorageDead(_4);
 -         _2 = I32(move _3);
-+         _2 = I32(const 0_i32);
++         _2 = const I32(0_i32);
           StorageDead(_3);
           _0 = const ();
           StorageDead(_2);
           StorageDead(_1);
           return;
       }
++ }
++ 
++ ALLOC0 (size: 4, align: 4) {
++     00 00 00 00                                     │ ....
++ }
++ 
++ ALLOC1 (size: 4, align: 4) {
++     00 00 00 00                                     │ ....
   }
   
diff --git a/tests/mir-opt/dataflow-const-prop/struct.main.DataflowConstProp.32bit.diff b/tests/mir-opt/dataflow-const-prop/struct.main.DataflowConstProp.32bit.diff
index e80f31ca934..8499d0a89c3 100644
--- a/tests/mir-opt/dataflow-const-prop/struct.main.DataflowConstProp.32bit.diff
+++ b/tests/mir-opt/dataflow-const-prop/struct.main.DataflowConstProp.32bit.diff
@@ -7,13 +7,24 @@
       let mut _3: i32;
       let mut _5: i32;
       let mut _6: i32;
-      let mut _11: BigStruct;
-      let mut _16: &&BigStruct;
-      let mut _17: &BigStruct;
-      let mut _18: &BigStruct;
-      let mut _19: &BigStruct;
-      let mut _20: &BigStruct;
-      let mut _21: &BigStruct;
+      let mut _10: SmallStruct;
+      let mut _14: &&SmallStruct;
+      let mut _16: f32;
+      let mut _17: std::option::Option<S>;
+      let mut _18: &[f32];
+      let mut _22: BigStruct;
+      let mut _26: &&BigStruct;
+      let mut _28: f32;
+      let mut _29: std::option::Option<S>;
+      let mut _30: &[f32];
+      let mut _31: &SmallStruct;
+      let mut _32: &SmallStruct;
+      let mut _33: &SmallStruct;
+      let mut _34: &SmallStruct;
+      let mut _35: &BigStruct;
+      let mut _36: &BigStruct;
+      let mut _37: &BigStruct;
+      let mut _38: &BigStruct;
       scope 1 {
           debug s => _1;
           let _2: i32;
@@ -22,24 +33,44 @@
               let _4: i32;
               scope 3 {
                   debug b => _4;
-                  let _7: S;
-                  let _8: u8;
-                  let _9: f32;
-                  let _10: S;
+                  let _7: f32;
+                  let _8: std::option::Option<S>;
+                  let _9: &[f32];
                   scope 4 {
                       debug a => _7;
                       debug b => _8;
                       debug c => _9;
-                      debug d => _10;
-                      let _12: S;
-                      let _13: u8;
-                      let _14: f32;
-                      let _15: S;
+                      let _11: f32;
+                      let _12: std::option::Option<S>;
+                      let _13: &[f32];
                       scope 5 {
-                          debug a => _12;
-                          debug b => _13;
-                          debug c => _14;
-                          debug d => _15;
+                          debug a => _11;
+                          debug b => _12;
+                          debug c => _13;
+                          let _15: SmallStruct;
+                          scope 6 {
+                              debug ss => _15;
+                              let _19: f32;
+                              let _20: std::option::Option<S>;
+                              let _21: &[f32];
+                              scope 7 {
+                                  debug a => _19;
+                                  debug b => _20;
+                                  debug c => _21;
+                                  let _23: f32;
+                                  let _24: std::option::Option<S>;
+                                  let _25: &[f32];
+                                  scope 8 {
+                                      debug a => _23;
+                                      debug b => _24;
+                                      debug c => _25;
+                                      let _27: BigStruct;
+                                      scope 9 {
+                                          debug bs => _27;
+                                      }
+                                  }
+                              }
+                          }
                       }
                   }
               }
@@ -48,7 +79,8 @@
   
       bb0: {
           StorageLive(_1);
-          _1 = S(const 1_i32);
+-         _1 = S(const 1_i32);
++         _1 = const S(1_i32);
           StorageLive(_2);
           StorageLive(_3);
 -         _3 = (_1.0: i32);
@@ -68,47 +100,95 @@
 +         _4 = const 6_i32;
           StorageDead(_6);
           StorageDead(_5);
-          StorageLive(_11);
-          _11 = const _;
-          StorageLive(_7);
--         _7 = (_11.0: S);
-+         _7 = const S(1_i32);
-          StorageLive(_8);
--         _8 = (_11.1: u8);
-+         _8 = const 5_u8;
-          StorageLive(_9);
--         _9 = (_11.2: f32);
-+         _9 = const 7f32;
           StorageLive(_10);
--         _10 = (_11.3: S);
-+         _10 = const S(13_i32);
-          StorageDead(_11);
-          StorageLive(_16);
-          _16 = const {ALLOC1: &&BigStruct};
-          _17 = deref_copy (*_16);
-          StorageLive(_12);
-          _18 = deref_copy (*_16);
--         _12 = ((*_18).0: S);
-+         _12 = const S(1_i32);
-          StorageLive(_13);
-          _19 = deref_copy (*_16);
--         _13 = ((*_19).1: u8);
-+         _13 = const 5_u8;
+          _10 = const _;
+          StorageLive(_7);
+-         _7 = (_10.0: f32);
++         _7 = const 4f32;
+          StorageLive(_8);
+-         _8 = (_10.1: std::option::Option<S>);
++         _8 = const Option::<S>::Some(S(1_i32));
+          StorageLive(_9);
+          _9 = (_10.2: &[f32]);
+          StorageDead(_10);
           StorageLive(_14);
-          _20 = deref_copy (*_16);
--         _14 = ((*_20).2: f32);
-+         _14 = const 7f32;
-          StorageLive(_15);
-          _21 = deref_copy (*_16);
--         _15 = ((*_21).3: S);
-+         _15 = const S(13_i32);
-          StorageDead(_16);
-          _0 = const ();
-          StorageDead(_15);
+          _14 = const {ALLOC4: &&SmallStruct};
+          _31 = deref_copy (*_14);
+          StorageLive(_11);
+          _32 = deref_copy (*_14);
+-         _11 = ((*_32).0: f32);
++         _11 = const 9f32;
+          StorageLive(_12);
+          _33 = deref_copy (*_14);
+          _12 = ((*_33).1: std::option::Option<S>);
+          StorageLive(_13);
+          _34 = deref_copy (*_14);
+          _13 = ((*_34).2: &[f32]);
           StorageDead(_14);
+          StorageLive(_15);
+          StorageLive(_16);
+-         _16 = _11;
++         _16 = const 9f32;
+          StorageLive(_17);
+          _17 = _12;
+          StorageLive(_18);
+          _18 = _13;
+-         _15 = SmallStruct(move _16, move _17, move _18);
++         _15 = SmallStruct(const 9f32, move _17, move _18);
+          StorageDead(_18);
+          StorageDead(_17);
+          StorageDead(_16);
+          StorageLive(_22);
+          _22 = const _;
+          StorageLive(_19);
+-         _19 = (_22.0: f32);
++         _19 = const 25f32;
+          StorageLive(_20);
+          _20 = (_22.1: std::option::Option<S>);
+          StorageLive(_21);
+          _21 = (_22.2: &[f32]);
+          StorageDead(_22);
+          StorageLive(_26);
+          _26 = const {ALLOC5: &&BigStruct};
+          _35 = deref_copy (*_26);
+          StorageLive(_23);
+          _36 = deref_copy (*_26);
+-         _23 = ((*_36).0: f32);
++         _23 = const 82f32;
+          StorageLive(_24);
+          _37 = deref_copy (*_26);
+-         _24 = ((*_37).1: std::option::Option<S>);
++         _24 = const Option::<S>::Some(S(35_i32));
+          StorageLive(_25);
+          _38 = deref_copy (*_26);
+          _25 = ((*_38).2: &[f32]);
+          StorageDead(_26);
+          StorageLive(_27);
+          StorageLive(_28);
+-         _28 = _23;
++         _28 = const 82f32;
+          StorageLive(_29);
+-         _29 = _24;
++         _29 = const Option::<S>::Some(S(35_i32));
+          StorageLive(_30);
+          _30 = _25;
+-         _27 = BigStruct(move _28, move _29, move _30);
++         _27 = BigStruct(const 82f32, const Option::<S>::Some(S(35_i32)), move _30);
+          StorageDead(_30);
+          StorageDead(_29);
+          StorageDead(_28);
+          _0 = const ();
+          StorageDead(_27);
+          StorageDead(_25);
+          StorageDead(_24);
+          StorageDead(_23);
+          StorageDead(_21);
+          StorageDead(_20);
+          StorageDead(_19);
+          StorageDead(_15);
           StorageDead(_13);
           StorageDead(_12);
-          StorageDead(_10);
+          StorageDead(_11);
           StorageDead(_9);
           StorageDead(_8);
           StorageDead(_7);
@@ -117,13 +197,51 @@
           StorageDead(_1);
           return;
       }
++ }
++ 
++ ALLOC6 (size: 8, align: 4) {
++     01 00 00 00 23 00 00 00                         │ ....#...
++ }
++ 
++ ALLOC7 (size: 8, align: 4) {
++     01 00 00 00 23 00 00 00                         │ ....#...
++ }
++ 
++ ALLOC8 (size: 8, align: 4) {
++     01 00 00 00 23 00 00 00                         │ ....#...
++ }
++ 
++ ALLOC9 (size: 8, align: 4) {
++     01 00 00 00 01 00 00 00                         │ ........
++ }
++ 
++ ALLOC10 (size: 4, align: 4) {
++     01 00 00 00                                     │ ....
   }
   
-  ALLOC1 (static: STAT, size: 4, align: 4) {
+  ALLOC5 (static: BIG_STAT, size: 4, align: 4) {
       ╾ALLOC0╼                                     │ ╾──╼
   }
   
-  ALLOC0 (size: 16, align: 4) {
-      01 00 00 00 00 00 e0 40 0d 00 00 00 05 __ __ __ │ .......@.....░░░
+  ALLOC0 (size: 20, align: 4) {
+      0x00 │ 01 00 00 00 23 00 00 00 ╾ALLOC1╼ 02 00 00 00 │ ....#...╾──╼....
+      0x10 │ 00 00 a4 42                                     │ ...B
+  }
+  
+  ALLOC1 (size: 8, align: 4) {
+      00 00 34 42 00 00 90 42                         │ ..4B...B
+  }
+  
+  ALLOC4 (static: SMALL_STAT, size: 4, align: 4) {
+      ╾ALLOC2╼                                     │ ╾──╼
+  }
+  
+  ALLOC2 (size: 20, align: 4) {
+      0x00 │ 00 00 00 00 __ __ __ __ ╾ALLOC3╼ 01 00 00 00 │ ....░░░░╾──╼....
+      0x10 │ 00 00 10 41                                     │ ...A
+  }
+  
+  ALLOC3 (size: 4, align: 4) {
+      00 00 50 41                                     │ ..PA
   }
   
diff --git a/tests/mir-opt/dataflow-const-prop/struct.main.DataflowConstProp.64bit.diff b/tests/mir-opt/dataflow-const-prop/struct.main.DataflowConstProp.64bit.diff
index de9cf197199..01ec3f623d1 100644
--- a/tests/mir-opt/dataflow-const-prop/struct.main.DataflowConstProp.64bit.diff
+++ b/tests/mir-opt/dataflow-const-prop/struct.main.DataflowConstProp.64bit.diff
@@ -7,13 +7,24 @@
       let mut _3: i32;
       let mut _5: i32;
       let mut _6: i32;
-      let mut _11: BigStruct;
-      let mut _16: &&BigStruct;
-      let mut _17: &BigStruct;
-      let mut _18: &BigStruct;
-      let mut _19: &BigStruct;
-      let mut _20: &BigStruct;
-      let mut _21: &BigStruct;
+      let mut _10: SmallStruct;
+      let mut _14: &&SmallStruct;
+      let mut _16: f32;
+      let mut _17: std::option::Option<S>;
+      let mut _18: &[f32];
+      let mut _22: BigStruct;
+      let mut _26: &&BigStruct;
+      let mut _28: f32;
+      let mut _29: std::option::Option<S>;
+      let mut _30: &[f32];
+      let mut _31: &SmallStruct;
+      let mut _32: &SmallStruct;
+      let mut _33: &SmallStruct;
+      let mut _34: &SmallStruct;
+      let mut _35: &BigStruct;
+      let mut _36: &BigStruct;
+      let mut _37: &BigStruct;
+      let mut _38: &BigStruct;
       scope 1 {
           debug s => _1;
           let _2: i32;
@@ -22,24 +33,44 @@
               let _4: i32;
               scope 3 {
                   debug b => _4;
-                  let _7: S;
-                  let _8: u8;
-                  let _9: f32;
-                  let _10: S;
+                  let _7: f32;
+                  let _8: std::option::Option<S>;
+                  let _9: &[f32];
                   scope 4 {
                       debug a => _7;
                       debug b => _8;
                       debug c => _9;
-                      debug d => _10;
-                      let _12: S;
-                      let _13: u8;
-                      let _14: f32;
-                      let _15: S;
+                      let _11: f32;
+                      let _12: std::option::Option<S>;
+                      let _13: &[f32];
                       scope 5 {
-                          debug a => _12;
-                          debug b => _13;
-                          debug c => _14;
-                          debug d => _15;
+                          debug a => _11;
+                          debug b => _12;
+                          debug c => _13;
+                          let _15: SmallStruct;
+                          scope 6 {
+                              debug ss => _15;
+                              let _19: f32;
+                              let _20: std::option::Option<S>;
+                              let _21: &[f32];
+                              scope 7 {
+                                  debug a => _19;
+                                  debug b => _20;
+                                  debug c => _21;
+                                  let _23: f32;
+                                  let _24: std::option::Option<S>;
+                                  let _25: &[f32];
+                                  scope 8 {
+                                      debug a => _23;
+                                      debug b => _24;
+                                      debug c => _25;
+                                      let _27: BigStruct;
+                                      scope 9 {
+                                          debug bs => _27;
+                                      }
+                                  }
+                              }
+                          }
                       }
                   }
               }
@@ -48,7 +79,8 @@
   
       bb0: {
           StorageLive(_1);
-          _1 = S(const 1_i32);
+-         _1 = S(const 1_i32);
++         _1 = const S(1_i32);
           StorageLive(_2);
           StorageLive(_3);
 -         _3 = (_1.0: i32);
@@ -68,47 +100,95 @@
 +         _4 = const 6_i32;
           StorageDead(_6);
           StorageDead(_5);
-          StorageLive(_11);
-          _11 = const _;
-          StorageLive(_7);
--         _7 = (_11.0: S);
-+         _7 = const S(1_i32);
-          StorageLive(_8);
--         _8 = (_11.1: u8);
-+         _8 = const 5_u8;
-          StorageLive(_9);
--         _9 = (_11.2: f32);
-+         _9 = const 7f32;
           StorageLive(_10);
--         _10 = (_11.3: S);
-+         _10 = const S(13_i32);
-          StorageDead(_11);
-          StorageLive(_16);
-          _16 = const {ALLOC1: &&BigStruct};
-          _17 = deref_copy (*_16);
-          StorageLive(_12);
-          _18 = deref_copy (*_16);
--         _12 = ((*_18).0: S);
-+         _12 = const S(1_i32);
-          StorageLive(_13);
-          _19 = deref_copy (*_16);
--         _13 = ((*_19).1: u8);
-+         _13 = const 5_u8;
+          _10 = const _;
+          StorageLive(_7);
+-         _7 = (_10.0: f32);
++         _7 = const 4f32;
+          StorageLive(_8);
+-         _8 = (_10.1: std::option::Option<S>);
++         _8 = const Option::<S>::Some(S(1_i32));
+          StorageLive(_9);
+          _9 = (_10.2: &[f32]);
+          StorageDead(_10);
           StorageLive(_14);
-          _20 = deref_copy (*_16);
--         _14 = ((*_20).2: f32);
-+         _14 = const 7f32;
-          StorageLive(_15);
-          _21 = deref_copy (*_16);
--         _15 = ((*_21).3: S);
-+         _15 = const S(13_i32);
-          StorageDead(_16);
-          _0 = const ();
-          StorageDead(_15);
+          _14 = const {ALLOC4: &&SmallStruct};
+          _31 = deref_copy (*_14);
+          StorageLive(_11);
+          _32 = deref_copy (*_14);
+-         _11 = ((*_32).0: f32);
++         _11 = const 9f32;
+          StorageLive(_12);
+          _33 = deref_copy (*_14);
+          _12 = ((*_33).1: std::option::Option<S>);
+          StorageLive(_13);
+          _34 = deref_copy (*_14);
+          _13 = ((*_34).2: &[f32]);
           StorageDead(_14);
+          StorageLive(_15);
+          StorageLive(_16);
+-         _16 = _11;
++         _16 = const 9f32;
+          StorageLive(_17);
+          _17 = _12;
+          StorageLive(_18);
+          _18 = _13;
+-         _15 = SmallStruct(move _16, move _17, move _18);
++         _15 = SmallStruct(const 9f32, move _17, move _18);
+          StorageDead(_18);
+          StorageDead(_17);
+          StorageDead(_16);
+          StorageLive(_22);
+          _22 = const _;
+          StorageLive(_19);
+-         _19 = (_22.0: f32);
++         _19 = const 25f32;
+          StorageLive(_20);
+          _20 = (_22.1: std::option::Option<S>);
+          StorageLive(_21);
+          _21 = (_22.2: &[f32]);
+          StorageDead(_22);
+          StorageLive(_26);
+          _26 = const {ALLOC5: &&BigStruct};
+          _35 = deref_copy (*_26);
+          StorageLive(_23);
+          _36 = deref_copy (*_26);
+-         _23 = ((*_36).0: f32);
++         _23 = const 82f32;
+          StorageLive(_24);
+          _37 = deref_copy (*_26);
+-         _24 = ((*_37).1: std::option::Option<S>);
++         _24 = const Option::<S>::Some(S(35_i32));
+          StorageLive(_25);
+          _38 = deref_copy (*_26);
+          _25 = ((*_38).2: &[f32]);
+          StorageDead(_26);
+          StorageLive(_27);
+          StorageLive(_28);
+-         _28 = _23;
++         _28 = const 82f32;
+          StorageLive(_29);
+-         _29 = _24;
++         _29 = const Option::<S>::Some(S(35_i32));
+          StorageLive(_30);
+          _30 = _25;
+-         _27 = BigStruct(move _28, move _29, move _30);
++         _27 = BigStruct(const 82f32, const Option::<S>::Some(S(35_i32)), move _30);
+          StorageDead(_30);
+          StorageDead(_29);
+          StorageDead(_28);
+          _0 = const ();
+          StorageDead(_27);
+          StorageDead(_25);
+          StorageDead(_24);
+          StorageDead(_23);
+          StorageDead(_21);
+          StorageDead(_20);
+          StorageDead(_19);
+          StorageDead(_15);
           StorageDead(_13);
           StorageDead(_12);
-          StorageDead(_10);
+          StorageDead(_11);
           StorageDead(_9);
           StorageDead(_8);
           StorageDead(_7);
@@ -117,13 +197,51 @@
           StorageDead(_1);
           return;
       }
++ }
++ 
++ ALLOC6 (size: 8, align: 4) {
++     01 00 00 00 23 00 00 00                         │ ....#...
++ }
++ 
++ ALLOC7 (size: 8, align: 4) {
++     01 00 00 00 23 00 00 00                         │ ....#...
++ }
++ 
++ ALLOC8 (size: 8, align: 4) {
++     01 00 00 00 23 00 00 00                         │ ....#...
++ }
++ 
++ ALLOC9 (size: 8, align: 4) {
++     01 00 00 00 01 00 00 00                         │ ........
++ }
++ 
++ ALLOC10 (size: 4, align: 4) {
++     01 00 00 00                                     │ ....
   }
   
-  ALLOC1 (static: STAT, size: 8, align: 8) {
+  ALLOC5 (static: BIG_STAT, size: 8, align: 8) {
       ╾ALLOC0╼                         │ ╾──────╼
   }
   
-  ALLOC0 (size: 16, align: 4) {
-      01 00 00 00 00 00 e0 40 0d 00 00 00 05 __ __ __ │ .......@.....░░░
+  ALLOC0 (size: 32, align: 8) {
+      0x00 │ 01 00 00 00 23 00 00 00 ╾ALLOC1╼ │ ....#...╾──────╼
+      0x10 │ 02 00 00 00 00 00 00 00 00 00 a4 42 __ __ __ __ │ ...........B░░░░
+  }
+  
+  ALLOC1 (size: 8, align: 4) {
+      00 00 34 42 00 00 90 42                         │ ..4B...B
+  }
+  
+  ALLOC4 (static: SMALL_STAT, size: 8, align: 8) {
+      ╾ALLOC2╼                         │ ╾──────╼
+  }
+  
+  ALLOC2 (size: 32, align: 8) {
+      0x00 │ 00 00 00 00 __ __ __ __ ╾ALLOC3╼ │ ....░░░░╾──────╼
+      0x10 │ 01 00 00 00 00 00 00 00 00 00 10 41 __ __ __ __ │ ...........A░░░░
+  }
+  
+  ALLOC3 (size: 4, align: 4) {
+      00 00 50 41                                     │ ..PA
   }
   
diff --git a/tests/mir-opt/dataflow-const-prop/struct.rs b/tests/mir-opt/dataflow-const-prop/struct.rs
index 7b0646a5356..043981a2954 100644
--- a/tests/mir-opt/dataflow-const-prop/struct.rs
+++ b/tests/mir-opt/dataflow-const-prop/struct.rs
@@ -6,7 +6,10 @@
 struct S(i32);
 
 #[derive(Copy, Clone)]
-struct BigStruct(S, u8, f32, S);
+struct SmallStruct(f32, Option<S>, &'static [f32]);
+
+#[derive(Copy, Clone)]
+struct BigStruct(f32, Option<S>, &'static [f32]);
 
 // EMIT_MIR struct.main.DataflowConstProp.diff
 fn main() {
@@ -15,9 +18,21 @@ fn main() {
     s.0 = 3;
     let b = a + s.0;
 
-    const VAL: BigStruct = BigStruct(S(1), 5, 7., S(13));
-    let BigStruct(a, b, c, d) = VAL;
+    const SMALL_VAL: SmallStruct = SmallStruct(4., Some(S(1)), &[]);
+    let SmallStruct(a, b, c) = SMALL_VAL;
 
-    static STAT: &BigStruct = &BigStruct(S(1), 5, 7., S(13));
-    let BigStruct(a, b, c, d) = *STAT;
+    static SMALL_STAT: &SmallStruct = &SmallStruct(9., None, &[13.]);
+    let SmallStruct(a, b, c) = *SMALL_STAT;
+
+    let ss = SmallStruct(a, b, c);
+
+    const BIG_VAL: BigStruct = BigStruct(25., None, &[]);
+    let BigStruct(a, b, c) = BIG_VAL;
+
+    static BIG_STAT: &BigStruct = &BigStruct(82., Some(S(35)), &[45., 72.]);
+    let BigStruct(a, b, c) = *BIG_STAT;
+
+    // We arbitrarily limit the size of synthetized values to 4 pointers.
+    // `BigStruct` can be read, but we will keep a MIR aggregate for this.
+    let bs = BigStruct(a, b, c);
 }
diff --git a/tests/mir-opt/dataflow-const-prop/transmute.rs b/tests/mir-opt/dataflow-const-prop/transmute.rs
index 02e4f1e5013..bb85e458678 100644
--- a/tests/mir-opt/dataflow-const-prop/transmute.rs
+++ b/tests/mir-opt/dataflow-const-prop/transmute.rs
@@ -52,8 +52,8 @@ pub unsafe fn undef_union_as_integer() -> u32 {
 // EMIT_MIR transmute.unreachable_direct.DataflowConstProp.diff
 pub unsafe fn unreachable_direct() -> ! {
     // CHECK-LABEL: fn unreachable_direct(
-    // CHECK: [[unit:_.*]] = ();
-    // CHECK: move [[unit]] as Never (Transmute);
+    // CHECK: = const ();
+    // CHECK: = const ZeroSized: Never;
     let x: Never = unsafe { transmute(()) };
     match x {}
 }
diff --git a/tests/mir-opt/dataflow-const-prop/transmute.undef_union_as_integer.DataflowConstProp.32bit.diff b/tests/mir-opt/dataflow-const-prop/transmute.undef_union_as_integer.DataflowConstProp.32bit.diff
index fc0634b1f8f..fb28aa8f6d9 100644
--- a/tests/mir-opt/dataflow-const-prop/transmute.undef_union_as_integer.DataflowConstProp.32bit.diff
+++ b/tests/mir-opt/dataflow-const-prop/transmute.undef_union_as_integer.DataflowConstProp.32bit.diff
@@ -11,8 +11,10 @@
       bb0: {
           StorageLive(_1);
           StorageLive(_2);
-          _2 = ();
-          _1 = Union32 { value: move _2 };
+-         _2 = ();
+-         _1 = Union32 { value: move _2 };
++         _2 = const ();
++         _1 = Union32 { value: const () };
           StorageDead(_2);
           _0 = move _1 as u32 (Transmute);
           StorageDead(_1);
diff --git a/tests/mir-opt/dataflow-const-prop/transmute.undef_union_as_integer.DataflowConstProp.64bit.diff b/tests/mir-opt/dataflow-const-prop/transmute.undef_union_as_integer.DataflowConstProp.64bit.diff
index fc0634b1f8f..fb28aa8f6d9 100644
--- a/tests/mir-opt/dataflow-const-prop/transmute.undef_union_as_integer.DataflowConstProp.64bit.diff
+++ b/tests/mir-opt/dataflow-const-prop/transmute.undef_union_as_integer.DataflowConstProp.64bit.diff
@@ -11,8 +11,10 @@
       bb0: {
           StorageLive(_1);
           StorageLive(_2);
-          _2 = ();
-          _1 = Union32 { value: move _2 };
+-         _2 = ();
+-         _1 = Union32 { value: move _2 };
++         _2 = const ();
++         _1 = Union32 { value: const () };
           StorageDead(_2);
           _0 = move _1 as u32 (Transmute);
           StorageDead(_1);
diff --git a/tests/mir-opt/dataflow-const-prop/transmute.unreachable_direct.DataflowConstProp.32bit.diff b/tests/mir-opt/dataflow-const-prop/transmute.unreachable_direct.DataflowConstProp.32bit.diff
index acbb5cd1bc7..c8d4d6edba1 100644
--- a/tests/mir-opt/dataflow-const-prop/transmute.unreachable_direct.DataflowConstProp.32bit.diff
+++ b/tests/mir-opt/dataflow-const-prop/transmute.unreachable_direct.DataflowConstProp.32bit.diff
@@ -14,8 +14,10 @@
       bb0: {
           StorageLive(_1);
           StorageLive(_2);
-          _2 = ();
-          _1 = move _2 as Never (Transmute);
+-         _2 = ();
+-         _1 = move _2 as Never (Transmute);
++         _2 = const ();
++         _1 = const ZeroSized: Never;
           unreachable;
       }
   }
diff --git a/tests/mir-opt/dataflow-const-prop/transmute.unreachable_direct.DataflowConstProp.64bit.diff b/tests/mir-opt/dataflow-const-prop/transmute.unreachable_direct.DataflowConstProp.64bit.diff
index acbb5cd1bc7..c8d4d6edba1 100644
--- a/tests/mir-opt/dataflow-const-prop/transmute.unreachable_direct.DataflowConstProp.64bit.diff
+++ b/tests/mir-opt/dataflow-const-prop/transmute.unreachable_direct.DataflowConstProp.64bit.diff
@@ -14,8 +14,10 @@
       bb0: {
           StorageLive(_1);
           StorageLive(_2);
-          _2 = ();
-          _1 = move _2 as Never (Transmute);
+-         _2 = ();
+-         _1 = move _2 as Never (Transmute);
++         _2 = const ();
++         _1 = const ZeroSized: Never;
           unreachable;
       }
   }
diff --git a/tests/mir-opt/dataflow-const-prop/tuple.main.DataflowConstProp.diff b/tests/mir-opt/dataflow-const-prop/tuple.main.DataflowConstProp.32bit.diff
similarity index 57%
rename from tests/mir-opt/dataflow-const-prop/tuple.main.DataflowConstProp.diff
rename to tests/mir-opt/dataflow-const-prop/tuple.main.DataflowConstProp.32bit.diff
index 5e385d21ec6..f5723cac7d9 100644
--- a/tests/mir-opt/dataflow-const-prop/tuple.main.DataflowConstProp.diff
+++ b/tests/mir-opt/dataflow-const-prop/tuple.main.DataflowConstProp.32bit.diff
@@ -11,6 +11,9 @@
       let mut _8: i32;
       let mut _9: i32;
       let mut _10: i32;
+      let mut _12: i32;
+      let mut _13: (i32, i32);
+      let mut _14: i32;
       scope 1 {
           debug a => _1;
           let _2: i32;
@@ -19,13 +22,18 @@
               let _6: i32;
               scope 3 {
                   debug c => _6;
+                  let _11: (i32, (i32, i32), i32);
+                  scope 4 {
+                      debug d => _11;
+                  }
               }
           }
       }
   
       bb0: {
           StorageLive(_1);
-          _1 = (const 1_i32, const 2_i32);
+-         _1 = (const 1_i32, const 2_i32);
++         _1 = const (1_i32, 2_i32);
           StorageLive(_2);
           StorageLive(_3);
           StorageLive(_4);
@@ -41,7 +49,8 @@
 -         _2 = Add(move _3, const 3_i32);
 +         _2 = const 6_i32;
           StorageDead(_3);
-          _1 = (const 2_i32, const 3_i32);
+-         _1 = (const 2_i32, const 3_i32);
++         _1 = const (2_i32, 3_i32);
           StorageLive(_6);
           StorageLive(_7);
           StorageLive(_8);
@@ -61,11 +70,43 @@
 +         _6 = const 11_i32;
           StorageDead(_10);
           StorageDead(_7);
+          StorageLive(_11);
+          StorageLive(_12);
+-         _12 = _2;
++         _12 = const 6_i32;
+          StorageLive(_13);
+-         _13 = _1;
++         _13 = const (2_i32, 3_i32);
+          StorageLive(_14);
+-         _14 = _6;
+-         _11 = (move _12, move _13, move _14);
++         _14 = const 11_i32;
++         _11 = (const 6_i32, const (2_i32, 3_i32), const 11_i32);
+          StorageDead(_14);
+          StorageDead(_13);
+          StorageDead(_12);
           _0 = const ();
+          StorageDead(_11);
           StorageDead(_6);
           StorageDead(_2);
           StorageDead(_1);
           return;
       }
++ }
++ 
++ ALLOC0 (size: 8, align: 4) {
++     02 00 00 00 03 00 00 00                         │ ........
++ }
++ 
++ ALLOC1 (size: 8, align: 4) {
++     02 00 00 00 03 00 00 00                         │ ........
++ }
++ 
++ ALLOC2 (size: 8, align: 4) {
++     02 00 00 00 03 00 00 00                         │ ........
++ }
++ 
++ ALLOC3 (size: 8, align: 4) {
++     01 00 00 00 02 00 00 00                         │ ........
   }
   
diff --git a/tests/mir-opt/dataflow-const-prop/tuple.main.DataflowConstProp.64bit.diff b/tests/mir-opt/dataflow-const-prop/tuple.main.DataflowConstProp.64bit.diff
new file mode 100644
index 00000000000..f5723cac7d9
--- /dev/null
+++ b/tests/mir-opt/dataflow-const-prop/tuple.main.DataflowConstProp.64bit.diff
@@ -0,0 +1,112 @@
+- // MIR for `main` before DataflowConstProp
++ // MIR for `main` after DataflowConstProp
+  
+  fn main() -> () {
+      let mut _0: ();
+      let mut _1: (i32, i32);
+      let mut _3: i32;
+      let mut _4: i32;
+      let mut _5: i32;
+      let mut _7: i32;
+      let mut _8: i32;
+      let mut _9: i32;
+      let mut _10: i32;
+      let mut _12: i32;
+      let mut _13: (i32, i32);
+      let mut _14: i32;
+      scope 1 {
+          debug a => _1;
+          let _2: i32;
+          scope 2 {
+              debug b => _2;
+              let _6: i32;
+              scope 3 {
+                  debug c => _6;
+                  let _11: (i32, (i32, i32), i32);
+                  scope 4 {
+                      debug d => _11;
+                  }
+              }
+          }
+      }
+  
+      bb0: {
+          StorageLive(_1);
+-         _1 = (const 1_i32, const 2_i32);
++         _1 = const (1_i32, 2_i32);
+          StorageLive(_2);
+          StorageLive(_3);
+          StorageLive(_4);
+-         _4 = (_1.0: i32);
++         _4 = const 1_i32;
+          StorageLive(_5);
+-         _5 = (_1.1: i32);
+-         _3 = Add(move _4, move _5);
++         _5 = const 2_i32;
++         _3 = const 3_i32;
+          StorageDead(_5);
+          StorageDead(_4);
+-         _2 = Add(move _3, const 3_i32);
++         _2 = const 6_i32;
+          StorageDead(_3);
+-         _1 = (const 2_i32, const 3_i32);
++         _1 = const (2_i32, 3_i32);
+          StorageLive(_6);
+          StorageLive(_7);
+          StorageLive(_8);
+-         _8 = (_1.0: i32);
++         _8 = const 2_i32;
+          StorageLive(_9);
+-         _9 = (_1.1: i32);
+-         _7 = Add(move _8, move _9);
++         _9 = const 3_i32;
++         _7 = const 5_i32;
+          StorageDead(_9);
+          StorageDead(_8);
+          StorageLive(_10);
+-         _10 = _2;
+-         _6 = Add(move _7, move _10);
++         _10 = const 6_i32;
++         _6 = const 11_i32;
+          StorageDead(_10);
+          StorageDead(_7);
+          StorageLive(_11);
+          StorageLive(_12);
+-         _12 = _2;
++         _12 = const 6_i32;
+          StorageLive(_13);
+-         _13 = _1;
++         _13 = const (2_i32, 3_i32);
+          StorageLive(_14);
+-         _14 = _6;
+-         _11 = (move _12, move _13, move _14);
++         _14 = const 11_i32;
++         _11 = (const 6_i32, const (2_i32, 3_i32), const 11_i32);
+          StorageDead(_14);
+          StorageDead(_13);
+          StorageDead(_12);
+          _0 = const ();
+          StorageDead(_11);
+          StorageDead(_6);
+          StorageDead(_2);
+          StorageDead(_1);
+          return;
+      }
++ }
++ 
++ ALLOC0 (size: 8, align: 4) {
++     02 00 00 00 03 00 00 00                         │ ........
++ }
++ 
++ ALLOC1 (size: 8, align: 4) {
++     02 00 00 00 03 00 00 00                         │ ........
++ }
++ 
++ ALLOC2 (size: 8, align: 4) {
++     02 00 00 00 03 00 00 00                         │ ........
++ }
++ 
++ ALLOC3 (size: 8, align: 4) {
++     01 00 00 00 02 00 00 00                         │ ........
+  }
+  
diff --git a/tests/mir-opt/dataflow-const-prop/tuple.rs b/tests/mir-opt/dataflow-const-prop/tuple.rs
index c63ce8b140f..bb706eafe88 100644
--- a/tests/mir-opt/dataflow-const-prop/tuple.rs
+++ b/tests/mir-opt/dataflow-const-prop/tuple.rs
@@ -1,5 +1,6 @@
 // skip-filecheck
 // unit-test: DataflowConstProp
+// EMIT_MIR_FOR_EACH_BIT_WIDTH
 
 // EMIT_MIR tuple.main.DataflowConstProp.diff
 fn main() {
@@ -7,4 +8,6 @@ fn main() {
     let b = a.0 + a.1 + 3;
     a = (2, 3);
     let c = a.0 + a.1 + b;
+
+    let d = (b, a, c);
 }
diff --git a/tests/rustdoc/deprecated-future-staged-api.rs b/tests/rustdoc/deprecated-future-staged-api.rs
index 2670e7f5d04..09120b8d411 100644
--- a/tests/rustdoc/deprecated-future-staged-api.rs
+++ b/tests/rustdoc/deprecated-future-staged-api.rs
@@ -1,12 +1,12 @@
 #![feature(staged_api)]
-#![stable(feature = "deprecated-future-staged-api", since = "1.0.0")]
+#![stable(feature = "deprecated_future_staged_api", since = "1.0.0")]
 
 // @has deprecated_future_staged_api/index.html '//*[@class="stab deprecated"]' \
 //      'Deprecation planned'
 // @has deprecated_future_staged_api/struct.S1.html '//*[@class="stab deprecated"]' \
 //      'Deprecating in 99.99.99: effectively never'
 #[deprecated(since = "99.99.99", note = "effectively never")]
-#[stable(feature = "deprecated-future-staged-api", since = "1.0.0")]
+#[stable(feature = "deprecated_future_staged_api", since = "1.0.0")]
 pub struct S1;
 
 // @has deprecated_future_staged_api/index.html '//*[@class="stab deprecated"]' \
@@ -14,5 +14,5 @@ pub struct S1;
 // @has deprecated_future_staged_api/struct.S2.html '//*[@class="stab deprecated"]' \
 //      'Deprecating in a future Rust version: literally never'
 #[deprecated(since = "TBD", note = "literally never")]
-#[stable(feature = "deprecated-future-staged-api", since = "1.0.0")]
+#[stable(feature = "deprecated_future_staged_api", since = "1.0.0")]
 pub struct S2;
diff --git a/tests/rustdoc/implementor-stable-version.rs b/tests/rustdoc/implementor-stable-version.rs
index a1f3fd5a8c5..9c5b9b7e303 100644
--- a/tests/rustdoc/implementor-stable-version.rs
+++ b/tests/rustdoc/implementor-stable-version.rs
@@ -1,21 +1,21 @@
-#![stable(feature = "bar", since = "OLD 1.0")]
+#![stable(feature = "bar", since = "3.3.3")]
 #![crate_name = "foo"]
 
 #![feature(staged_api)]
 
-#[stable(feature = "bar", since = "OLD 1.0")]
+#[stable(feature = "bar", since = "3.3.3")]
 pub trait Bar {}
 
-#[stable(feature = "baz", since = "OLD 1.0")]
+#[stable(feature = "baz", since = "3.3.3")]
 pub trait Baz {}
 
-#[stable(feature = "baz", since = "OLD 1.0")]
+#[stable(feature = "baz", since = "3.3.3")]
 pub struct Foo;
 
-// @has foo/trait.Bar.html '//div[@id="implementors-list"]//span[@class="since"]' 'NEW 2.0'
-#[stable(feature = "foobar", since = "NEW 2.0")]
+// @has foo/trait.Bar.html '//div[@id="implementors-list"]//span[@class="since"]' '4.4.4'
+#[stable(feature = "foobar", since = "4.4.4")]
 impl Bar for Foo {}
 
-// @!has foo/trait.Baz.html '//div[@id="implementors-list"]//span[@class="since"]' 'OLD 1.0'
-#[stable(feature = "foobaz", since = "OLD 1.0")]
+// @!has foo/trait.Baz.html '//div[@id="implementors-list"]//span[@class="since"]' '3.3.3'
+#[stable(feature = "foobaz", since = "3.3.3")]
 impl Baz for Foo {}
diff --git a/tests/ui-fulldeps/stable-mir/check_instance.rs b/tests/ui-fulldeps/stable-mir/check_instance.rs
index c6a9e08ed02..ee82bc77aed 100644
--- a/tests/ui-fulldeps/stable-mir/check_instance.rs
+++ b/tests/ui-fulldeps/stable-mir/check_instance.rs
@@ -1,5 +1,5 @@
 // run-pass
-// Test that users are able to use stable mir APIs to retrieve monomorphized instances
+//! Test that users are able to use stable mir APIs to retrieve monomorphized instances
 
 // ignore-stage1
 // ignore-cross-compile
@@ -14,15 +14,15 @@
 extern crate rustc_middle;
 #[macro_use]
 extern crate rustc_smir;
-extern crate stable_mir;
 extern crate rustc_driver;
 extern crate rustc_interface;
+extern crate stable_mir;
 
-use rustc_middle::ty::TyCtxt;
 use mir::{mono::Instance, TerminatorKind::*};
-use stable_mir::ty::{TyKind, RigidTy};
-use stable_mir::*;
+use rustc_middle::ty::TyCtxt;
 use rustc_smir::rustc_internal;
+use stable_mir::ty::{RigidTy, TyKind};
+use stable_mir::*;
 use std::io::Write;
 use std::ops::ControlFlow;
 
@@ -33,16 +33,16 @@ fn test_stable_mir(_tcx: TyCtxt<'_>) -> ControlFlow<()> {
     let items = stable_mir::all_local_items();
 
     // Get all items and split generic vs monomorphic items.
-    let (generic, mono) : (Vec<_>, Vec<_>) = items.into_iter().partition(|item| {
-        item.requires_monomorphization()
-    });
+    let (generic, mono): (Vec<_>, Vec<_>) =
+        items.into_iter().partition(|item| item.requires_monomorphization());
     assert_eq!(mono.len(), 3, "Expected 2 mono functions and one constant");
     assert_eq!(generic.len(), 2, "Expected 2 generic functions");
 
     // For all monomorphic items, get the correspondent instances.
-    let instances = mono.iter().filter_map(|item| {
-        mir::mono::Instance::try_from(*item).ok()
-    }).collect::<Vec<mir::mono::Instance>>();
+    let instances = mono
+        .iter()
+        .filter_map(|item| mir::mono::Instance::try_from(*item).ok())
+        .collect::<Vec<mir::mono::Instance>>();
     assert_eq!(instances.len(), mono.len());
 
     // For all generic items, try_from should fail.
@@ -58,19 +58,22 @@ fn test_stable_mir(_tcx: TyCtxt<'_>) -> ControlFlow<()> {
 fn test_body(body: mir::Body) {
     for term in body.blocks.iter().map(|bb| &bb.terminator) {
         match &term.kind {
-            Call{ func, .. } => {
+            Call { func, .. } => {
                 let TyKind::RigidTy(ty) = func.ty(&body.locals).kind() else { unreachable!() };
                 let RigidTy::FnDef(def, args) = ty else { unreachable!() };
                 let result = Instance::resolve(def, &args);
                 assert!(result.is_ok());
             }
-            Goto {..} | Assert{..} | SwitchInt{..} | Return | Drop {..} => { /* Do nothing */}
-            _ => { unreachable!("Unexpected terminator {term:?}") }
+            Goto { .. } | Assert { .. } | SwitchInt { .. } | Return | Drop { .. } => {
+                /* Do nothing */
+            }
+            _ => {
+                unreachable!("Unexpected terminator {term:?}")
+            }
         }
     }
 }
 
-
 /// This test will generate and analyze a dummy crate using the stable mir.
 /// For that, it will first write the dummy crate into a file.
 /// Then it will create a `StableMir` using custom arguments and then
diff --git a/tests/ui-fulldeps/stable-mir/smir_internal.rs b/tests/ui-fulldeps/stable-mir/smir_internal.rs
new file mode 100644
index 00000000000..5ad05559cb4
--- /dev/null
+++ b/tests/ui-fulldeps/stable-mir/smir_internal.rs
@@ -0,0 +1,64 @@
+// run-pass
+//! Test that users are able to use retrieve internal constructs from stable ones to help with
+//! the migration.
+
+// ignore-stage1
+// ignore-cross-compile
+// ignore-remote
+// ignore-windows-gnu mingw has troubles with linking https://github.com/rust-lang/rust/pull/116837
+// edition: 2021
+
+#![feature(rustc_private)]
+#![feature(assert_matches)]
+#![feature(control_flow_enum)]
+
+#[macro_use]
+extern crate rustc_smir;
+extern crate rustc_driver;
+extern crate rustc_interface;
+extern crate rustc_middle;
+extern crate stable_mir;
+
+use rustc_middle::ty::TyCtxt;
+use rustc_smir::rustc_internal;
+use std::io::Write;
+use std::ops::ControlFlow;
+
+const CRATE_NAME: &str = "input";
+
+fn test_translation(_tcx: TyCtxt<'_>) -> ControlFlow<()> {
+    let main_fn = stable_mir::entry_fn().unwrap();
+    let body = main_fn.body();
+    let orig_ty = body.locals[0].ty;
+    let rustc_ty = rustc_internal::internal(&orig_ty);
+    assert!(rustc_ty.is_unit());
+    ControlFlow::Continue(())
+}
+
+/// This test will generate and analyze a dummy crate using the stable mir.
+/// For that, it will first write the dummy crate into a file.
+/// Then it will create a `StableMir` using custom arguments and then
+/// it will run the compiler.
+fn main() {
+    let path = "internal_input.rs";
+    generate_input(&path).unwrap();
+    let args = vec![
+        "rustc".to_string(),
+        "--crate-name".to_string(),
+        CRATE_NAME.to_string(),
+        path.to_string(),
+    ];
+    run!(args, tcx, test_translation(tcx)).unwrap();
+}
+
+fn generate_input(path: &str) -> std::io::Result<()> {
+    let mut file = std::fs::File::create(path)?;
+    write!(
+        file,
+        r#"
+    pub fn main() {{
+    }}
+    "#
+    )?;
+    Ok(())
+}
diff --git a/tests/ui/abi/compatibility.rs b/tests/ui/abi/compatibility.rs
index 1f049b1785a..0cdf229711a 100644
--- a/tests/ui/abi/compatibility.rs
+++ b/tests/ui/abi/compatibility.rs
@@ -30,6 +30,7 @@
 // revisions: loongarch64
 //[loongarch64] compile-flags: --target loongarch64-unknown-linux-gnu
 //[loongarch64] needs-llvm-components: loongarch
+//[loongarch64] min-llvm-version: 17
 // revisions: wasm
 //[wasm] compile-flags: --target wasm32-unknown-unknown
 //[wasm] needs-llvm-components: webassembly
diff --git a/tests/ui/async-await/async-unsafe-fn-call-in-safe.mir.stderr b/tests/ui/async-await/async-unsafe-fn-call-in-safe.mir.stderr
index 2114fb59ba3..f9e5bf675cb 100644
--- a/tests/ui/async-await/async-unsafe-fn-call-in-safe.mir.stderr
+++ b/tests/ui/async-await/async-unsafe-fn-call-in-safe.mir.stderr
@@ -23,7 +23,7 @@ LL |     S::f();
    = note: consult the function's documentation for information on how to avoid undefined behavior
 
 error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
-  --> $DIR/async-unsafe-fn-call-in-safe.rs:24:5
+  --> $DIR/async-unsafe-fn-call-in-safe.rs:26:5
    |
 LL |     f();
    |     ^^^ call to unsafe function
diff --git a/tests/ui/async-await/async-unsafe-fn-call-in-safe.rs b/tests/ui/async-await/async-unsafe-fn-call-in-safe.rs
index c941dc27aa3..14cc0dc614f 100644
--- a/tests/ui/async-await/async-unsafe-fn-call-in-safe.rs
+++ b/tests/ui/async-await/async-unsafe-fn-call-in-safe.rs
@@ -20,6 +20,10 @@ async fn g() {
 }
 
 fn main() {
-    S::f(); //[mir]~ ERROR call to unsafe function is unsafe
-    f(); //[mir]~ ERROR call to unsafe function is unsafe
+    S::f();
+    //[mir]~^ ERROR call to unsafe function is unsafe
+    //[thir]~^^ ERROR call to unsafe function `S::f` is unsafe
+    f();
+    //[mir]~^ ERROR call to unsafe function is unsafe
+    //[thir]~^^ ERROR call to unsafe function `f` is unsafe
 }
diff --git a/tests/ui/async-await/async-unsafe-fn-call-in-safe.thir.stderr b/tests/ui/async-await/async-unsafe-fn-call-in-safe.thir.stderr
index 68d97d3fd7d..ba3303fe793 100644
--- a/tests/ui/async-await/async-unsafe-fn-call-in-safe.thir.stderr
+++ b/tests/ui/async-await/async-unsafe-fn-call-in-safe.thir.stderr
@@ -14,6 +14,22 @@ LL |     f();
    |
    = note: consult the function's documentation for information on how to avoid undefined behavior
 
-error: aborting due to 2 previous errors
+error[E0133]: call to unsafe function `S::f` is unsafe and requires unsafe function or block
+  --> $DIR/async-unsafe-fn-call-in-safe.rs:23:5
+   |
+LL |     S::f();
+   |     ^^^^^^ call to unsafe function
+   |
+   = note: consult the function's documentation for information on how to avoid undefined behavior
+
+error[E0133]: call to unsafe function `f` is unsafe and requires unsafe function or block
+  --> $DIR/async-unsafe-fn-call-in-safe.rs:26:5
+   |
+LL |     f();
+   |     ^^^ call to unsafe function
+   |
+   = note: consult the function's documentation for information on how to avoid undefined behavior
+
+error: aborting due to 4 previous errors
 
 For more information about this error, try `rustc --explain E0133`.
diff --git a/tests/ui/async-await/in-trait/async-example-desugared-boxed-in-trait.rs b/tests/ui/async-await/in-trait/async-example-desugared-boxed-in-trait.rs
index 3cc11d241f7..c26f6625f00 100644
--- a/tests/ui/async-await/in-trait/async-example-desugared-boxed-in-trait.rs
+++ b/tests/ui/async-await/in-trait/async-example-desugared-boxed-in-trait.rs
@@ -1,7 +1,5 @@
 // edition: 2021
 
-#![allow(incomplete_features)]
-
 use std::future::Future;
 use std::pin::Pin;
 
diff --git a/tests/ui/async-await/in-trait/async-example-desugared-boxed-in-trait.stderr b/tests/ui/async-await/in-trait/async-example-desugared-boxed-in-trait.stderr
index e6dd83b6b0a..b70b36adb4a 100644
--- a/tests/ui/async-await/in-trait/async-example-desugared-boxed-in-trait.stderr
+++ b/tests/ui/async-await/in-trait/async-example-desugared-boxed-in-trait.stderr
@@ -1,11 +1,11 @@
 error[E0053]: method `foo` has an incompatible type for trait
-  --> $DIR/async-example-desugared-boxed-in-trait.rs:13:5
+  --> $DIR/async-example-desugared-boxed-in-trait.rs:11:5
    |
 LL |     async fn foo(&self) -> i32 {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Pin<Box<dyn Future<Output = i32>>>`, found future
    |
 note: type in trait
-  --> $DIR/async-example-desugared-boxed-in-trait.rs:9:22
+  --> $DIR/async-example-desugared-boxed-in-trait.rs:7:22
    |
 LL |     fn foo(&self) -> Pin<Box<dyn Future<Output = i32> + '_>>;
    |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/async-await/in-trait/async-example-desugared-boxed.rs b/tests/ui/async-await/in-trait/async-example-desugared-boxed.rs
index 81d25ce27ae..c5a9841029e 100644
--- a/tests/ui/async-await/in-trait/async-example-desugared-boxed.rs
+++ b/tests/ui/async-await/in-trait/async-example-desugared-boxed.rs
@@ -1,7 +1,5 @@
 // edition: 2021
 
-#![allow(incomplete_features)]
-
 use std::future::Future;
 use std::pin::Pin;
 
diff --git a/tests/ui/async-await/in-trait/async-example-desugared-boxed.stderr b/tests/ui/async-await/in-trait/async-example-desugared-boxed.stderr
index cd18790fdfb..6392ce86e4a 100644
--- a/tests/ui/async-await/in-trait/async-example-desugared-boxed.stderr
+++ b/tests/ui/async-await/in-trait/async-example-desugared-boxed.stderr
@@ -1,5 +1,5 @@
 error: method `foo` should be async because the method from the trait is async
-  --> $DIR/async-example-desugared-boxed.rs:13:5
+  --> $DIR/async-example-desugared-boxed.rs:11:5
    |
 LL |     async fn foo(&self) -> i32;
    |     --------------------------- required because the trait method is async
diff --git a/tests/ui/async-await/in-trait/async-example-desugared-extra.rs b/tests/ui/async-await/in-trait/async-example-desugared-extra.rs
index f0c59180fb5..ce93bd62608 100644
--- a/tests/ui/async-await/in-trait/async-example-desugared-extra.rs
+++ b/tests/ui/async-await/in-trait/async-example-desugared-extra.rs
@@ -2,7 +2,6 @@
 // edition: 2021
 
 #![feature(lint_reasons)]
-#![allow(incomplete_features)]
 
 use std::future::Future;
 use std::pin::Pin;
diff --git a/tests/ui/async-await/in-trait/async-example-desugared-in-trait.rs b/tests/ui/async-await/in-trait/async-example-desugared-in-trait.rs
index deca28af853..f7a351efff5 100644
--- a/tests/ui/async-await/in-trait/async-example-desugared-in-trait.rs
+++ b/tests/ui/async-await/in-trait/async-example-desugared-in-trait.rs
@@ -1,8 +1,6 @@
 // check-pass
 // edition: 2021
 
-#![allow(incomplete_features)]
-
 use std::future::Future;
 
 trait MyTrait {
diff --git a/tests/ui/async-await/in-trait/async-example-desugared-manual.rs b/tests/ui/async-await/in-trait/async-example-desugared-manual.rs
index fdba4d93c77..c287b9a5b84 100644
--- a/tests/ui/async-await/in-trait/async-example-desugared-manual.rs
+++ b/tests/ui/async-await/in-trait/async-example-desugared-manual.rs
@@ -1,7 +1,5 @@
 // edition: 2021
 
-#![allow(incomplete_features)]
-
 use std::future::Future;
 use std::task::Poll;
 
diff --git a/tests/ui/async-await/in-trait/async-example-desugared-manual.stderr b/tests/ui/async-await/in-trait/async-example-desugared-manual.stderr
index 463892f21bf..1eda6fe6532 100644
--- a/tests/ui/async-await/in-trait/async-example-desugared-manual.stderr
+++ b/tests/ui/async-await/in-trait/async-example-desugared-manual.stderr
@@ -1,5 +1,5 @@
 error: method `foo` should be async because the method from the trait is async
-  --> $DIR/async-example-desugared-manual.rs:21:5
+  --> $DIR/async-example-desugared-manual.rs:19:5
    |
 LL |     async fn foo(&self) -> i32;
    |     --------------------------- required because the trait method is async
diff --git a/tests/ui/async-await/in-trait/async-example-desugared.rs b/tests/ui/async-await/in-trait/async-example-desugared.rs
index 7fc78f7da6d..78904d87abc 100644
--- a/tests/ui/async-await/in-trait/async-example-desugared.rs
+++ b/tests/ui/async-await/in-trait/async-example-desugared.rs
@@ -1,8 +1,6 @@
 // check-pass
 // edition: 2021
 
-#![allow(incomplete_features)]
-
 use std::future::Future;
 
 trait MyTrait {
diff --git a/tests/ui/async-await/in-trait/async-example.rs b/tests/ui/async-await/in-trait/async-example.rs
index 62ed490bf05..a32f979df6b 100644
--- a/tests/ui/async-await/in-trait/async-example.rs
+++ b/tests/ui/async-await/in-trait/async-example.rs
@@ -1,8 +1,6 @@
 // check-pass
 // edition: 2021
 
-#![allow(incomplete_features)]
-
 trait MyTrait {
     #[allow(async_fn_in_trait)]
     async fn foo(&self) -> i32;
diff --git a/tests/ui/async-await/in-trait/async-generics-and-bounds.rs b/tests/ui/async-await/in-trait/async-generics-and-bounds.rs
index 4e859fb27a9..8dc0574c757 100644
--- a/tests/ui/async-await/in-trait/async-generics-and-bounds.rs
+++ b/tests/ui/async-await/in-trait/async-generics-and-bounds.rs
@@ -2,8 +2,6 @@
 // known-bug: #102682
 // edition: 2021
 
-#![allow(incomplete_features)]
-
 use std::fmt::Debug;
 use std::hash::Hash;
 
diff --git a/tests/ui/async-await/in-trait/async-generics-and-bounds.stderr b/tests/ui/async-await/in-trait/async-generics-and-bounds.stderr
index d7251a52863..3cc35b21409 100644
--- a/tests/ui/async-await/in-trait/async-generics-and-bounds.stderr
+++ b/tests/ui/async-await/in-trait/async-generics-and-bounds.stderr
@@ -1,5 +1,5 @@
 error[E0311]: the parameter type `U` may not live long enough
-  --> $DIR/async-generics-and-bounds.rs:11:5
+  --> $DIR/async-generics-and-bounds.rs:9:5
    |
 LL |     async fn foo(&self) -> &(T, U) where T: Debug + Sized, U: Hash;
    |     ^^^^^^^^^^^^^-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -13,7 +13,7 @@ LL |     async fn foo<'a>(&'a self) -> &'a (T, U) where T: Debug + Sized, U: Has
    |                 ++++  ++           ++                                       +++++++
 
 error[E0311]: the parameter type `T` may not live long enough
-  --> $DIR/async-generics-and-bounds.rs:11:5
+  --> $DIR/async-generics-and-bounds.rs:9:5
    |
 LL |     async fn foo(&self) -> &(T, U) where T: Debug + Sized, U: Hash;
    |     ^^^^^^^^^^^^^-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/async-await/in-trait/async-generics.rs b/tests/ui/async-await/in-trait/async-generics.rs
index 2d342592848..6004916a4e5 100644
--- a/tests/ui/async-await/in-trait/async-generics.rs
+++ b/tests/ui/async-await/in-trait/async-generics.rs
@@ -2,8 +2,6 @@
 // known-bug: #102682
 // edition: 2021
 
-#![allow(incomplete_features)]
-
 trait MyTrait<T, U> {
     async fn foo(&self) -> &(T, U);
 }
diff --git a/tests/ui/async-await/in-trait/async-generics.stderr b/tests/ui/async-await/in-trait/async-generics.stderr
index aec62d12201..3b27f8fe2f0 100644
--- a/tests/ui/async-await/in-trait/async-generics.stderr
+++ b/tests/ui/async-await/in-trait/async-generics.stderr
@@ -1,5 +1,5 @@
 error[E0311]: the parameter type `U` may not live long enough
-  --> $DIR/async-generics.rs:8:5
+  --> $DIR/async-generics.rs:6:5
    |
 LL |     async fn foo(&self) -> &(T, U);
    |     ^^^^^^^^^^^^^-^^^^^^^^^^^^^^^^^
@@ -13,7 +13,7 @@ LL |     async fn foo<'a>(&'a self) -> &'a (T, U) where U: 'a;
    |                 ++++  ++           ++        +++++++++++
 
 error[E0311]: the parameter type `T` may not live long enough
-  --> $DIR/async-generics.rs:8:5
+  --> $DIR/async-generics.rs:6:5
    |
 LL |     async fn foo(&self) -> &(T, U);
    |     ^^^^^^^^^^^^^-^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/async-await/in-trait/async-lifetimes-and-bounds.rs b/tests/ui/async-await/in-trait/async-lifetimes-and-bounds.rs
index ea8330a4b52..3721b01350d 100644
--- a/tests/ui/async-await/in-trait/async-lifetimes-and-bounds.rs
+++ b/tests/ui/async-await/in-trait/async-lifetimes-and-bounds.rs
@@ -1,8 +1,6 @@
 // check-pass
 // edition: 2021
 
-#![allow(incomplete_features)]
-
 use std::fmt::Debug;
 
 trait MyTrait<'a, 'b, T> {
diff --git a/tests/ui/async-await/in-trait/async-lifetimes.rs b/tests/ui/async-await/in-trait/async-lifetimes.rs
index 6e573b9cc8b..cb4b871cbe1 100644
--- a/tests/ui/async-await/in-trait/async-lifetimes.rs
+++ b/tests/ui/async-await/in-trait/async-lifetimes.rs
@@ -1,8 +1,6 @@
 // check-pass
 // edition: 2021
 
-#![allow(incomplete_features)]
-
 trait MyTrait<'a, 'b, T> {
     #[allow(async_fn_in_trait)]
     async fn foo(&'a self, key: &'b T) -> (&'a Self, &'b T);
diff --git a/tests/ui/async-await/in-trait/async-recursive-generic.rs b/tests/ui/async-await/in-trait/async-recursive-generic.rs
index 34f1b09756e..c6031ce28d1 100644
--- a/tests/ui/async-await/in-trait/async-recursive-generic.rs
+++ b/tests/ui/async-await/in-trait/async-recursive-generic.rs
@@ -1,7 +1,5 @@
 // edition: 2021
 
-#![allow(incomplete_features)]
-
 trait MyTrait<T> {
     async fn foo_recursive(&self, n: usize) -> T;
 }
diff --git a/tests/ui/async-await/in-trait/async-recursive-generic.stderr b/tests/ui/async-await/in-trait/async-recursive-generic.stderr
index 7c2df6683f0..cf0bcd741fc 100644
--- a/tests/ui/async-await/in-trait/async-recursive-generic.stderr
+++ b/tests/ui/async-await/in-trait/async-recursive-generic.stderr
@@ -1,5 +1,5 @@
 error[E0733]: recursion in an `async fn` requires boxing
-  --> $DIR/async-recursive-generic.rs:10:5
+  --> $DIR/async-recursive-generic.rs:8:5
    |
 LL |     async fn foo_recursive(&self, n: usize) -> T {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ recursive `async fn`
diff --git a/tests/ui/async-await/in-trait/async-recursive.rs b/tests/ui/async-await/in-trait/async-recursive.rs
index ddf119b252f..09f1ffe499e 100644
--- a/tests/ui/async-await/in-trait/async-recursive.rs
+++ b/tests/ui/async-await/in-trait/async-recursive.rs
@@ -1,7 +1,5 @@
 // edition: 2021
 
-#![allow(incomplete_features)]
-
 trait MyTrait {
     async fn foo_recursive(&self, n: usize) -> i32;
 }
diff --git a/tests/ui/async-await/in-trait/async-recursive.stderr b/tests/ui/async-await/in-trait/async-recursive.stderr
index 1253252cc40..b959652ea16 100644
--- a/tests/ui/async-await/in-trait/async-recursive.stderr
+++ b/tests/ui/async-await/in-trait/async-recursive.stderr
@@ -1,5 +1,5 @@
 error[E0733]: recursion in an `async fn` requires boxing
-  --> $DIR/async-recursive.rs:10:5
+  --> $DIR/async-recursive.rs:8:5
    |
 LL |     async fn foo_recursive(&self, n: usize) -> i32 {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ recursive `async fn`
diff --git a/tests/ui/async-await/in-trait/early-bound-1.rs b/tests/ui/async-await/in-trait/early-bound-1.rs
index f79d6f23c93..ddcb477a1dc 100644
--- a/tests/ui/async-await/in-trait/early-bound-1.rs
+++ b/tests/ui/async-await/in-trait/early-bound-1.rs
@@ -1,8 +1,6 @@
 // check-pass
 // edition:2021
 
-#![allow(incomplete_features)]
-
 pub trait Foo {
     #[allow(async_fn_in_trait)]
     async fn foo(&mut self);
diff --git a/tests/ui/attributes/const-stability-on-macro.rs b/tests/ui/attributes/const-stability-on-macro.rs
index 412af195d7a..af268ccd536 100644
--- a/tests/ui/attributes/const-stability-on-macro.rs
+++ b/tests/ui/attributes/const-stability-on-macro.rs
@@ -1,7 +1,7 @@
 #![feature(staged_api)]
 #![stable(feature = "rust1", since = "1.0.0")]
 
-#[rustc_const_stable(feature = "foo", since = "0")]
+#[rustc_const_stable(feature = "foo", since = "3.3.3")]
 //~^ ERROR macros cannot have const stability attributes
 macro_rules! foo {
     () => {};
diff --git a/tests/ui/attributes/const-stability-on-macro.stderr b/tests/ui/attributes/const-stability-on-macro.stderr
index c3da02c79cb..28f31e3d4f6 100644
--- a/tests/ui/attributes/const-stability-on-macro.stderr
+++ b/tests/ui/attributes/const-stability-on-macro.stderr
@@ -1,8 +1,8 @@
 error: macros cannot have const stability attributes
   --> $DIR/const-stability-on-macro.rs:4:1
    |
-LL | #[rustc_const_stable(feature = "foo", since = "0")]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid const stability attribute
+LL | #[rustc_const_stable(feature = "foo", since = "3.3.3")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid const stability attribute
 LL |
 LL | macro_rules! foo {
    | ---------------- const stability attribute affects this macro
diff --git a/tests/ui/attributes/statement-attribute-validation.rs b/tests/ui/attributes/statement-attribute-validation.rs
new file mode 100644
index 00000000000..31407364acf
--- /dev/null
+++ b/tests/ui/attributes/statement-attribute-validation.rs
@@ -0,0 +1,39 @@
+// test for #117058 - check that attributes are validated on various kinds of statements.
+
+struct A;
+
+fn func() {}
+
+fn main() {
+    #[allow(two-words)]
+    //~^ ERROR expected one of `(`, `,`, `::`, or `=`, found `-`
+    if true {
+    } else {
+    }
+    #[allow(two-words)]
+    //~^ ERROR expected one of `(`, `,`, `::`, or `=`, found `-`
+    (1);
+    #[allow(two-words)]
+    //~^ ERROR expected one of `(`, `,`, `::`, or `=`, found `-`
+    match 1 {
+        _ => {}
+    }
+    #[allow(two-words)]
+    //~^ ERROR expected one of `(`, `,`, `::`, or `=`, found `-`
+    while false {}
+    #[allow(two-words)]
+    //~^ ERROR expected one of `(`, `,`, `::`, or `=`, found `-`
+    {}
+    #[allow(two-words)]
+    //~^ ERROR expected one of `(`, `,`, `::`, or `=`, found `-`
+    A {};
+    #[allow(two-words)]
+    //~^ ERROR expected one of `(`, `,`, `::`, or `=`, found `-`
+    func();
+    #[allow(two-words)]
+    //~^ ERROR expected one of `(`, `,`, `::`, or `=`, found `-`
+    A;
+    #[allow(two-words)]
+    //~^ ERROR expected one of `(`, `,`, `::`, or `=`, found `-`
+    loop {}
+}
diff --git a/tests/ui/attributes/statement-attribute-validation.stderr b/tests/ui/attributes/statement-attribute-validation.stderr
new file mode 100644
index 00000000000..06f447be562
--- /dev/null
+++ b/tests/ui/attributes/statement-attribute-validation.stderr
@@ -0,0 +1,56 @@
+error: expected one of `(`, `,`, `::`, or `=`, found `-`
+  --> $DIR/statement-attribute-validation.rs:8:16
+   |
+LL |     #[allow(two-words)]
+   |                ^ expected one of `(`, `,`, `::`, or `=`
+
+error: expected one of `(`, `,`, `::`, or `=`, found `-`
+  --> $DIR/statement-attribute-validation.rs:13:16
+   |
+LL |     #[allow(two-words)]
+   |                ^ expected one of `(`, `,`, `::`, or `=`
+
+error: expected one of `(`, `,`, `::`, or `=`, found `-`
+  --> $DIR/statement-attribute-validation.rs:16:16
+   |
+LL |     #[allow(two-words)]
+   |                ^ expected one of `(`, `,`, `::`, or `=`
+
+error: expected one of `(`, `,`, `::`, or `=`, found `-`
+  --> $DIR/statement-attribute-validation.rs:21:16
+   |
+LL |     #[allow(two-words)]
+   |                ^ expected one of `(`, `,`, `::`, or `=`
+
+error: expected one of `(`, `,`, `::`, or `=`, found `-`
+  --> $DIR/statement-attribute-validation.rs:24:16
+   |
+LL |     #[allow(two-words)]
+   |                ^ expected one of `(`, `,`, `::`, or `=`
+
+error: expected one of `(`, `,`, `::`, or `=`, found `-`
+  --> $DIR/statement-attribute-validation.rs:27:16
+   |
+LL |     #[allow(two-words)]
+   |                ^ expected one of `(`, `,`, `::`, or `=`
+
+error: expected one of `(`, `,`, `::`, or `=`, found `-`
+  --> $DIR/statement-attribute-validation.rs:30:16
+   |
+LL |     #[allow(two-words)]
+   |                ^ expected one of `(`, `,`, `::`, or `=`
+
+error: expected one of `(`, `,`, `::`, or `=`, found `-`
+  --> $DIR/statement-attribute-validation.rs:33:16
+   |
+LL |     #[allow(two-words)]
+   |                ^ expected one of `(`, `,`, `::`, or `=`
+
+error: expected one of `(`, `,`, `::`, or `=`, found `-`
+  --> $DIR/statement-attribute-validation.rs:36:16
+   |
+LL |     #[allow(two-words)]
+   |                ^ expected one of `(`, `,`, `::`, or `=`
+
+error: aborting due to 9 previous errors
+
diff --git a/tests/ui/const-generics/defaults/default-annotation.rs b/tests/ui/const-generics/defaults/default-annotation.rs
index 7a9f5732f7f..587ad78e298 100644
--- a/tests/ui/const-generics/defaults/default-annotation.rs
+++ b/tests/ui/const-generics/defaults/default-annotation.rs
@@ -4,12 +4,12 @@
 // FIXME(const_generics_defaults): It seems like we aren't testing the right thing here,
 // I would assume that we want the attributes to apply to the const parameter defaults
 // themselves.
-#![stable(feature = "const_default_test", since="none")]
+#![stable(feature = "const_default_test", since = "3.3.3")]
 
-#[unstable(feature = "const_default_stable", issue="none")]
+#[unstable(feature = "const_default_stable", issue = "none")]
 pub struct ConstDefaultUnstable<const N: usize = 3>;
 
-#[stable(feature = "const_default_unstable", since="none")]
+#[stable(feature = "const_default_unstable", since = "3.3.3")]
 pub struct ConstDefaultStable<const N: usize = {
     3
 }>;
diff --git a/tests/ui/consts/const-extern-fn/const-extern-fn-requires-unsafe.rs b/tests/ui/consts/const-extern-fn/const-extern-fn-requires-unsafe.rs
index afe645ae881..6c4f0a5accf 100644
--- a/tests/ui/consts/const-extern-fn/const-extern-fn-requires-unsafe.rs
+++ b/tests/ui/consts/const-extern-fn/const-extern-fn-requires-unsafe.rs
@@ -11,4 +11,5 @@ fn main() {
     //[thir]~^^ call to unsafe function `foo` is unsafe and requires unsafe function or block
     foo();
     //[mir]~^ ERROR call to unsafe function is unsafe and requires unsafe function or block
+    //[thir]~^^ ERROR call to unsafe function `foo` is unsafe and requires unsafe function or block
 }
diff --git a/tests/ui/consts/const-extern-fn/const-extern-fn-requires-unsafe.thir.stderr b/tests/ui/consts/const-extern-fn/const-extern-fn-requires-unsafe.thir.stderr
index b313f06539f..e6b8173eb05 100644
--- a/tests/ui/consts/const-extern-fn/const-extern-fn-requires-unsafe.thir.stderr
+++ b/tests/ui/consts/const-extern-fn/const-extern-fn-requires-unsafe.thir.stderr
@@ -1,3 +1,11 @@
+error[E0133]: call to unsafe function `foo` is unsafe and requires unsafe function or block
+  --> $DIR/const-extern-fn-requires-unsafe.rs:12:5
+   |
+LL |     foo();
+   |     ^^^^^ call to unsafe function
+   |
+   = note: consult the function's documentation for information on how to avoid undefined behavior
+
 error[E0133]: call to unsafe function `foo` is unsafe and requires unsafe function or block
   --> $DIR/const-extern-fn-requires-unsafe.rs:9:17
    |
@@ -6,6 +14,6 @@ LL |     let a: [u8; foo()];
    |
    = note: consult the function's documentation for information on how to avoid undefined behavior
 
-error: aborting due to previous error
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0133`.
diff --git a/tests/ui/deprecation/staged-deprecation-in-future.rs b/tests/ui/deprecation/staged-deprecation-in-future.rs
index 87b15ec303c..49ee60b9bd0 100644
--- a/tests/ui/deprecation/staged-deprecation-in-future.rs
+++ b/tests/ui/deprecation/staged-deprecation-in-future.rs
@@ -2,14 +2,14 @@
 
 #![feature(staged_api)]
 
-#![stable(feature = "rustc_deprecation-in-future-test", since = "1.0.0")]
+#![stable(feature = "rustc_deprecation_in_future_test", since = "1.0.0")]
 
 #[deprecated(since = "99.99.99", note = "effectively never")]
-#[stable(feature = "rustc_deprecation-in-future-test", since = "1.0.0")]
+#[stable(feature = "rustc_deprecation_in_future_test", since = "1.0.0")]
 pub struct S1;
 
 #[deprecated(since = "TBD", note = "literally never")]
-#[stable(feature = "rustc_deprecation-in-future-test", since = "1.0.0")]
+#[stable(feature = "rustc_deprecation_in_future_test", since = "1.0.0")]
 pub struct S2;
 
 fn main() {
diff --git a/tests/ui/feature-gates/feature-gate-staged_api.rs b/tests/ui/feature-gates/feature-gate-staged_api.rs
index 2571ab5d1b4..ce6b218dd7d 100644
--- a/tests/ui/feature-gates/feature-gate-staged_api.rs
+++ b/tests/ui/feature-gates/feature-gate-staged_api.rs
@@ -1,11 +1,11 @@
-#![stable(feature = "a", since = "b")]
+#![stable(feature = "a", since = "3.3.3")]
 //~^ ERROR stability attributes may not be used outside of the standard library
 mod inner_private_module {
     // UnnameableTypeAlias isn't marked as reachable, so no stability annotation is required here
     pub type UnnameableTypeAlias = u8;
 }
 
-#[stable(feature = "a", since = "b")]
+#[stable(feature = "a", since = "3.3.3")]
 //~^ ERROR stability attributes may not be used outside of the standard library
 pub fn f() -> inner_private_module::UnnameableTypeAlias {
     0
diff --git a/tests/ui/feature-gates/feature-gate-staged_api.stderr b/tests/ui/feature-gates/feature-gate-staged_api.stderr
index 951bb5a1740..1a9fcb02b0d 100644
--- a/tests/ui/feature-gates/feature-gate-staged_api.stderr
+++ b/tests/ui/feature-gates/feature-gate-staged_api.stderr
@@ -1,14 +1,14 @@
 error[E0734]: stability attributes may not be used outside of the standard library
   --> $DIR/feature-gate-staged_api.rs:8:1
    |
-LL | #[stable(feature = "a", since = "b")]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | #[stable(feature = "a", since = "3.3.3")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0734]: stability attributes may not be used outside of the standard library
   --> $DIR/feature-gate-staged_api.rs:1:1
    |
-LL | #![stable(feature = "a", since = "b")]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | #![stable(feature = "a", since = "3.3.3")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/impl-trait/erased-regions-in-hidden-ty.current.stderr b/tests/ui/impl-trait/erased-regions-in-hidden-ty.current.stderr
new file mode 100644
index 00000000000..84b61dc5044
--- /dev/null
+++ b/tests/ui/impl-trait/erased-regions-in-hidden-ty.current.stderr
@@ -0,0 +1,14 @@
+error: {foo<ReEarlyBound(DefId(..), 0, 'a)>::{closure#0} closure_kind_ty=i8 closure_sig_as_fn_ptr_ty=extern "rust-call" fn(()) upvar_tys=()}
+  --> $DIR/erased-regions-in-hidden-ty.rs:11:36
+   |
+LL | fn foo<'a: 'a>(x: &'a Vec<i32>) -> impl Fn() + 'static {
+   |                                    ^^^^^^^^^^^^^^^^^^^
+
+error: Opaque(DefId(..), [ReErased])
+  --> $DIR/erased-regions-in-hidden-ty.rs:17:13
+   |
+LL | fn bar() -> impl Fn() + 'static {
+   |             ^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/impl-trait/erased-regions-in-hidden-ty.next.stderr b/tests/ui/impl-trait/erased-regions-in-hidden-ty.next.stderr
new file mode 100644
index 00000000000..84b61dc5044
--- /dev/null
+++ b/tests/ui/impl-trait/erased-regions-in-hidden-ty.next.stderr
@@ -0,0 +1,14 @@
+error: {foo<ReEarlyBound(DefId(..), 0, 'a)>::{closure#0} closure_kind_ty=i8 closure_sig_as_fn_ptr_ty=extern "rust-call" fn(()) upvar_tys=()}
+  --> $DIR/erased-regions-in-hidden-ty.rs:11:36
+   |
+LL | fn foo<'a: 'a>(x: &'a Vec<i32>) -> impl Fn() + 'static {
+   |                                    ^^^^^^^^^^^^^^^^^^^
+
+error: Opaque(DefId(..), [ReErased])
+  --> $DIR/erased-regions-in-hidden-ty.rs:17:13
+   |
+LL | fn bar() -> impl Fn() + 'static {
+   |             ^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/impl-trait/erased-regions-in-hidden-ty.rs b/tests/ui/impl-trait/erased-regions-in-hidden-ty.rs
new file mode 100644
index 00000000000..698123a932d
--- /dev/null
+++ b/tests/ui/impl-trait/erased-regions-in-hidden-ty.rs
@@ -0,0 +1,23 @@
+// revisions: current next
+// compile-flags: -Zverbose
+//[next] compile-flags: -Ztrait-solver=next
+// normalize-stderr-test "DefId\([^\)]+\)" -> "DefId(..)"
+
+#![feature(rustc_attrs)]
+#![rustc_hidden_type_of_opaques]
+
+// Make sure that the compiler can handle `ReErased` in the hidden type of an opaque.
+
+fn foo<'a: 'a>(x: &'a Vec<i32>) -> impl Fn() + 'static {
+//~^ ERROR 0, 'a)>::{closure#0} closure_kind_ty=i8 closure_sig_as_fn_ptr_ty=extern "rust-call" fn(()) upvar_tys=()}
+// Can't write whole type because of lack of path sanitization
+    || ()
+}
+
+fn bar() -> impl Fn() + 'static {
+//~^ ERROR , [ReErased])
+// Can't write whole type because of lack of path sanitization
+    foo(&vec![])
+}
+
+fn main() {}
diff --git a/tests/ui/impl-trait/in-trait/deep-match.rs b/tests/ui/impl-trait/in-trait/deep-match.rs
index 02889347ba4..82eac7760fc 100644
--- a/tests/ui/impl-trait/in-trait/deep-match.rs
+++ b/tests/ui/impl-trait/in-trait/deep-match.rs
@@ -1,5 +1,3 @@
-#![allow(incomplete_features)]
-
 struct Wrapper<T>(T);
 
 trait Foo {
diff --git a/tests/ui/impl-trait/in-trait/deep-match.stderr b/tests/ui/impl-trait/in-trait/deep-match.stderr
index 9cfc54f5094..a658d8fa078 100644
--- a/tests/ui/impl-trait/in-trait/deep-match.stderr
+++ b/tests/ui/impl-trait/in-trait/deep-match.stderr
@@ -1,5 +1,5 @@
 error[E0053]: method `bar` has an incompatible return type for trait
-  --> $DIR/deep-match.rs:10:17
+  --> $DIR/deep-match.rs:8:17
    |
 LL |     fn bar() -> i32 {
    |                 ^^^
diff --git a/tests/ui/impl-trait/in-trait/default-body-type-err.rs b/tests/ui/impl-trait/in-trait/default-body-type-err.rs
index 977ff8111dd..ac7a50a365e 100644
--- a/tests/ui/impl-trait/in-trait/default-body-type-err.rs
+++ b/tests/ui/impl-trait/in-trait/default-body-type-err.rs
@@ -1,5 +1,3 @@
-#![allow(incomplete_features)]
-
 use std::ops::Deref;
 
 pub trait Foo {
diff --git a/tests/ui/impl-trait/in-trait/default-body-type-err.stderr b/tests/ui/impl-trait/in-trait/default-body-type-err.stderr
index 3d9ca62b0db..596ff101155 100644
--- a/tests/ui/impl-trait/in-trait/default-body-type-err.stderr
+++ b/tests/ui/impl-trait/in-trait/default-body-type-err.stderr
@@ -1,5 +1,5 @@
 error[E0271]: type mismatch resolving `<&i32 as Deref>::Target == String`
-  --> $DIR/default-body-type-err.rs:6:22
+  --> $DIR/default-body-type-err.rs:4:22
    |
 LL |     fn lol(&self) -> impl Deref<Target = String> {
    |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `i32`, found `String`
diff --git a/tests/ui/impl-trait/in-trait/doesnt-satisfy.rs b/tests/ui/impl-trait/in-trait/doesnt-satisfy.rs
index 5a53c9a19b5..0ac60918b67 100644
--- a/tests/ui/impl-trait/in-trait/doesnt-satisfy.rs
+++ b/tests/ui/impl-trait/in-trait/doesnt-satisfy.rs
@@ -1,5 +1,3 @@
-#![allow(incomplete_features)]
-
 trait Foo {
     fn bar() -> impl std::fmt::Display;
 }
diff --git a/tests/ui/impl-trait/in-trait/doesnt-satisfy.stderr b/tests/ui/impl-trait/in-trait/doesnt-satisfy.stderr
index cb9ecc7fa48..cd45c6a9c6d 100644
--- a/tests/ui/impl-trait/in-trait/doesnt-satisfy.stderr
+++ b/tests/ui/impl-trait/in-trait/doesnt-satisfy.stderr
@@ -1,5 +1,5 @@
 error[E0277]: `()` doesn't implement `std::fmt::Display`
-  --> $DIR/doesnt-satisfy.rs:8:17
+  --> $DIR/doesnt-satisfy.rs:6:17
    |
 LL |     fn bar() -> () {}
    |                 ^^ `()` cannot be formatted with the default formatter
@@ -7,7 +7,7 @@ LL |     fn bar() -> () {}
    = help: the trait `std::fmt::Display` is not implemented for `()`
    = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
 note: required by a bound in `Foo::{opaque#0}`
-  --> $DIR/doesnt-satisfy.rs:4:22
+  --> $DIR/doesnt-satisfy.rs:2:22
    |
 LL |     fn bar() -> impl std::fmt::Display;
    |                      ^^^^^^^^^^^^^^^^^ required by this bound in `Foo::{opaque#0}`
diff --git a/tests/ui/impl-trait/in-trait/generics-mismatch.rs b/tests/ui/impl-trait/in-trait/generics-mismatch.rs
index 2e5373dbd5d..3ea31cc9347 100644
--- a/tests/ui/impl-trait/in-trait/generics-mismatch.rs
+++ b/tests/ui/impl-trait/in-trait/generics-mismatch.rs
@@ -1,5 +1,3 @@
-#![allow(incomplete_features)]
-
 struct U;
 
 trait Foo {
diff --git a/tests/ui/impl-trait/in-trait/generics-mismatch.stderr b/tests/ui/impl-trait/in-trait/generics-mismatch.stderr
index 3dbf2235c5e..043dbc8db5d 100644
--- a/tests/ui/impl-trait/in-trait/generics-mismatch.stderr
+++ b/tests/ui/impl-trait/in-trait/generics-mismatch.stderr
@@ -1,5 +1,5 @@
 error[E0049]: method `bar` has 1 type parameter but its trait declaration has 0 type parameters
-  --> $DIR/generics-mismatch.rs:10:12
+  --> $DIR/generics-mismatch.rs:8:12
    |
 LL |     fn bar(&self) -> impl Sized;
    |           - expected 0 type parameters
diff --git a/tests/ui/impl-trait/in-trait/issue-102140.rs b/tests/ui/impl-trait/in-trait/issue-102140.rs
index 1132bd25f81..7960018482f 100644
--- a/tests/ui/impl-trait/in-trait/issue-102140.rs
+++ b/tests/ui/impl-trait/in-trait/issue-102140.rs
@@ -1,5 +1,3 @@
-#![allow(incomplete_features)]
-
 trait Marker {}
 impl Marker for u32 {}
 
diff --git a/tests/ui/impl-trait/in-trait/issue-102140.stderr b/tests/ui/impl-trait/in-trait/issue-102140.stderr
index 6d50d2f3a24..9cd2cdfd1a5 100644
--- a/tests/ui/impl-trait/in-trait/issue-102140.stderr
+++ b/tests/ui/impl-trait/in-trait/issue-102140.stderr
@@ -1,5 +1,5 @@
 error[E0277]: the trait bound `&dyn MyTrait: MyTrait` is not satisfied
-  --> $DIR/issue-102140.rs:22:22
+  --> $DIR/issue-102140.rs:20:22
    |
 LL |         MyTrait::foo(&self)
    |         ------------ ^^^^^ the trait `MyTrait` is not implemented for `&dyn MyTrait`
@@ -13,7 +13,7 @@ LL +         MyTrait::foo(self)
    |
 
 error[E0277]: the trait bound `&dyn MyTrait: MyTrait` is not satisfied
-  --> $DIR/issue-102140.rs:22:9
+  --> $DIR/issue-102140.rs:20:9
    |
 LL |         MyTrait::foo(&self)
    |         ^^^^^^^^^^^^^^^^^^^ the trait `MyTrait` is not implemented for `&dyn MyTrait`
@@ -21,7 +21,7 @@ LL |         MyTrait::foo(&self)
    = help: the trait `MyTrait` is implemented for `Outer`
 
 error[E0277]: the trait bound `&dyn MyTrait: MyTrait` is not satisfied
-  --> $DIR/issue-102140.rs:22:9
+  --> $DIR/issue-102140.rs:20:9
    |
 LL |         MyTrait::foo(&self)
    |         ^^^^^^^^^^^^ the trait `MyTrait` is not implemented for `&dyn MyTrait`
diff --git a/tests/ui/impl-trait/in-trait/issue-102571.rs b/tests/ui/impl-trait/in-trait/issue-102571.rs
index 4534753f0d2..4fa3fdd31b5 100644
--- a/tests/ui/impl-trait/in-trait/issue-102571.rs
+++ b/tests/ui/impl-trait/in-trait/issue-102571.rs
@@ -1,5 +1,3 @@
-#![allow(incomplete_features)]
-
 use std::fmt::Display;
 use std::ops::Deref;
 
diff --git a/tests/ui/impl-trait/in-trait/issue-102571.stderr b/tests/ui/impl-trait/in-trait/issue-102571.stderr
index 4d1a0feb22b..872988faf7a 100644
--- a/tests/ui/impl-trait/in-trait/issue-102571.stderr
+++ b/tests/ui/impl-trait/in-trait/issue-102571.stderr
@@ -1,5 +1,5 @@
 error[E0308]: mismatched types
-  --> $DIR/issue-102571.rs:11:9
+  --> $DIR/issue-102571.rs:9:9
    |
 LL |     let () = t.bar();
    |         ^^   ------- this expression has type `impl Deref<Target = impl std::fmt::Display + ?Sized>`
diff --git a/tests/ui/impl-trait/in-trait/object-safety.rs b/tests/ui/impl-trait/in-trait/object-safety.rs
index 15634537dae..5cca4ad839c 100644
--- a/tests/ui/impl-trait/in-trait/object-safety.rs
+++ b/tests/ui/impl-trait/in-trait/object-safety.rs
@@ -1,5 +1,3 @@
-#![allow(incomplete_features)]
-
 use std::fmt::Debug;
 
 trait Foo {
diff --git a/tests/ui/impl-trait/in-trait/object-safety.stderr b/tests/ui/impl-trait/in-trait/object-safety.stderr
index 8d882391251..3271cb18d9f 100644
--- a/tests/ui/impl-trait/in-trait/object-safety.stderr
+++ b/tests/ui/impl-trait/in-trait/object-safety.stderr
@@ -1,11 +1,11 @@
 error[E0038]: the trait `Foo` cannot be made into an object
-  --> $DIR/object-safety.rs:16:33
+  --> $DIR/object-safety.rs:14:33
    |
 LL |     let i = Box::new(42_u32) as Box<dyn Foo>;
    |                                 ^^^^^^^^^^^^ `Foo` 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/object-safety.rs:6:22
+  --> $DIR/object-safety.rs:4:22
    |
 LL | trait Foo {
    |       --- this trait cannot be made into an object...
@@ -14,13 +14,13 @@ LL |     fn baz(&self) -> impl Debug;
    = help: consider moving `baz` to another trait
 
 error[E0038]: the trait `Foo` cannot be made into an object
-  --> $DIR/object-safety.rs:19:15
+  --> $DIR/object-safety.rs:17:15
    |
 LL |     let s = i.baz();
    |               ^^^ `Foo` 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/object-safety.rs:6:22
+  --> $DIR/object-safety.rs:4:22
    |
 LL | trait Foo {
    |       --- this trait cannot be made into an object...
@@ -29,13 +29,13 @@ LL |     fn baz(&self) -> impl Debug;
    = help: consider moving `baz` to another trait
 
 error[E0038]: the trait `Foo` cannot be made into an object
-  --> $DIR/object-safety.rs:19:13
+  --> $DIR/object-safety.rs:17:13
    |
 LL |     let s = i.baz();
    |             ^^^^^^^ `Foo` 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/object-safety.rs:6:22
+  --> $DIR/object-safety.rs:4:22
    |
 LL | trait Foo {
    |       --- this trait cannot be made into an object...
@@ -44,13 +44,13 @@ LL |     fn baz(&self) -> impl Debug;
    = help: consider moving `baz` to another trait
 
 error[E0038]: the trait `Foo` cannot be made into an object
-  --> $DIR/object-safety.rs:16:13
+  --> $DIR/object-safety.rs:14:13
    |
 LL |     let i = Box::new(42_u32) as Box<dyn Foo>;
    |             ^^^^^^^^^^^^^^^^ `Foo` 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/object-safety.rs:6:22
+  --> $DIR/object-safety.rs:4:22
    |
 LL | trait Foo {
    |       --- this trait cannot be made into an object...
diff --git a/tests/ui/impl-trait/in-trait/opaque-in-impl-is-opaque.rs b/tests/ui/impl-trait/in-trait/opaque-in-impl-is-opaque.rs
index fc708536b0f..1f18bb3b774 100644
--- a/tests/ui/impl-trait/in-trait/opaque-in-impl-is-opaque.rs
+++ b/tests/ui/impl-trait/in-trait/opaque-in-impl-is-opaque.rs
@@ -1,5 +1,3 @@
-#![allow(incomplete_features)]
-
 use std::fmt::Display;
 
 trait Foo {
diff --git a/tests/ui/impl-trait/in-trait/opaque-in-impl-is-opaque.stderr b/tests/ui/impl-trait/in-trait/opaque-in-impl-is-opaque.stderr
index 99b62e80acd..e260762d89f 100644
--- a/tests/ui/impl-trait/in-trait/opaque-in-impl-is-opaque.stderr
+++ b/tests/ui/impl-trait/in-trait/opaque-in-impl-is-opaque.stderr
@@ -1,5 +1,5 @@
 error[E0308]: mismatched types
-  --> $DIR/opaque-in-impl-is-opaque.rs:16:19
+  --> $DIR/opaque-in-impl-is-opaque.rs:14:19
    |
 LL |     fn bar(&self) -> impl Display {
    |                      ------------ the found opaque type
diff --git a/tests/ui/impl-trait/in-trait/trait-more-generics-than-impl.rs b/tests/ui/impl-trait/in-trait/trait-more-generics-than-impl.rs
index c905bfce852..d9fac0238e1 100644
--- a/tests/ui/impl-trait/in-trait/trait-more-generics-than-impl.rs
+++ b/tests/ui/impl-trait/in-trait/trait-more-generics-than-impl.rs
@@ -1,5 +1,3 @@
-#![allow(incomplete_features)]
-
 struct S;
 
 trait Foo {
diff --git a/tests/ui/impl-trait/in-trait/trait-more-generics-than-impl.stderr b/tests/ui/impl-trait/in-trait/trait-more-generics-than-impl.stderr
index e904548742d..2836e9c7821 100644
--- a/tests/ui/impl-trait/in-trait/trait-more-generics-than-impl.stderr
+++ b/tests/ui/impl-trait/in-trait/trait-more-generics-than-impl.stderr
@@ -1,5 +1,5 @@
 error[E0049]: method `bar` has 0 type parameters but its trait declaration has 1 type parameter
-  --> $DIR/trait-more-generics-than-impl.rs:10:11
+  --> $DIR/trait-more-generics-than-impl.rs:8:11
    |
 LL |     fn bar<T>() -> impl Sized;
    |            - expected 1 type parameter
diff --git a/tests/ui/inline-const/pat-unsafe-err.rs b/tests/ui/inline-const/pat-unsafe-err.rs
index e290b438c51..6df281c6d94 100644
--- a/tests/ui/inline-const/pat-unsafe-err.rs
+++ b/tests/ui/inline-const/pat-unsafe-err.rs
@@ -1,11 +1,13 @@
-// ignore-test This is currently broken
 // revisions: mir thir
+// [mir]ignore-test This is currently broken
 // [thir]compile-flags: -Z thir-unsafeck
 
 #![allow(incomplete_features)]
 #![feature(inline_const_pat)]
 
-const unsafe fn require_unsafe() -> usize { 1 }
+const unsafe fn require_unsafe() -> usize {
+    1
+}
 
 fn main() {
     match () {
@@ -14,4 +16,12 @@ fn main() {
             //~^ ERROR [E0133]
         } => (),
     }
+
+    match 1 {
+        const {
+            require_unsafe()
+            //~^ ERROR [E0133]
+        }..=4 => (),
+        _ => (),
+    }
 }
diff --git a/tests/ui/inline-const/pat-unsafe-err.thir.stderr b/tests/ui/inline-const/pat-unsafe-err.thir.stderr
new file mode 100644
index 00000000000..48a2cb4c704
--- /dev/null
+++ b/tests/ui/inline-const/pat-unsafe-err.thir.stderr
@@ -0,0 +1,19 @@
+error[E0133]: call to unsafe function `require_unsafe` is unsafe and requires unsafe function or block
+  --> $DIR/pat-unsafe-err.rs:15:13
+   |
+LL |             require_unsafe();
+   |             ^^^^^^^^^^^^^^^^ call to unsafe function
+   |
+   = note: consult the function's documentation for information on how to avoid undefined behavior
+
+error[E0133]: call to unsafe function `require_unsafe` is unsafe and requires unsafe function or block
+  --> $DIR/pat-unsafe-err.rs:22:13
+   |
+LL |             require_unsafe()
+   |             ^^^^^^^^^^^^^^^^ call to unsafe function
+   |
+   = note: consult the function's documentation for information on how to avoid undefined behavior
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0133`.
diff --git a/tests/ui/inline-const/pat-unsafe.rs b/tests/ui/inline-const/pat-unsafe.rs
index bcf7f6e0180..36f8632af67 100644
--- a/tests/ui/inline-const/pat-unsafe.rs
+++ b/tests/ui/inline-const/pat-unsafe.rs
@@ -1,13 +1,15 @@
-// ignore-test This is currently broken
 // check-pass
 // revisions: mir thir
+// [mir]ignore-test This is currently broken
 // [thir]compile-flags: -Z thir-unsafeck
 
 #![allow(incomplete_features)]
 #![warn(unused_unsafe)]
 #![feature(inline_const_pat)]
 
-const unsafe fn require_unsafe() -> usize { 1 }
+const unsafe fn require_unsafe() -> usize {
+    1
+}
 
 fn main() {
     unsafe {
@@ -18,5 +20,14 @@ fn main() {
                 //~^ WARNING unnecessary `unsafe` block
             } => (),
         }
+
+        match 1 {
+            const {
+                unsafe {}
+                //~^ WARNING unnecessary `unsafe` block
+                require_unsafe()
+            }..=4 => (),
+            _ => (),
+        }
     }
 }
diff --git a/tests/ui/inline-const/pat-unsafe.thir.stderr b/tests/ui/inline-const/pat-unsafe.thir.stderr
new file mode 100644
index 00000000000..d62c87fc8f3
--- /dev/null
+++ b/tests/ui/inline-const/pat-unsafe.thir.stderr
@@ -0,0 +1,26 @@
+warning: unnecessary `unsafe` block
+  --> $DIR/pat-unsafe.rs:19:17
+   |
+LL |     unsafe {
+   |     ------ because it's nested under this `unsafe` block
+...
+LL |                 unsafe {}
+   |                 ^^^^^^ unnecessary `unsafe` block
+   |
+note: the lint level is defined here
+  --> $DIR/pat-unsafe.rs:7:9
+   |
+LL | #![warn(unused_unsafe)]
+   |         ^^^^^^^^^^^^^
+
+warning: unnecessary `unsafe` block
+  --> $DIR/pat-unsafe.rs:26:17
+   |
+LL |     unsafe {
+   |     ------ because it's nested under this `unsafe` block
+...
+LL |                 unsafe {}
+   |                 ^^^^^^ unnecessary `unsafe` block
+
+warning: 2 warnings emitted
+
diff --git a/tests/ui/instrument-coverage/bad-value.bad.stderr b/tests/ui/instrument-coverage/bad-value.bad.stderr
index 246c4f31a4b..b867d169dae 100644
--- a/tests/ui/instrument-coverage/bad-value.bad.stderr
+++ b/tests/ui/instrument-coverage/bad-value.bad.stderr
@@ -1,2 +1,2 @@
-error: incorrect value `bad-value` for codegen option `instrument-coverage` - `all` (default), `except-unused-generics`, `except-unused-functions`, or `off` was expected
+error: incorrect value `bad-value` for codegen option `instrument-coverage` - `all` (default), `branch`, `except-unused-generics`, `except-unused-functions`, or `off` was expected
 
diff --git a/tests/ui/instrument-coverage/bad-value.blank.stderr b/tests/ui/instrument-coverage/bad-value.blank.stderr
index b539c558d9b..e7122fb61cd 100644
--- a/tests/ui/instrument-coverage/bad-value.blank.stderr
+++ b/tests/ui/instrument-coverage/bad-value.blank.stderr
@@ -1,2 +1,2 @@
-error: incorrect value `` for codegen option `instrument-coverage` - `all` (default), `except-unused-generics`, `except-unused-functions`, or `off` was expected
+error: incorrect value `` for codegen option `instrument-coverage` - `all` (default), `branch`, `except-unused-generics`, `except-unused-functions`, or `off` was expected
 
diff --git a/tests/ui/instrument-coverage/except-unused-functions.stderr b/tests/ui/instrument-coverage/except-unused-functions.stderr
index 82c1c630cbf..acc633a2a6d 100644
--- a/tests/ui/instrument-coverage/except-unused-functions.stderr
+++ b/tests/ui/instrument-coverage/except-unused-functions.stderr
@@ -1,2 +1,2 @@
-error: `-C instrument-coverage=except-*` requires `-Z unstable-options`
+error: `-C instrument-coverage=branch` and `-C instrument-coverage=except-*` require `-Z unstable-options`
 
diff --git a/tests/ui/instrument-coverage/except-unused-generics.stderr b/tests/ui/instrument-coverage/except-unused-generics.stderr
index 82c1c630cbf..acc633a2a6d 100644
--- a/tests/ui/instrument-coverage/except-unused-generics.stderr
+++ b/tests/ui/instrument-coverage/except-unused-generics.stderr
@@ -1,2 +1,2 @@
-error: `-C instrument-coverage=except-*` requires `-Z unstable-options`
+error: `-C instrument-coverage=branch` and `-C instrument-coverage=except-*` require `-Z unstable-options`
 
diff --git a/tests/ui/lifetimes/issue-26638.stderr b/tests/ui/lifetimes/issue-26638.stderr
index 30afcecf827..e61158a5d4d 100644
--- a/tests/ui/lifetimes/issue-26638.stderr
+++ b/tests/ui/lifetimes/issue-26638.stderr
@@ -44,6 +44,10 @@ LL | fn parse_type(iter: Box<dyn Iterator<Item=&str>+'static>) -> &str { iter.ne
    |
    = note: expected reference `&str`
                    found enum `Option<&str>`
+help: consider using `Option::expect` to unwrap the `Option<&str>` value, panicking if the value is an `Option::None`
+   |
+LL | fn parse_type(iter: Box<dyn Iterator<Item=&str>+'static>) -> &str { iter.next().expect("REASON") }
+   |                                                                                +++++++++++++++++
 
 error[E0061]: this function takes 1 argument but 0 arguments were supplied
   --> $DIR/issue-26638.rs:5:47
diff --git a/tests/ui/mismatched_types/mismatch-ty-dont-suggest.rs b/tests/ui/mismatched_types/mismatch-ty-dont-suggest.rs
new file mode 100644
index 00000000000..b288a9b05ef
--- /dev/null
+++ b/tests/ui/mismatched_types/mismatch-ty-dont-suggest.rs
@@ -0,0 +1,23 @@
+#![allow(unused, dead_code)]
+
+fn test_unwrap() -> Option<i32> {
+    let b: Result<i32, ()> = Ok(1);
+    let v: i32 = b; // return type is not `Result`, we don't suggest ? here
+    //~^ ERROR mismatched types
+    Some(v)
+}
+
+fn test_unwrap_option() -> Result<i32, ()> {
+    let b = Some(1);
+    let v: i32 = b; // return type is not `Option`, we don't suggest ? here
+    //~^ ERROR mismatched types
+    Ok(v)
+}
+
+fn main() {
+    let v: i32 = Some(0); //~ ERROR mismatched types
+
+    let c = Ok(false);
+    let v: i32 = c; //~ ERROR mismatched types
+
+}
diff --git a/tests/ui/mismatched_types/mismatch-ty-dont-suggest.stderr b/tests/ui/mismatched_types/mismatch-ty-dont-suggest.stderr
new file mode 100644
index 00000000000..4f8f9b1a8a5
--- /dev/null
+++ b/tests/ui/mismatched_types/mismatch-ty-dont-suggest.stderr
@@ -0,0 +1,55 @@
+error[E0308]: mismatched types
+  --> $DIR/mismatch-ty-dont-suggest.rs:5:18
+   |
+LL |     let v: i32 = b; // return type is not `Result`, we don't suggest ? here
+   |            ---   ^ expected `i32`, found `Result<i32, ()>`
+   |            |
+   |            expected due to this
+   |
+   = note: expected type `i32`
+              found enum `Result<i32, ()>`
+help: consider using `Result::expect` to unwrap the `Result<i32, ()>` value, panicking if the value is a `Result::Err`
+   |
+LL |     let v: i32 = b.expect("REASON"); // return type is not `Result`, we don't suggest ? here
+   |                   +++++++++++++++++
+
+error[E0308]: mismatched types
+  --> $DIR/mismatch-ty-dont-suggest.rs:12:18
+   |
+LL |     let v: i32 = b; // return type is not `Option`, we don't suggest ? here
+   |            ---   ^ expected `i32`, found `Option<{integer}>`
+   |            |
+   |            expected due to this
+   |
+   = note: expected type `i32`
+              found enum `Option<{integer}>`
+help: consider using `Option::expect` to unwrap the `Option<{integer}>` value, panicking if the value is an `Option::None`
+   |
+LL |     let v: i32 = b.expect("REASON"); // return type is not `Option`, we don't suggest ? here
+   |                   +++++++++++++++++
+
+error[E0308]: mismatched types
+  --> $DIR/mismatch-ty-dont-suggest.rs:18:18
+   |
+LL |     let v: i32 = Some(0);
+   |            ---   ^^^^^^^ expected `i32`, found `Option<{integer}>`
+   |            |
+   |            expected due to this
+   |
+   = note: expected type `i32`
+              found enum `Option<{integer}>`
+
+error[E0308]: mismatched types
+  --> $DIR/mismatch-ty-dont-suggest.rs:21:18
+   |
+LL |     let v: i32 = c;
+   |            ---   ^ expected `i32`, found `Result<bool, _>`
+   |            |
+   |            expected due to this
+   |
+   = note: expected type `i32`
+              found enum `Result<bool, _>`
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/mismatched_types/mismatch-ty-unwrap-expect.fixed b/tests/ui/mismatched_types/mismatch-ty-unwrap-expect.fixed
new file mode 100644
index 00000000000..f3f560fe530
--- /dev/null
+++ b/tests/ui/mismatched_types/mismatch-ty-unwrap-expect.fixed
@@ -0,0 +1,31 @@
+// run-rustfix
+#![allow(unused, dead_code)]
+
+fn func() -> Option<i32> {
+    Some(1)
+}
+
+fn test_unwrap() -> Result<i32, ()> {
+    let b: Result<i32, ()> = Ok(1);
+    let v: i32 = b?; //~ ERROR mismatched types
+    Ok(v)
+}
+
+fn test_unwrap_option() -> Option<i32> {
+    let b = Some(1);
+    let v: i32 = b?; //~ ERROR mismatched types
+    Some(v)
+}
+
+fn main() {
+    let a = Some(1);
+    let v: i32 = a.expect("REASON"); //~ ERROR mismatched types
+
+    let b: Result<i32, ()> = Ok(1);
+    let v: i32 = b.expect("REASON"); //~ ERROR mismatched types
+
+    let v: i32 = func().expect("REASON"); //~ ERROR mismatched types
+
+    let a = None;
+    let v: i32 = a.expect("REASON"); //~ ERROR mismatched types
+}
diff --git a/tests/ui/mismatched_types/mismatch-ty-unwrap-expect.rs b/tests/ui/mismatched_types/mismatch-ty-unwrap-expect.rs
new file mode 100644
index 00000000000..14020e872ff
--- /dev/null
+++ b/tests/ui/mismatched_types/mismatch-ty-unwrap-expect.rs
@@ -0,0 +1,31 @@
+// run-rustfix
+#![allow(unused, dead_code)]
+
+fn func() -> Option<i32> {
+    Some(1)
+}
+
+fn test_unwrap() -> Result<i32, ()> {
+    let b: Result<i32, ()> = Ok(1);
+    let v: i32 = b; //~ ERROR mismatched types
+    Ok(v)
+}
+
+fn test_unwrap_option() -> Option<i32> {
+    let b = Some(1);
+    let v: i32 = b; //~ ERROR mismatched types
+    Some(v)
+}
+
+fn main() {
+    let a = Some(1);
+    let v: i32 = a; //~ ERROR mismatched types
+
+    let b: Result<i32, ()> = Ok(1);
+    let v: i32 = b; //~ ERROR mismatched types
+
+    let v: i32 = func(); //~ ERROR mismatched types
+
+    let a = None;
+    let v: i32 = a; //~ ERROR mismatched types
+}
diff --git a/tests/ui/mismatched_types/mismatch-ty-unwrap-expect.stderr b/tests/ui/mismatched_types/mismatch-ty-unwrap-expect.stderr
new file mode 100644
index 00000000000..9de23447fed
--- /dev/null
+++ b/tests/ui/mismatched_types/mismatch-ty-unwrap-expect.stderr
@@ -0,0 +1,93 @@
+error[E0308]: mismatched types
+  --> $DIR/mismatch-ty-unwrap-expect.rs:10:18
+   |
+LL |     let v: i32 = b;
+   |            ---   ^ expected `i32`, found `Result<i32, ()>`
+   |            |
+   |            expected due to this
+   |
+   = note: expected type `i32`
+              found enum `Result<i32, ()>`
+help: use the `?` operator to extract the `Result<i32, ()>` value, propagating a `Result::Err` value to the caller
+   |
+LL |     let v: i32 = b?;
+   |                   +
+
+error[E0308]: mismatched types
+  --> $DIR/mismatch-ty-unwrap-expect.rs:16:18
+   |
+LL |     let v: i32 = b;
+   |            ---   ^ expected `i32`, found `Option<{integer}>`
+   |            |
+   |            expected due to this
+   |
+   = note: expected type `i32`
+              found enum `Option<{integer}>`
+help: use the `?` operator to extract the `Option<{integer}>` value, propagating an `Option::None` value to the caller
+   |
+LL |     let v: i32 = b?;
+   |                   +
+
+error[E0308]: mismatched types
+  --> $DIR/mismatch-ty-unwrap-expect.rs:22:18
+   |
+LL |     let v: i32 = a;
+   |            ---   ^ expected `i32`, found `Option<{integer}>`
+   |            |
+   |            expected due to this
+   |
+   = note: expected type `i32`
+              found enum `Option<{integer}>`
+help: consider using `Option::expect` to unwrap the `Option<{integer}>` value, panicking if the value is an `Option::None`
+   |
+LL |     let v: i32 = a.expect("REASON");
+   |                   +++++++++++++++++
+
+error[E0308]: mismatched types
+  --> $DIR/mismatch-ty-unwrap-expect.rs:25:18
+   |
+LL |     let v: i32 = b;
+   |            ---   ^ expected `i32`, found `Result<i32, ()>`
+   |            |
+   |            expected due to this
+   |
+   = note: expected type `i32`
+              found enum `Result<i32, ()>`
+help: consider using `Result::expect` to unwrap the `Result<i32, ()>` value, panicking if the value is a `Result::Err`
+   |
+LL |     let v: i32 = b.expect("REASON");
+   |                   +++++++++++++++++
+
+error[E0308]: mismatched types
+  --> $DIR/mismatch-ty-unwrap-expect.rs:27:18
+   |
+LL |     let v: i32 = func();
+   |            ---   ^^^^^^ expected `i32`, found `Option<i32>`
+   |            |
+   |            expected due to this
+   |
+   = note: expected type `i32`
+              found enum `Option<i32>`
+help: consider using `Option::expect` to unwrap the `Option<i32>` value, panicking if the value is an `Option::None`
+   |
+LL |     let v: i32 = func().expect("REASON");
+   |                        +++++++++++++++++
+
+error[E0308]: mismatched types
+  --> $DIR/mismatch-ty-unwrap-expect.rs:30:18
+   |
+LL |     let v: i32 = a;
+   |            ---   ^ expected `i32`, found `Option<_>`
+   |            |
+   |            expected due to this
+   |
+   = note: expected type `i32`
+              found enum `Option<_>`
+help: consider using `Option::expect` to unwrap the `Option<_>` value, panicking if the value is an `Option::None`
+   |
+LL |     let v: i32 = a.expect("REASON");
+   |                   +++++++++++++++++
+
+error: aborting due to 6 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/noexporttypeexe.stderr b/tests/ui/noexporttypeexe.stderr
index 26bafd31d01..bf88ceaa5d2 100644
--- a/tests/ui/noexporttypeexe.stderr
+++ b/tests/ui/noexporttypeexe.stderr
@@ -8,6 +8,10 @@ LL |   let x: isize = noexporttypelib::foo();
    |
    = note: expected type `isize`
               found enum `Option<isize>`
+help: consider using `Option::expect` to unwrap the `Option<isize>` value, panicking if the value is an `Option::None`
+   |
+LL |   let x: isize = noexporttypelib::foo().expect("REASON");
+   |                                        +++++++++++++++++
 
 error: aborting due to previous error
 
diff --git a/tests/ui/pattern/non-structural-match-types.mir.stderr b/tests/ui/pattern/non-structural-match-types.mir.stderr
new file mode 100644
index 00000000000..7a9e5b7e02e
--- /dev/null
+++ b/tests/ui/pattern/non-structural-match-types.mir.stderr
@@ -0,0 +1,14 @@
+error: `{closure@$DIR/non-structural-match-types.rs:12:17: 12:19}` cannot be used in patterns
+  --> $DIR/non-structural-match-types.rs:12:9
+   |
+LL |         const { || {} } => {}
+   |         ^^^^^^^^^^^^^^^
+
+error: `{async block@$DIR/non-structural-match-types.rs:15:17: 15:25}` cannot be used in patterns
+  --> $DIR/non-structural-match-types.rs:15:9
+   |
+LL |         const { async {} } => {}
+   |         ^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/pattern/non-structural-match-types.rs b/tests/ui/pattern/non-structural-match-types.rs
index fc52ee3d013..fb7779fa808 100644
--- a/tests/ui/pattern/non-structural-match-types.rs
+++ b/tests/ui/pattern/non-structural-match-types.rs
@@ -1,4 +1,7 @@
 // edition:2021
+// revisions: mir thir
+// [thir]compile-flags: -Z thir-unsafeck
+
 #![allow(incomplete_features)]
 #![allow(unreachable_code)]
 #![feature(const_async_blocks)]
diff --git a/tests/ui/pattern/non-structural-match-types.stderr b/tests/ui/pattern/non-structural-match-types.stderr
deleted file mode 100644
index f3e0665fef5..00000000000
--- a/tests/ui/pattern/non-structural-match-types.stderr
+++ /dev/null
@@ -1,14 +0,0 @@
-error: `{closure@$DIR/non-structural-match-types.rs:9:17: 9:19}` cannot be used in patterns
-  --> $DIR/non-structural-match-types.rs:9:9
-   |
-LL |         const { || {} } => {}
-   |         ^^^^^^^^^^^^^^^
-
-error: `{async block@$DIR/non-structural-match-types.rs:12:17: 12:25}` cannot be used in patterns
-  --> $DIR/non-structural-match-types.rs:12:9
-   |
-LL |         const { async {} } => {}
-   |         ^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 2 previous errors
-
diff --git a/tests/ui/pattern/non-structural-match-types.thir.stderr b/tests/ui/pattern/non-structural-match-types.thir.stderr
new file mode 100644
index 00000000000..7a9e5b7e02e
--- /dev/null
+++ b/tests/ui/pattern/non-structural-match-types.thir.stderr
@@ -0,0 +1,14 @@
+error: `{closure@$DIR/non-structural-match-types.rs:12:17: 12:19}` cannot be used in patterns
+  --> $DIR/non-structural-match-types.rs:12:9
+   |
+LL |         const { || {} } => {}
+   |         ^^^^^^^^^^^^^^^
+
+error: `{async block@$DIR/non-structural-match-types.rs:15:17: 15:25}` cannot be used in patterns
+  --> $DIR/non-structural-match-types.rs:15:9
+   |
+LL |         const { async {} } => {}
+   |         ^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/reachable/reachable-unnameable-type-alias.rs b/tests/ui/reachable/reachable-unnameable-type-alias.rs
index 461355f87cf..ce830d2d4b4 100644
--- a/tests/ui/reachable/reachable-unnameable-type-alias.rs
+++ b/tests/ui/reachable/reachable-unnameable-type-alias.rs
@@ -1,14 +1,14 @@
 // run-pass
 
 #![feature(staged_api)]
-#![stable(feature = "a", since = "b")]
+#![stable(feature = "a", since = "3.3.3")]
 
 mod inner_private_module {
     // UnnameableTypeAlias isn't marked as reachable, so no stability annotation is required here
     pub type UnnameableTypeAlias = u8;
 }
 
-#[stable(feature = "a", since = "b")]
+#[stable(feature = "a", since = "3.3.3")]
 pub fn f() -> inner_private_module::UnnameableTypeAlias {
     0
 }
diff --git a/tests/ui/repr/16-bit-repr-c-enum.rs b/tests/ui/repr/16-bit-repr-c-enum.rs
index d4fea2b192b..987fd455fcc 100644
--- a/tests/ui/repr/16-bit-repr-c-enum.rs
+++ b/tests/ui/repr/16-bit-repr-c-enum.rs
@@ -8,7 +8,7 @@
 #![feature(no_core, lang_items, intrinsics, staged_api, rustc_attrs)]
 #![no_core]
 #![crate_type = "lib"]
-#![stable(feature = "", since = "")]
+#![stable(feature = "intrinsics_for_test", since = "3.3.3")]
 #![allow(dead_code)]
 
 // Test that the repr(C) attribute doesn't break compilation
@@ -22,8 +22,8 @@ enum Foo {
 }
 
 extern "rust-intrinsic" {
-    #[stable(feature = "", since = "")]
-    #[rustc_const_stable(feature = "", since = "")]
+    #[stable(feature = "intrinsics_for_test", since = "3.3.3")]
+    #[rustc_const_stable(feature = "intrinsics_for_test", since = "3.3.3")]
     #[rustc_safe_intrinsic]
     fn size_of<T>() -> usize;
 }
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/default-method-body-is-const-with-staged-api.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/default-method-body-is-const-with-staged-api.rs
index 1b45cd9aab9..13881e042a3 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/default-method-body-is-const-with-staged-api.rs
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/default-method-body-is-const-with-staged-api.rs
@@ -7,7 +7,7 @@
 
 #![feature(staged_api)]
 #![feature(const_trait_impl)]
-#![stable(since = "1", feature = "foo")]
+#![stable(feature = "foo", since = "3.3.3")]
 
 #[const_trait]
 trait Tr {
diff --git a/tests/ui/stability-attribute/stability-attribute-issue-43027.rs b/tests/ui/stability-attribute/stability-attribute-issue-43027.rs
index 3f4fdfd0180..810fbef7b38 100644
--- a/tests/ui/stability-attribute/stability-attribute-issue-43027.rs
+++ b/tests/ui/stability-attribute/stability-attribute-issue-43027.rs
@@ -1,12 +1,12 @@
 // check-pass
 #![feature(staged_api)]
-#![stable(feature = "test", since = "0")]
+#![stable(feature = "test", since = "3.3.3")]
 
-#[stable(feature = "test", since = "0")]
+#[stable(feature = "test", since = "3.3.3")]
 pub struct A<T>(pub T);
 
-#[stable(feature = "test", since = "0")]
-pub struct B<T>(#[stable(feature = "test", since = "0")] pub T);
+#[stable(feature = "test", since = "3.3.3")]
+pub struct B<T>(#[stable(feature = "test", since = "3.3.3")] pub T);
 
 fn main() {
     // Make sure the field is used to fill the stability cache
diff --git a/tests/ui/stability-attribute/stability-attribute-sanity-4.rs b/tests/ui/stability-attribute/stability-attribute-sanity-4.rs
index 64f99635219..4fe8e45fd04 100644
--- a/tests/ui/stability-attribute/stability-attribute-sanity-4.rs
+++ b/tests/ui/stability-attribute/stability-attribute-sanity-4.rs
@@ -17,11 +17,11 @@ mod bogus_attribute_types_2 {
     #[stable = "a"] //~ ERROR malformed `stable` attribute
     fn f4() { }
 
-    #[stable(feature = "a", since = "b")]
+    #[stable(feature = "a", since = "3.3.3")]
     #[deprecated] //~ ERROR missing 'since'
     fn f5() { }
 
-    #[stable(feature = "a", since = "b")]
+    #[stable(feature = "a", since = "3.3.3")]
     #[deprecated = "a"] //~ ERROR missing 'since'
     fn f6() { }
 }
diff --git a/tests/ui/stability-attribute/stability-attribute-sanity.rs b/tests/ui/stability-attribute/stability-attribute-sanity.rs
index cc30e6ab9a9..7b3a7b537c1 100644
--- a/tests/ui/stability-attribute/stability-attribute-sanity.rs
+++ b/tests/ui/stability-attribute/stability-attribute-sanity.rs
@@ -5,19 +5,19 @@
 #![stable(feature = "rust1", since = "1.0.0")]
 
 mod bogus_attribute_types_1 {
-    #[stable(feature = "a", since = "b", reason)] //~ ERROR unknown meta item 'reason' [E0541]
+    #[stable(feature = "a", since = "4.4.4", reason)] //~ ERROR unknown meta item 'reason' [E0541]
     fn f1() { }
 
     #[stable(feature = "a", since)] //~ ERROR incorrect meta item [E0539]
     fn f2() { }
 
-    #[stable(feature, since = "a")] //~ ERROR incorrect meta item [E0539]
+    #[stable(feature, since = "3.3.3")] //~ ERROR incorrect meta item [E0539]
     fn f3() { }
 
     #[stable(feature = "a", since(b))] //~ ERROR incorrect meta item [E0539]
     fn f5() { }
 
-    #[stable(feature(b), since = "a")] //~ ERROR incorrect meta item [E0539]
+    #[stable(feature(b), since = "3.3.3")] //~ ERROR incorrect meta item [E0539]
     fn f6() { }
 }
 
@@ -28,7 +28,7 @@ mod missing_feature_names {
     #[unstable(feature = "b")] //~ ERROR missing 'issue' [E0547]
     fn f2() { }
 
-    #[stable(since = "a")] //~ ERROR missing 'feature' [E0546]
+    #[stable(since = "3.3.3")] //~ ERROR missing 'feature' [E0546]
     fn f3() { }
 }
 
@@ -36,33 +36,34 @@ mod missing_version {
     #[stable(feature = "a")] //~ ERROR missing 'since' [E0542]
     fn f1() { }
 
-    #[stable(feature = "a", since = "b")]
+    #[stable(feature = "a", since = "4.4.4")]
     #[deprecated(note = "a")] //~ ERROR missing 'since' [E0542]
     fn f2() { }
 
-    #[stable(feature = "a", since = "b")]
+    #[stable(feature = "a", since = "4.4.4")]
     #[deprecated(since = "a")] //~ ERROR missing 'note' [E0543]
     fn f3() { }
 }
 
 #[unstable(feature = "b", issue = "none")]
-#[stable(feature = "a", since = "b")] //~ ERROR multiple stability levels [E0544]
+#[stable(feature = "a", since = "4.4.4")] //~ ERROR multiple stability levels [E0544]
 fn multiple1() { }
 
 #[unstable(feature = "b", issue = "none")]
 #[unstable(feature = "b", issue = "none")] //~ ERROR multiple stability levels [E0544]
 fn multiple2() { }
 
-#[stable(feature = "a", since = "b")]
-#[stable(feature = "a", since = "b")] //~ ERROR multiple stability levels [E0544]
+#[stable(feature = "a", since = "4.4.4")]
+#[stable(feature = "a", since = "4.4.4")] //~ ERROR multiple stability levels [E0544]
 fn multiple3() { }
 
-#[stable(feature = "a", since = "b")] //~ ERROR invalid stability version found
+#[stable(feature = "e", since = "b")] //~ ERROR 'since' must be a Rust version number, such as "1.31.0"
 #[deprecated(since = "b", note = "text")]
 #[deprecated(since = "b", note = "text")] //~ ERROR multiple `deprecated` attributes
+//~^ ERROR deprecated attribute must be paired with either stable or unstable attribute
 #[rustc_const_unstable(feature = "c", issue = "none")]
 #[rustc_const_unstable(feature = "d", issue = "none")] //~ ERROR multiple stability levels
-pub const fn multiple4() { }
+pub const fn multiple4() { } //~ ERROR function has missing stability attribute
 
 #[stable(feature = "a", since = "1.0.0")] //~ ERROR invalid deprecation version found
 //~^ ERROR feature `a` is declared stable since 1.0.0
diff --git a/tests/ui/stability-attribute/stability-attribute-sanity.stderr b/tests/ui/stability-attribute/stability-attribute-sanity.stderr
index 89a8425f5e7..f9610c90f76 100644
--- a/tests/ui/stability-attribute/stability-attribute-sanity.stderr
+++ b/tests/ui/stability-attribute/stability-attribute-sanity.stderr
@@ -11,10 +11,10 @@ LL | #[deprecated(since = "b", note = "text")]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0541]: unknown meta item 'reason'
-  --> $DIR/stability-attribute-sanity.rs:8:42
+  --> $DIR/stability-attribute-sanity.rs:8:46
    |
-LL |     #[stable(feature = "a", since = "b", reason)]
-   |                                          ^^^^^^ expected one of `feature`, `since`
+LL |     #[stable(feature = "a", since = "4.4.4", reason)]
+   |                                              ^^^^^^ expected one of `feature`, `since`
 
 error[E0539]: incorrect meta item
   --> $DIR/stability-attribute-sanity.rs:11:29
@@ -25,7 +25,7 @@ LL |     #[stable(feature = "a", since)]
 error[E0539]: incorrect meta item
   --> $DIR/stability-attribute-sanity.rs:14:14
    |
-LL |     #[stable(feature, since = "a")]
+LL |     #[stable(feature, since = "3.3.3")]
    |              ^^^^^^^
 
 error[E0539]: incorrect meta item
@@ -37,7 +37,7 @@ LL |     #[stable(feature = "a", since(b))]
 error[E0539]: incorrect meta item
   --> $DIR/stability-attribute-sanity.rs:20:14
    |
-LL |     #[stable(feature(b), since = "a")]
+LL |     #[stable(feature(b), since = "3.3.3")]
    |              ^^^^^^^^^^
 
 error[E0546]: missing 'feature'
@@ -55,8 +55,8 @@ LL |     #[unstable(feature = "b")]
 error[E0546]: missing 'feature'
   --> $DIR/stability-attribute-sanity.rs:31:5
    |
-LL |     #[stable(since = "a")]
-   |     ^^^^^^^^^^^^^^^^^^^^^^
+LL |     #[stable(since = "3.3.3")]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0542]: missing 'since'
   --> $DIR/stability-attribute-sanity.rs:36:5
@@ -79,8 +79,8 @@ LL |     #[deprecated(since = "a")]
 error[E0544]: multiple stability levels
   --> $DIR/stability-attribute-sanity.rs:49:1
    |
-LL | #[stable(feature = "a", since = "b")]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | #[stable(feature = "a", since = "4.4.4")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0544]: multiple stability levels
   --> $DIR/stability-attribute-sanity.rs:53:1
@@ -91,26 +91,29 @@ LL | #[unstable(feature = "b", issue = "none")]
 error[E0544]: multiple stability levels
   --> $DIR/stability-attribute-sanity.rs:57:1
    |
-LL | #[stable(feature = "a", since = "b")]
+LL | #[stable(feature = "a", since = "4.4.4")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: 'since' must be a Rust version number, such as "1.31.0"
+  --> $DIR/stability-attribute-sanity.rs:60:1
+   |
+LL | #[stable(feature = "e", since = "b")]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0544]: multiple stability levels
-  --> $DIR/stability-attribute-sanity.rs:64:1
+  --> $DIR/stability-attribute-sanity.rs:65:1
    |
 LL | #[rustc_const_unstable(feature = "d", issue = "none")]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: invalid stability version found
-  --> $DIR/stability-attribute-sanity.rs:60:1
+error[E0549]: deprecated attribute must be paired with either stable or unstable attribute
+  --> $DIR/stability-attribute-sanity.rs:62:1
    |
-LL | #[stable(feature = "a", since = "b")]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid stability version
-...
-LL | pub const fn multiple4() { }
-   | ---------------------------- the stability attribute annotates this item
+LL | #[deprecated(since = "b", note = "text")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: invalid deprecation version found
-  --> $DIR/stability-attribute-sanity.rs:67:1
+  --> $DIR/stability-attribute-sanity.rs:68:1
    |
 LL | #[stable(feature = "a", since = "1.0.0")]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid deprecation version
@@ -119,18 +122,24 @@ LL | fn invalid_deprecation_version() {}
    | ----------------------------------- the stability attribute annotates this item
 
 error[E0549]: deprecated attribute must be paired with either stable or unstable attribute
-  --> $DIR/stability-attribute-sanity.rs:72:1
+  --> $DIR/stability-attribute-sanity.rs:73:1
    |
 LL | #[deprecated(since = "a", note = "text")]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error[E0711]: feature `a` is declared stable since 1.0.0, but was previously declared stable since b
-  --> $DIR/stability-attribute-sanity.rs:67:1
+error: function has missing stability attribute
+  --> $DIR/stability-attribute-sanity.rs:66:1
+   |
+LL | pub const fn multiple4() { }
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0711]: feature `a` is declared stable since 1.0.0, but was previously declared stable since 4.4.4
+  --> $DIR/stability-attribute-sanity.rs:68:1
    |
 LL | #[stable(feature = "a", since = "1.0.0")]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 20 previous errors
+error: aborting due to 22 previous errors
 
 Some errors have detailed explanations: E0539, E0541, E0542, E0543, E0544, E0546, E0547, E0549, E0711.
 For more information about an error, try `rustc --explain E0539`.
diff --git a/tests/ui/stability-attribute/stability-attribute-trait-impl.rs b/tests/ui/stability-attribute/stability-attribute-trait-impl.rs
index 1d138e26408..880000ee7a4 100644
--- a/tests/ui/stability-attribute/stability-attribute-trait-impl.rs
+++ b/tests/ui/stability-attribute/stability-attribute-trait-impl.rs
@@ -1,13 +1,13 @@
 #![feature(staged_api, never_type, rust_cold_cc)]
 //~^ ERROR module has missing stability attribute
 
-#[stable(feature = "a", since = "1")]
+#[stable(feature = "a", since = "3.3.3")]
 struct StableType;
 
 #[unstable(feature = "b", issue = "none")]
 struct UnstableType;
 
-#[stable(feature = "c", since = "1")]
+#[stable(feature = "c", since = "3.3.3")]
 trait StableTrait {}
 
 #[unstable(feature = "d", issue = "none")]
diff --git a/tests/ui/stability-attribute/stability-attribute-trait-impl.stderr b/tests/ui/stability-attribute/stability-attribute-trait-impl.stderr
index 96322c2c945..018786dd26d 100644
--- a/tests/ui/stability-attribute/stability-attribute-trait-impl.stderr
+++ b/tests/ui/stability-attribute/stability-attribute-trait-impl.stderr
@@ -21,7 +21,7 @@ error: module has missing stability attribute
 LL | / #![feature(staged_api, never_type, rust_cold_cc)]
 LL | |
 LL | |
-LL | | #[stable(feature = "a", since = "1")]
+LL | | #[stable(feature = "a", since = "3.3.3")]
 ...  |
 LL | |
 LL | | fn main() {}
diff --git a/tests/ui/target-feature/gate.rs b/tests/ui/target-feature/gate.rs
index 782444417a8..971a4654b4c 100644
--- a/tests/ui/target-feature/gate.rs
+++ b/tests/ui/target-feature/gate.rs
@@ -18,6 +18,7 @@
 // gate-test-bpf_target_feature
 // gate-test-aarch64_ver_target_feature
 // gate-test-csky_target_feature
+// gate-test-loongarch_target_feature
 
 #[target_feature(enable = "avx512bw")]
 //~^ ERROR: currently unstable
diff --git a/tests/ui/target-feature/gate.stderr b/tests/ui/target-feature/gate.stderr
index f56efb3bb83..0ec7427c3c4 100644
--- a/tests/ui/target-feature/gate.stderr
+++ b/tests/ui/target-feature/gate.stderr
@@ -1,5 +1,5 @@
 error[E0658]: the target feature `avx512bw` is currently unstable
-  --> $DIR/gate.rs:22:18
+  --> $DIR/gate.rs:23:18
    |
 LL | #[target_feature(enable = "avx512bw")]
    |                  ^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/typeck/tag-that-dare-not-speak-its-name.stderr b/tests/ui/typeck/tag-that-dare-not-speak-its-name.stderr
index f53abe53bf1..c4f16429563 100644
--- a/tests/ui/typeck/tag-that-dare-not-speak-its-name.stderr
+++ b/tests/ui/typeck/tag-that-dare-not-speak-its-name.stderr
@@ -8,6 +8,10 @@ LL |     let x : char = last(y);
    |
    = note: expected type `char`
               found enum `Option<_>`
+help: consider using `Option::expect` to unwrap the `Option<_>` value, panicking if the value is an `Option::None`
+   |
+LL |     let x : char = last(y).expect("REASON");
+   |                           +++++++++++++++++
 
 error: aborting due to previous error