diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
index 238145c5c6ee4..6e007b181f2c2 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
@@ -65,6 +65,7 @@ use rustc_hir::def_id::DefId;
 use rustc_hir::lang_items::LangItem;
 use rustc_hir::{Item, ItemKind, Node};
 use rustc_middle::dep_graph::DepContext;
+use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::{
     self,
     error::TypeError,
@@ -1736,6 +1737,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
             };
 
             if should_suggest_fixes {
+                self.suggest_tuple_pattern(cause, &exp_found, diag);
                 self.suggest_as_ref_where_appropriate(span, &exp_found, diag);
                 self.suggest_accessing_field_where_appropriate(cause, &exp_found, diag);
                 self.suggest_await_on_expect_found(cause, span, &exp_found, diag);
@@ -1766,6 +1768,73 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
         self.note_error_origin(diag, cause, exp_found, terr);
     }
 
+    fn suggest_tuple_pattern(
+        &self,
+        cause: &ObligationCause<'tcx>,
+        exp_found: &ty::error::ExpectedFound<Ty<'tcx>>,
+        diag: &mut Diagnostic,
+    ) {
+        // Heavily inspired by `FnCtxt::suggest_compatible_variants`, with
+        // some modifications due to that being in typeck and this being in infer.
+        if let ObligationCauseCode::Pattern { .. } = cause.code() {
+            if let ty::Adt(expected_adt, substs) = exp_found.expected.kind() {
+                let compatible_variants: Vec<_> = expected_adt
+                    .variants()
+                    .iter()
+                    .filter(|variant| {
+                        variant.fields.len() == 1 && variant.ctor_kind == hir::def::CtorKind::Fn
+                    })
+                    .filter_map(|variant| {
+                        let sole_field = &variant.fields[0];
+                        let sole_field_ty = sole_field.ty(self.tcx, substs);
+                        if same_type_modulo_infer(sole_field_ty, exp_found.found) {
+                            let variant_path =
+                                with_no_trimmed_paths!(self.tcx.def_path_str(variant.def_id));
+                            // FIXME #56861: DRYer prelude filtering
+                            if let Some(path) = variant_path.strip_prefix("std::prelude::") {
+                                if let Some((_, path)) = path.split_once("::") {
+                                    return Some(path.to_string());
+                                }
+                            }
+                            Some(variant_path)
+                        } else {
+                            None
+                        }
+                    })
+                    .collect();
+                match &compatible_variants[..] {
+                    [] => {}
+                    [variant] => {
+                        diag.multipart_suggestion_verbose(
+                            &format!("try wrapping the pattern in `{}`", variant),
+                            vec![
+                                (cause.span.shrink_to_lo(), format!("{}(", variant)),
+                                (cause.span.shrink_to_hi(), ")".to_string()),
+                            ],
+                            Applicability::MaybeIncorrect,
+                        );
+                    }
+                    _ => {
+                        // More than one matching variant.
+                        diag.multipart_suggestions(
+                            &format!(
+                                "try wrapping the pattern in a variant of `{}`",
+                                self.tcx.def_path_str(expected_adt.did())
+                            ),
+                            compatible_variants.into_iter().map(|variant| {
+                                vec![
+                                    (cause.span.shrink_to_lo(), format!("{}(", variant)),
+                                    (cause.span.shrink_to_hi(), ")".to_string()),
+                                ]
+                            }),
+                            Applicability::MaybeIncorrect,
+                        );
+                    }
+                }
+            }
+        }
+    }
+
     pub fn get_impl_future_output_ty(&self, ty: Ty<'tcx>) -> Option<Binder<'tcx, Ty<'tcx>>> {
         if let ty::Opaque(def_id, substs) = ty.kind() {
             let future_trait = self.tcx.require_lang_item(LangItem::Future, None);
diff --git a/compiler/rustc_typeck/src/check/demand.rs b/compiler/rustc_typeck/src/check/demand.rs
index 58e5c9315c30c..7f5ab8e4f42fa 100644
--- a/compiler/rustc_typeck/src/check/demand.rs
+++ b/compiler/rustc_typeck/src/check/demand.rs
@@ -268,10 +268,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         expr_ty: Ty<'tcx>,
     ) {
         if let ty::Adt(expected_adt, substs) = expected.kind() {
-            if !expected_adt.is_enum() {
-                return;
-            }
-
             // If the expression is of type () and it's the return expression of a block,
             // we suggest adding a separate return expression instead.
             // (To avoid things like suggesting `Ok(while .. { .. })`.)
@@ -336,7 +332,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             let compatible_variants: Vec<String> = expected_adt
                 .variants()
                 .iter()
-                .filter(|variant| variant.fields.len() == 1)
+                .filter(|variant| {
+                    variant.fields.len() == 1 && variant.ctor_kind == hir::def::CtorKind::Fn
+                })
                 .filter_map(|variant| {
                     let sole_field = &variant.fields[0];
                     let sole_field_ty = sole_field.ty(self.tcx, substs);
diff --git a/library/std/src/io/error/repr_bitpacked.rs b/library/std/src/io/error/repr_bitpacked.rs
index 1a0538f861a1e..208d5a80c5a69 100644
--- a/library/std/src/io/error/repr_bitpacked.rs
+++ b/library/std/src/io/error/repr_bitpacked.rs
@@ -104,6 +104,7 @@
 
 use super::{Custom, ErrorData, ErrorKind, SimpleMessage};
 use alloc::boxed::Box;
+use core::marker::PhantomData;
 use core::mem::{align_of, size_of};
 use core::ptr::NonNull;
 
@@ -114,8 +115,17 @@ const TAG_CUSTOM: usize = 0b01;
 const TAG_OS: usize = 0b10;
 const TAG_SIMPLE: usize = 0b11;
 
+/// The internal representation.
+///
+/// See the module docs for more, this is just a way to hack in a check that we
+/// indeed are not unwind-safe.
+///
+/// ```compile_fail,E0277
+/// fn is_unwind_safe<T: core::panic::UnwindSafe>() {}
+/// is_unwind_safe::<std::io::Error>();
+/// ```
 #[repr(transparent)]
-pub(super) struct Repr(NonNull<()>);
+pub(super) struct Repr(NonNull<()>, PhantomData<ErrorData<Box<Custom>>>);
 
 // All the types `Repr` stores internally are Send + Sync, and so is it.
 unsafe impl Send for Repr {}
@@ -145,7 +155,7 @@ impl Repr {
         // box, and `TAG_CUSTOM` just... isn't zero -- it's `0b01`). Therefore,
         // `TAG_CUSTOM + p` isn't zero and so `tagged` can't be, and the
         // `new_unchecked` is safe.
-        let res = Self(unsafe { NonNull::new_unchecked(tagged) });
+        let res = Self(unsafe { NonNull::new_unchecked(tagged) }, PhantomData);
         // quickly smoke-check we encoded the right thing (This generally will
         // only run in libstd's tests, unless the user uses -Zbuild-std)
         debug_assert!(matches!(res.data(), ErrorData::Custom(_)), "repr(custom) encoding failed");
@@ -156,7 +166,7 @@ impl Repr {
     pub(super) fn new_os(code: i32) -> Self {
         let utagged = ((code as usize) << 32) | TAG_OS;
         // Safety: `TAG_OS` is not zero, so the result of the `|` is not 0.
-        let res = Self(unsafe { NonNull::new_unchecked(utagged as *mut ()) });
+        let res = Self(unsafe { NonNull::new_unchecked(utagged as *mut ()) }, PhantomData);
         // quickly smoke-check we encoded the right thing (This generally will
         // only run in libstd's tests, unless the user uses -Zbuild-std)
         debug_assert!(
@@ -170,7 +180,7 @@ impl Repr {
     pub(super) fn new_simple(kind: ErrorKind) -> Self {
         let utagged = ((kind as usize) << 32) | TAG_SIMPLE;
         // Safety: `TAG_SIMPLE` is not zero, so the result of the `|` is not 0.
-        let res = Self(unsafe { NonNull::new_unchecked(utagged as *mut ()) });
+        let res = Self(unsafe { NonNull::new_unchecked(utagged as *mut ()) }, PhantomData);
         // quickly smoke-check we encoded the right thing (This generally will
         // only run in libstd's tests, unless the user uses -Zbuild-std)
         debug_assert!(
@@ -184,7 +194,7 @@ impl Repr {
     #[inline]
     pub(super) const fn new_simple_message(m: &'static SimpleMessage) -> Self {
         // Safety: References are never null.
-        Self(unsafe { NonNull::new_unchecked(m as *const _ as *mut ()) })
+        Self(unsafe { NonNull::new_unchecked(m as *const _ as *mut ()) }, PhantomData)
     }
 
     #[inline]
diff --git a/library/std/src/process.rs b/library/std/src/process.rs
index b6edf8bca0a23..d3c8d864b0c10 100644
--- a/library/std/src/process.rs
+++ b/library/std/src/process.rs
@@ -1417,6 +1417,15 @@ impl From<fs::File> for Stdio {
 /// For proper error reporting of failed processes, print the value of `ExitStatus` or
 /// `ExitStatusError` using their implementations of [`Display`](crate::fmt::Display).
 ///
+/// # Differences from `ExitStatus`
+///
+/// `ExitCode` is intended for terminating the currently running process, via
+/// the `Termination` trait, in contrast to [`ExitStatus`], which represents the
+/// termination of a child process. These APIs are separate due to platform
+/// compatibility differences and their expected usage; it is not generally
+/// possible to exactly reproduce an ExitStatus from a child for the current
+/// process after the fact.
+///
 /// [`status`]: Command::status
 /// [`wait`]: Child::wait
 //
@@ -1649,8 +1658,16 @@ impl fmt::Display for ExitStatusError {
 #[unstable(feature = "exit_status_error", issue = "84908")]
 impl crate::error::Error for ExitStatusError {}
 
-/// This type represents the status code a process can return to its
-/// parent under normal termination.
+/// This type represents the status code the current process can return
+/// to its parent under normal termination.
+///
+/// `ExitCode` is intended to be consumed only by the standard library (via
+/// [`Termination::report()`]), and intentionally does not provide accessors like
+/// `PartialEq`, `Eq`, or `Hash`. Instead the standard library provides the
+/// canonical `SUCCESS` and `FAILURE` exit codes as well as `From<u8> for
+/// ExitCode` for constructing other arbitrary exit codes.
+///
+/// # Portability
 ///
 /// Numeric values used in this type don't have portable meanings, and
 /// different platforms may mask different amounts of them.
@@ -1661,52 +1678,78 @@ impl crate::error::Error for ExitStatusError {}
 /// [`SUCCESS`]: ExitCode::SUCCESS
 /// [`FAILURE`]: ExitCode::FAILURE
 ///
-/// **Warning**: While various forms of this were discussed in [RFC #1937],
-/// it was ultimately cut from that RFC, and thus this type is more subject
-/// to change even than the usual unstable item churn.
+/// # Differences from `ExitStatus`
+///
+/// `ExitCode` is intended for terminating the currently running process, via
+/// the `Termination` trait, in contrast to [`ExitStatus`], which represents the
+/// termination of a child process. These APIs are separate due to platform
+/// compatibility differences and their expected usage; it is not generally
+/// possible to exactly reproduce an ExitStatus from a child for the current
+/// process after the fact.
+///
+/// # Examples
+///
+/// `ExitCode` can be returned from the `main` function of a crate, as it implements
+/// [`Termination`]:
+///
+/// ```
+/// use std::process::ExitCode;
+/// # fn check_foo() -> bool { true }
 ///
-/// [RFC #1937]: https://github.com/rust-lang/rfcs/pull/1937
+/// fn main() -> ExitCode {
+///     if !check_foo() {
+///         return ExitCode::from(42);
+///     }
+///
+///     ExitCode::SUCCESS
+/// }
+/// ```
 #[derive(Clone, Copy, Debug)]
-#[unstable(feature = "process_exitcode_placeholder", issue = "48711")]
+#[stable(feature = "process_exitcode", since = "1.60.0")]
 pub struct ExitCode(imp::ExitCode);
 
-#[unstable(feature = "process_exitcode_placeholder", issue = "48711")]
+#[stable(feature = "process_exitcode", since = "1.60.0")]
 impl ExitCode {
-    /// The canonical ExitCode for successful termination on this platform.
+    /// The canonical `ExitCode` for successful termination on this platform.
     ///
     /// Note that a `()`-returning `main` implicitly results in a successful
     /// termination, so there's no need to return this from `main` unless
     /// you're also returning other possible codes.
-    #[unstable(feature = "process_exitcode_placeholder", issue = "48711")]
+    #[stable(feature = "process_exitcode", since = "1.60.0")]
     pub const SUCCESS: ExitCode = ExitCode(imp::ExitCode::SUCCESS);
 
-    /// The canonical ExitCode for unsuccessful termination on this platform.
+    /// The canonical `ExitCode` for unsuccessful termination on this platform.
     ///
     /// If you're only returning this and `SUCCESS` from `main`, consider
     /// instead returning `Err(_)` and `Ok(())` respectively, which will
     /// return the same codes (but will also `eprintln!` the error).
-    #[unstable(feature = "process_exitcode_placeholder", issue = "48711")]
+    #[stable(feature = "process_exitcode", since = "1.60.0")]
     pub const FAILURE: ExitCode = ExitCode(imp::ExitCode::FAILURE);
 }
 
 impl ExitCode {
-    // This should not be stabilized when stabilizing ExitCode, we don't know that i32 will serve
+    // This is private/perma-unstable because ExitCode is opaque; we don't know that i32 will serve
     // all usecases, for example windows seems to use u32, unix uses the 8-15th bits of an i32, we
     // likely want to isolate users anything that could restrict the platform specific
     // representation of an ExitCode
     //
     // More info: https://internals.rust-lang.org/t/mini-pre-rfc-redesigning-process-exitstatus/5426
-    /// Convert an ExitCode into an i32
-    #[unstable(feature = "process_exitcode_placeholder", issue = "48711")]
+    /// Convert an `ExitCode` into an i32
+    #[unstable(
+        feature = "process_exitcode_internals",
+        reason = "exposed only for libstd",
+        issue = "none"
+    )]
     #[inline]
+    #[doc(hidden)]
     pub fn to_i32(self) -> i32 {
         self.0.as_i32()
     }
 }
 
-#[unstable(feature = "process_exitcode_placeholder", issue = "48711")]
+#[stable(feature = "process_exitcode", since = "1.60.0")]
 impl From<u8> for ExitCode {
-    /// Construct an exit code from an arbitrary u8 value.
+    /// Construct an `ExitCode` from an arbitrary u8 value.
     fn from(code: u8) -> Self {
         ExitCode(imp::ExitCode::from(code))
     }
@@ -2049,7 +2092,7 @@ pub fn id() -> u32 {
 /// standard library's runtime for convenience. Other runtimes are not required
 /// to provide similar functionality.
 #[cfg_attr(not(test), lang = "termination")]
-#[unstable(feature = "termination_trait_lib", issue = "43301")]
+#[stable(feature = "termination_trait_lib", since = "1.60.0")]
 #[rustc_on_unimplemented(
     message = "`main` has invalid return type `{Self}`",
     label = "`main` can only return types that implement `{Termination}`"
@@ -2057,10 +2100,11 @@ pub fn id() -> u32 {
 pub trait Termination {
     /// Is called to get the representation of the value as status code.
     /// This status code is returned to the operating system.
+    #[stable(feature = "termination_trait_lib", since = "1.60.0")]
     fn report(self) -> ExitCode;
 }
 
-#[unstable(feature = "termination_trait_lib", issue = "43301")]
+#[stable(feature = "termination_trait_lib", since = "1.60.0")]
 impl Termination for () {
     #[inline]
     fn report(self) -> ExitCode {
@@ -2068,7 +2112,7 @@ impl Termination for () {
     }
 }
 
-#[unstable(feature = "termination_trait_lib", issue = "43301")]
+#[stable(feature = "termination_trait_lib", since = "1.60.0")]
 impl<E: fmt::Debug> Termination for Result<(), E> {
     fn report(self) -> ExitCode {
         match self {
@@ -2078,14 +2122,14 @@ impl<E: fmt::Debug> Termination for Result<(), E> {
     }
 }
 
-#[unstable(feature = "termination_trait_lib", issue = "43301")]
+#[stable(feature = "termination_trait_lib", since = "1.60.0")]
 impl Termination for ! {
     fn report(self) -> ExitCode {
         self
     }
 }
 
-#[unstable(feature = "termination_trait_lib", issue = "43301")]
+#[stable(feature = "termination_trait_lib", since = "1.60.0")]
 impl<E: fmt::Debug> Termination for Result<!, E> {
     fn report(self) -> ExitCode {
         let Err(err) = self;
@@ -2094,7 +2138,7 @@ impl<E: fmt::Debug> Termination for Result<!, E> {
     }
 }
 
-#[unstable(feature = "termination_trait_lib", issue = "43301")]
+#[stable(feature = "termination_trait_lib", since = "1.60.0")]
 impl<E: fmt::Debug> Termination for Result<Infallible, E> {
     fn report(self) -> ExitCode {
         let Err(err) = self;
@@ -2102,7 +2146,7 @@ impl<E: fmt::Debug> Termination for Result<Infallible, E> {
     }
 }
 
-#[unstable(feature = "termination_trait_lib", issue = "43301")]
+#[stable(feature = "termination_trait_lib", since = "1.60.0")]
 impl Termination for ExitCode {
     #[inline]
     fn report(self) -> ExitCode {
diff --git a/library/test/src/lib.rs b/library/test/src/lib.rs
index 088e3a23ea4d9..889f7cb9db941 100644
--- a/library/test/src/lib.rs
+++ b/library/test/src/lib.rs
@@ -19,8 +19,7 @@
 #![feature(bench_black_box)]
 #![feature(internal_output_capture)]
 #![feature(staged_api)]
-#![feature(termination_trait_lib)]
-#![feature(process_exitcode_placeholder)]
+#![feature(process_exitcode_internals)]
 #![feature(test)]
 #![feature(total_cmp)]
 
diff --git a/src/test/ui/did_you_mean/compatible-variants-in-pat.rs b/src/test/ui/did_you_mean/compatible-variants-in-pat.rs
new file mode 100644
index 0000000000000..09e12dab2d3fc
--- /dev/null
+++ b/src/test/ui/did_you_mean/compatible-variants-in-pat.rs
@@ -0,0 +1,41 @@
+enum Foo {
+    Bar(Bar),
+}
+struct Bar {
+    x: i32,
+}
+
+fn a(f: Foo) {
+    match f {
+        Bar { x } => {
+            //~^ ERROR mismatched types
+            //~| HELP try wrapping
+        }
+    }
+}
+
+struct S;
+
+fn b(s: Option<S>) {
+    match s {
+        S => {
+            //~^ ERROR mismatched types
+            //~| HELP try wrapping
+            //~| HELP introduce a new binding instead
+        }
+        _ => {}
+    }
+}
+
+fn c(s: Result<S, S>) {
+    match s {
+        S => {
+            //~^ ERROR mismatched types
+            //~| HELP try wrapping
+            //~| HELP introduce a new binding instead
+        }
+        _ => {}
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/did_you_mean/compatible-variants-in-pat.stderr b/src/test/ui/did_you_mean/compatible-variants-in-pat.stderr
new file mode 100644
index 0000000000000..a4c77e08efe19
--- /dev/null
+++ b/src/test/ui/did_you_mean/compatible-variants-in-pat.stderr
@@ -0,0 +1,68 @@
+error[E0308]: mismatched types
+  --> $DIR/compatible-variants-in-pat.rs:10:9
+   |
+LL |     match f {
+   |           - this expression has type `Foo`
+LL |         Bar { x } => {
+   |         ^^^^^^^^^ expected enum `Foo`, found struct `Bar`
+   |
+help: try wrapping the pattern in `Foo::Bar`
+   |
+LL |         Foo::Bar(Bar { x }) => {
+   |         +++++++++         +
+
+error[E0308]: mismatched types
+  --> $DIR/compatible-variants-in-pat.rs:21:9
+   |
+LL | struct S;
+   | --------- unit struct defined here
+...
+LL |     match s {
+   |           - this expression has type `Option<S>`
+LL |         S => {
+   |         ^
+   |         |
+   |         expected enum `Option`, found struct `S`
+   |         `S` is interpreted as a unit struct, not a new binding
+   |
+   = note: expected enum `Option<S>`
+            found struct `S`
+help: try wrapping the pattern in `Some`
+   |
+LL |         Some(S) => {
+   |         +++++ +
+help: introduce a new binding instead
+   |
+LL |         other_s => {
+   |         ~~~~~~~
+
+error[E0308]: mismatched types
+  --> $DIR/compatible-variants-in-pat.rs:32:9
+   |
+LL | struct S;
+   | --------- unit struct defined here
+...
+LL |     match s {
+   |           - this expression has type `Result<S, S>`
+LL |         S => {
+   |         ^
+   |         |
+   |         expected enum `Result`, found struct `S`
+   |         `S` is interpreted as a unit struct, not a new binding
+   |
+   = note: expected enum `Result<S, S>`
+            found struct `S`
+help: try wrapping the pattern in a variant of `Result`
+   |
+LL |         Ok(S) => {
+   |         +++ +
+LL |         Err(S) => {
+   |         ++++ +
+help: introduce a new binding instead
+   |
+LL |         other_s => {
+   |         ~~~~~~~
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/did_you_mean/compatible-variants.rs b/src/test/ui/did_you_mean/compatible-variants.rs
index b078064b26745..5d7c611980f1c 100644
--- a/src/test/ui/did_you_mean/compatible-variants.rs
+++ b/src/test/ui/did_you_mean/compatible-variants.rs
@@ -64,3 +64,27 @@ fn main() {
     //~^ ERROR mismatched types
     //~| HELP try wrapping
 }
+
+enum A {
+    B { b: B},
+}
+
+struct A2(B);
+
+enum B {
+    Fst,
+    Snd,
+}
+
+fn foo() {
+    // We don't want to suggest `A::B(B::Fst)` here.
+    let a: A = B::Fst;
+    //~^ ERROR mismatched types
+}
+
+fn bar() {
+    // But we _do_ want to suggest `A2(B::Fst)` here!
+    let a: A2 = B::Fst;
+    //~^ ERROR mismatched types
+    //~| HELP try wrapping
+}
diff --git a/src/test/ui/did_you_mean/compatible-variants.stderr b/src/test/ui/did_you_mean/compatible-variants.stderr
index 51c1bf97c4e2c..a8cb5d6d3e849 100644
--- a/src/test/ui/did_you_mean/compatible-variants.stderr
+++ b/src/test/ui/did_you_mean/compatible-variants.stderr
@@ -190,6 +190,27 @@ help: try wrapping the expression in `Some`
 LL |     let _ = Foo { bar: Some(bar) };
    |                   ++++++++++   +
 
-error: aborting due to 11 previous errors
+error[E0308]: mismatched types
+  --> $DIR/compatible-variants.rs:81:16
+   |
+LL |     let a: A = B::Fst;
+   |            -   ^^^^^^ expected enum `A`, found enum `B`
+   |            |
+   |            expected due to this
+
+error[E0308]: mismatched types
+  --> $DIR/compatible-variants.rs:87:17
+   |
+LL |     let a: A2 = B::Fst;
+   |            --   ^^^^^^ expected struct `A2`, found enum `B`
+   |            |
+   |            expected due to this
+   |
+help: try wrapping the expression in `A2`
+   |
+LL |     let a: A2 = A2(B::Fst);
+   |                 +++      +
+
+error: aborting due to 13 previous errors
 
 For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/issues/issue-12552.stderr b/src/test/ui/issues/issue-12552.stderr
index 3d8852ca748af..4b027eba2c25e 100644
--- a/src/test/ui/issues/issue-12552.stderr
+++ b/src/test/ui/issues/issue-12552.stderr
@@ -8,6 +8,10 @@ LL |     Some(k) => match k {
    |
    = note: expected enum `Result<_, {integer}>`
               found enum `Option<_>`
+help: try wrapping the pattern in `Ok`
+   |
+LL |     Ok(Some(k)) => match k {
+   |     +++       +
 
 error[E0308]: mismatched types
   --> $DIR/issue-12552.rs:9:5
@@ -20,6 +24,10 @@ LL |     None => ()
    |
    = note: expected enum `Result<_, {integer}>`
               found enum `Option<_>`
+help: try wrapping the pattern in `Ok`
+   |
+LL |     Ok(None) => ()
+   |     +++    +
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/issues/issue-3680.stderr b/src/test/ui/issues/issue-3680.stderr
index e8fafa76b919b..29ba44f136afa 100644
--- a/src/test/ui/issues/issue-3680.stderr
+++ b/src/test/ui/issues/issue-3680.stderr
@@ -8,6 +8,10 @@ LL |         Err(_) => ()
    |
    = note: expected enum `Option<_>`
               found enum `Result<_, _>`
+help: try wrapping the pattern in `Some`
+   |
+LL |         Some(Err(_)) => ()
+   |         +++++      +
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-5358-1.stderr b/src/test/ui/issues/issue-5358-1.stderr
index d1bc279c7589a..9d5b8d9d3fc1b 100644
--- a/src/test/ui/issues/issue-5358-1.stderr
+++ b/src/test/ui/issues/issue-5358-1.stderr
@@ -8,6 +8,10 @@ LL |         Either::Right(_) => {}
    |
    = note: expected struct `S`
                 found enum `Either<_, _>`
+help: try wrapping the pattern in `S`
+   |
+LL |         S(Either::Right(_)) => {}
+   |         ++                +
 help: you might have meant to use field `0` whose type is `Either<usize, usize>`
    |
 LL |     match S(Either::Left(5)).0 {
diff --git a/src/test/ui/rfcs/rfc-1937-termination-trait/termination-trait-for-exitcode.rs b/src/test/ui/rfcs/rfc-1937-termination-trait/termination-trait-for-exitcode.rs
index 9c2270bf82752..6d4c1562053b6 100644
--- a/src/test/ui/rfcs/rfc-1937-termination-trait/termination-trait-for-exitcode.rs
+++ b/src/test/ui/rfcs/rfc-1937-termination-trait/termination-trait-for-exitcode.rs
@@ -1,5 +1,4 @@
 // run-pass
-#![feature(process_exitcode_placeholder)]
 
 use std::process::ExitCode;
 
diff --git a/src/test/ui/rfcs/rfc-1937-termination-trait/termination-trait-for-impl-termination.rs b/src/test/ui/rfcs/rfc-1937-termination-trait/termination-trait-for-impl-termination.rs
index 79cfba011c017..c06a135dcbc20 100644
--- a/src/test/ui/rfcs/rfc-1937-termination-trait/termination-trait-for-impl-termination.rs
+++ b/src/test/ui/rfcs/rfc-1937-termination-trait/termination-trait-for-impl-termination.rs
@@ -1,4 +1,3 @@
 // run-pass
-#![feature(termination_trait_lib)]
 
 fn main() -> impl std::process::Termination { }
diff --git a/src/test/ui/suggestions/derive-clone-for-eq.fixed b/src/test/ui/suggestions/derive-clone-for-eq.fixed
new file mode 100644
index 0000000000000..f07784d53b3a3
--- /dev/null
+++ b/src/test/ui/suggestions/derive-clone-for-eq.fixed
@@ -0,0 +1,18 @@
+// run-rustfix
+// https://github.com/rust-lang/rust/issues/79076
+
+use std::cmp::PartialEq;
+
+#[derive(Clone, Eq)] //~ ERROR [E0277]
+pub struct Struct<T: std::clone::Clone>(T);
+
+impl<T: Clone, U> PartialEq<U> for Struct<T>
+where
+    U: Into<Struct<T>> + Clone
+{
+    fn eq(&self, _other: &U) -> bool {
+        todo!()
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/suggestions/derive-clone-for-eq.rs b/src/test/ui/suggestions/derive-clone-for-eq.rs
new file mode 100644
index 0000000000000..15c0d4659fbbe
--- /dev/null
+++ b/src/test/ui/suggestions/derive-clone-for-eq.rs
@@ -0,0 +1,18 @@
+// run-rustfix
+// https://github.com/rust-lang/rust/issues/79076
+
+use std::cmp::PartialEq;
+
+#[derive(Clone, Eq)] //~ ERROR [E0277]
+pub struct Struct<T>(T);
+
+impl<T: Clone, U> PartialEq<U> for Struct<T>
+where
+    U: Into<Struct<T>> + Clone
+{
+    fn eq(&self, _other: &U) -> bool {
+        todo!()
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/suggestions/derive-clone-for-eq.stderr b/src/test/ui/suggestions/derive-clone-for-eq.stderr
new file mode 100644
index 0000000000000..55a23c031d5bc
--- /dev/null
+++ b/src/test/ui/suggestions/derive-clone-for-eq.stderr
@@ -0,0 +1,25 @@
+error[E0277]: the trait bound `T: Clone` is not satisfied
+  --> $DIR/derive-clone-for-eq.rs:6:17
+   |
+LL | #[derive(Clone, Eq)]
+   |                 ^^ the trait `Clone` is not implemented for `T`
+   |
+note: required because of the requirements on the impl of `PartialEq` for `Struct<T>`
+  --> $DIR/derive-clone-for-eq.rs:9:19
+   |
+LL | impl<T: Clone, U> PartialEq<U> for Struct<T>
+   |                   ^^^^^^^^^^^^     ^^^^^^^^^
+note: required by a bound in `Eq`
+  --> $SRC_DIR/core/src/cmp.rs:LL:COL
+   |
+LL | pub trait Eq: PartialEq<Self> {
+   |               ^^^^^^^^^^^^^^^ required by this bound in `Eq`
+   = note: this error originates in the derive macro `Eq` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider restricting type parameter `T`
+   |
+LL | pub struct Struct<T: std::clone::Clone>(T);
+   |                    +++++++++++++++++++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.