From fc37633580af9da06ab5e01e595a51f1e7c54cc7 Mon Sep 17 00:00:00 2001
From: Arvind Mukund <armu30@gmail.com>
Date: Sat, 9 Mar 2024 11:56:17 -0800
Subject: [PATCH 1/9] Support Result<T, E> across FFI when niche optimization
 can be used

Allow allow enums like `Result<T, E>` to be used across FFI if the
T/E can be niche optimized and the non-niche-optimized type is FFI safe.
---
 compiler/rustc_lint/src/types.rs | 48 +++++++++++++++++++++++++++++++-
 1 file changed, 47 insertions(+), 1 deletion(-)

diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs
index e982842f5363f..001bf27afb9cc 100644
--- a/compiler/rustc_lint/src/types.rs
+++ b/compiler/rustc_lint/src/types.rs
@@ -1099,6 +1099,32 @@ fn get_nullable_type<'tcx>(
     })
 }
 
+/// A type is niche_optimization_candiate iff:
+/// - Is a zero-sized type with alignment 1 (a “1-ZST”).
+/// - Has no fields.
+/// - Does not have the #[non_exhaustive] attribute.
+fn is_niche_optimization_candidate<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    param_env: ty::ParamEnv<'tcx>,
+    ty: Ty<'tcx>,
+) -> bool {
+    if !tcx.layout_of(param_env.and(ty)).is_ok_and(|layout| layout.is_1zst()) {
+        return false;
+    }
+
+    match ty.kind() {
+        ty::Adt(ty_def, _) => {
+            let non_exhaustive = ty_def.is_variant_list_non_exhaustive()
+                || ty_def.variants().iter().any(|variant| variant.is_field_list_non_exhaustive());
+            let contains_no_fields = ty_def.all_fields().next().is_none();
+
+            !non_exhaustive && contains_no_fields
+        }
+        ty::Tuple(tys) => tys.is_empty(),
+        _ => false,
+    }
+}
+
 /// Check if this enum can be safely exported based on the "nullable pointer optimization". If it
 /// can, return the type that `ty` can be safely converted to, otherwise return `None`.
 /// Currently restricted to function pointers, boxes, references, `core::num::NonZero`,
@@ -1115,6 +1141,26 @@ pub(crate) fn repr_nullable_ptr<'tcx>(
         let field_ty = match &ty_def.variants().raw[..] {
             [var_one, var_two] => match (&var_one.fields.raw[..], &var_two.fields.raw[..]) {
                 ([], [field]) | ([field], []) => field.ty(tcx, args),
+                ([field1], [field2]) => {
+                    // TODO: We pass all the checks here although individual enum variants has
+                    // checks for FFI safety even when niche optimized which needs to be
+                    // suppressed. for types like `Result<PhantomData<()>, E>`, PhantomData has
+                    // it's own lint for FFI which needs to be suppressed: `composed only of
+                    // `PhantomData``. This is true for other custom types as well `struct
+                    // Example;` which emits `this struct has unspecified layout` and suggests to
+                    // add `#[repr(C)]` and when that is done, linter emits `this struct has no
+                    // fields`, all under the `improper_ctypes_definitions` lint group
+                    let ty1 = field1.ty(tcx, args);
+                    let ty2 = field2.ty(tcx, args);
+
+                    if is_niche_optimization_candidate(tcx, param_env, ty1) {
+                        ty2
+                    } else if is_niche_optimization_candidate(tcx, param_env, ty2) {
+                        ty1
+                    } else {
+                        return None;
+                    }
+                }
                 _ => return None,
             },
             _ => return None,
@@ -1331,7 +1377,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
                         // discriminant.
                         if !def.repr().c() && !def.repr().transparent() && def.repr().int.is_none()
                         {
-                            // Special-case types like `Option<extern fn()>`.
+                            // Special-case types like `Option<extern fn()>` and `Result<extern fn(), ()>`
                             if repr_nullable_ptr(self.cx.tcx, self.cx.param_env, ty, self.mode)
                                 .is_none()
                             {

From b3e6d52e49345db9e59c955b79ca3ea7cf4f7afc Mon Sep 17 00:00:00 2001
From: Arvind Mukund <armu30@gmail.com>
Date: Sat, 9 Mar 2024 12:35:17 -0800
Subject: [PATCH 2/9] We don't need to check for non-exhaustive fields

Fields are disallowed so checking the top attribute is enough.
---
 compiler/rustc_lint/src/types.rs | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs
index 001bf27afb9cc..ae118ffbf4c38 100644
--- a/compiler/rustc_lint/src/types.rs
+++ b/compiler/rustc_lint/src/types.rs
@@ -1114,8 +1114,7 @@ fn is_niche_optimization_candidate<'tcx>(
 
     match ty.kind() {
         ty::Adt(ty_def, _) => {
-            let non_exhaustive = ty_def.is_variant_list_non_exhaustive()
-                || ty_def.variants().iter().any(|variant| variant.is_field_list_non_exhaustive());
+            let non_exhaustive = ty_def.is_variant_list_non_exhaustive();
             let contains_no_fields = ty_def.all_fields().next().is_none();
 
             !non_exhaustive && contains_no_fields

From 08b85a1c5381cfc9c62347996b4b5c0316522b60 Mon Sep 17 00:00:00 2001
From: Arvind Mukund <armu30@gmail.com>
Date: Sat, 9 Mar 2024 14:30:01 -0800
Subject: [PATCH 3/9] Don't lint niche optimized variants in enums

---
 compiler/rustc_lint/src/types.rs | 33 +++++++++++++-------------------
 1 file changed, 13 insertions(+), 20 deletions(-)

diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs
index ae118ffbf4c38..1fd358836a2cf 100644
--- a/compiler/rustc_lint/src/types.rs
+++ b/compiler/rustc_lint/src/types.rs
@@ -1141,14 +1141,6 @@ pub(crate) fn repr_nullable_ptr<'tcx>(
             [var_one, var_two] => match (&var_one.fields.raw[..], &var_two.fields.raw[..]) {
                 ([], [field]) | ([field], []) => field.ty(tcx, args),
                 ([field1], [field2]) => {
-                    // TODO: We pass all the checks here although individual enum variants has
-                    // checks for FFI safety even when niche optimized which needs to be
-                    // suppressed. for types like `Result<PhantomData<()>, E>`, PhantomData has
-                    // it's own lint for FFI which needs to be suppressed: `composed only of
-                    // `PhantomData``. This is true for other custom types as well `struct
-                    // Example;` which emits `this struct has unspecified layout` and suggests to
-                    // add `#[repr(C)]` and when that is done, linter emits `this struct has no
-                    // fields`, all under the `improper_ctypes_definitions` lint group
                     let ty1 = field1.ty(tcx, args);
                     let ty2 = field2.ty(tcx, args);
 
@@ -1245,7 +1237,6 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
         args: GenericArgsRef<'tcx>,
     ) -> FfiResult<'tcx> {
         use FfiResult::*;
-
         let transparent_with_all_zst_fields = if def.repr().transparent() {
             if let Some(field) = transparent_newtype_field(self.cx.tcx, variant) {
                 // Transparent newtypes have at most one non-ZST field which needs to be checked..
@@ -1372,27 +1363,29 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
                             return FfiSafe;
                         }
 
+                        if def.is_variant_list_non_exhaustive() && !def.did().is_local() {
+                            return FfiUnsafe {
+                                ty,
+                                reason: fluent::lint_improper_ctypes_non_exhaustive,
+                                help: None,
+                            };
+                        }
+
                         // Check for a repr() attribute to specify the size of the
                         // discriminant.
                         if !def.repr().c() && !def.repr().transparent() && def.repr().int.is_none()
                         {
                             // Special-case types like `Option<extern fn()>` and `Result<extern fn(), ()>`
-                            if repr_nullable_ptr(self.cx.tcx, self.cx.param_env, ty, self.mode)
-                                .is_none()
+                            if let Some(ty) =
+                                repr_nullable_ptr(self.cx.tcx, self.cx.param_env, ty, self.mode)
                             {
-                                return FfiUnsafe {
-                                    ty,
-                                    reason: fluent::lint_improper_ctypes_enum_repr_reason,
-                                    help: Some(fluent::lint_improper_ctypes_enum_repr_help),
-                                };
+                                return self.check_type_for_ffi(cache, ty);
                             }
-                        }
 
-                        if def.is_variant_list_non_exhaustive() && !def.did().is_local() {
                             return FfiUnsafe {
                                 ty,
-                                reason: fluent::lint_improper_ctypes_non_exhaustive,
-                                help: None,
+                                reason: fluent::lint_improper_ctypes_enum_repr_reason,
+                                help: Some(fluent::lint_improper_ctypes_enum_repr_help),
                             };
                         }
 

From 223d5eb64f492a41801396e34e714a657d020ac6 Mon Sep 17 00:00:00 2001
From: Arvind Mukund <armu30@gmail.com>
Date: Sat, 9 Mar 2024 14:34:08 -0800
Subject: [PATCH 4/9] Add tests

Tests both `T` and `E` for niche variant optimization lints
---
 tests/ui/lint/lint-ctypes-enum.rs     | 144 +++++++++++++++-----
 tests/ui/lint/lint-ctypes-enum.stderr | 183 ++++++++++++++++++++++----
 2 files changed, 270 insertions(+), 57 deletions(-)

diff --git a/tests/ui/lint/lint-ctypes-enum.rs b/tests/ui/lint/lint-ctypes-enum.rs
index c60290f8553a7..8d60a8dd3171f 100644
--- a/tests/ui/lint/lint-ctypes-enum.rs
+++ b/tests/ui/lint/lint-ctypes-enum.rs
@@ -55,38 +55,120 @@ union TransparentUnion<T: Copy> {
 
 struct Rust<T>(T);
 
+struct NoField;
+
+#[repr(transparent)]
+struct Field(());
+
+#[non_exhaustive]
+enum NonExhaustive {}
+
 extern "C" {
-   fn zf(x: Z);
-   fn uf(x: U); //~ ERROR `extern` block uses type `U`
-   fn bf(x: B); //~ ERROR `extern` block uses type `B`
-   fn tf(x: T); //~ ERROR `extern` block uses type `T`
-   fn repr_c(x: ReprC);
-   fn repr_u8(x: U8);
-   fn repr_isize(x: Isize);
-   fn option_ref(x: Option<&'static u8>);
-   fn option_fn(x: Option<extern "C" fn()>);
-   fn nonnull(x: Option<std::ptr::NonNull<u8>>);
-   fn unique(x: Option<std::ptr::Unique<u8>>);
-   fn nonzero_u8(x: Option<num::NonZero<u8>>);
-   fn nonzero_u16(x: Option<num::NonZero<u16>>);
-   fn nonzero_u32(x: Option<num::NonZero<u32>>);
-   fn nonzero_u64(x: Option<num::NonZero<u64>>);
-   fn nonzero_u128(x: Option<num::NonZero<u128>>);
-   //~^ ERROR `extern` block uses type `u128`
-   fn nonzero_usize(x: Option<num::NonZero<usize>>);
-   fn nonzero_i8(x: Option<num::NonZero<i8>>);
-   fn nonzero_i16(x: Option<num::NonZero<i16>>);
-   fn nonzero_i32(x: Option<num::NonZero<i32>>);
-   fn nonzero_i64(x: Option<num::NonZero<i64>>);
-   fn nonzero_i128(x: Option<num::NonZero<i128>>);
-   //~^ ERROR `extern` block uses type `i128`
-   fn nonzero_isize(x: Option<num::NonZero<isize>>);
-   fn transparent_struct(x: Option<TransparentStruct<num::NonZero<u8>>>);
-   fn transparent_enum(x: Option<TransparentEnum<num::NonZero<u8>>>);
-   fn transparent_union(x: Option<TransparentUnion<num::NonZero<u8>>>);
-   //~^ ERROR `extern` block uses type
-   fn repr_rust(x: Option<Rust<num::NonZero<u8>>>); //~ ERROR `extern` block uses type
-   fn no_result(x: Result<(), num::NonZero<i32>>); //~ ERROR `extern` block uses type
+    fn zf(x: Z);
+    fn uf(x: U); //~ ERROR `extern` block uses type `U`
+    fn bf(x: B); //~ ERROR `extern` block uses type `B`
+    fn tf(x: T); //~ ERROR `extern` block uses type `T`
+    fn repr_c(x: ReprC);
+    fn repr_u8(x: U8);
+    fn repr_isize(x: Isize);
+    fn option_ref(x: Option<&'static u8>);
+    fn option_fn(x: Option<extern "C" fn()>);
+    fn option_nonnull(x: Option<std::ptr::NonNull<u8>>);
+    fn option_unique(x: Option<std::ptr::Unique<u8>>);
+    fn option_nonzero_u8(x: Option<num::NonZero<u8>>);
+    fn option_nonzero_u16(x: Option<num::NonZero<u16>>);
+    fn option_nonzero_u32(x: Option<num::NonZero<u32>>);
+    fn option_nonzero_u64(x: Option<num::NonZero<u64>>);
+    fn option_nonzero_u128(x: Option<num::NonZero<u128>>);
+    //~^ ERROR `extern` block uses type `u128`
+    fn option_nonzero_usize(x: Option<num::NonZero<usize>>);
+    fn option_nonzero_i8(x: Option<num::NonZero<i8>>);
+    fn option_nonzero_i16(x: Option<num::NonZero<i16>>);
+    fn option_nonzero_i32(x: Option<num::NonZero<i32>>);
+    fn option_nonzero_i64(x: Option<num::NonZero<i64>>);
+    fn option_nonzero_i128(x: Option<num::NonZero<i128>>);
+    //~^ ERROR `extern` block uses type `i128`
+    fn option_nonzero_isize(x: Option<num::NonZero<isize>>);
+    fn option_transparent_struct(x: Option<TransparentStruct<num::NonZero<u8>>>);
+    fn option_transparent_enum(x: Option<TransparentEnum<num::NonZero<u8>>>);
+    fn option_transparent_union(x: Option<TransparentUnion<num::NonZero<u8>>>);
+    //~^ ERROR `extern` block uses type
+    fn option_repr_rust(x: Option<Rust<num::NonZero<u8>>>); //~ ERROR `extern` block uses type
+
+    fn result_ref_t(x: Result<&'static u8, ()>);
+    fn result_fn_t(x: Result<extern "C" fn(), ()>);
+    fn result_nonnull_t(x: Result<std::ptr::NonNull<u8>, ()>);
+    fn result_unique_t(x: Result<std::ptr::Unique<u8>, ()>);
+    fn result_nonzero_u8_t(x: Result<num::NonZero<u8>, ()>);
+    fn result_nonzero_u16_t(x: Result<num::NonZero<u16>, ()>);
+    fn result_nonzero_u32_t(x: Result<num::NonZero<u32>, ()>);
+    fn result_nonzero_u64_t(x: Result<num::NonZero<u64>, ()>);
+    fn result_nonzero_u128_t(x: Result<num::NonZero<u128>, ()>);
+    //~^ ERROR `extern` block uses type `u128`
+    fn result_nonzero_usize_t(x: Result<num::NonZero<usize>, ()>);
+    fn result_nonzero_i8_t(x: Result<num::NonZero<i8>, ()>);
+    fn result_nonzero_i16_t(x: Result<num::NonZero<i16>, ()>);
+    fn result_nonzero_i32_t(x: Result<num::NonZero<i32>, ()>);
+    fn result_nonzero_i64_t(x: Result<num::NonZero<i64>, ()>);
+    fn result_nonzero_i128_t(x: Result<num::NonZero<i128>, ()>);
+    //~^ ERROR `extern` block uses type `i128`
+    fn result_nonzero_isize_t(x: Result<num::NonZero<isize>, ()>);
+    fn result_transparent_struct_t(x: Result<TransparentStruct<num::NonZero<u8>>, ()>);
+    fn result_transparent_enum_t(x: Result<TransparentEnum<num::NonZero<u8>>, ()>);
+    fn result_transparent_union_t(x: Result<TransparentUnion<num::NonZero<u8>>, ()>);
+    //~^ ERROR `extern` block uses type
+    fn result_repr_rust_t(x: Result<Rust<num::NonZero<u8>>, ()>);
+    //~^ ERROR `extern` block uses type
+    fn result_phantom_t(x: Result<num::NonZero<u8>, std::marker::PhantomData<()>>);
+    fn result_1zst_exhaustive_no_variant_t(x: Result<num::NonZero<u8>, Z>);
+    fn result_1zst_exhaustive_single_variant_t(x: Result<num::NonZero<u8>, U>);
+    fn result_1zst_exhaustive_multiple_variant_t(x: Result<num::NonZero<u8>, B>);
+    //~^ ERROR `extern` block uses type
+    fn result_1zst_non_exhaustive_no_variant_t(x: Result<num::NonZero<u8>, NonExhaustive>);
+    //~^ ERROR `extern` block uses type
+    fn result_1zst_exhaustive_no_field_t(x: Result<num::NonZero<u8>, NoField>);
+    fn result_1zst_exhaustive_single_field_t(x: Result<num::NonZero<u8>, Field>);
+    //~^ ERROR `extern` block uses type
+    fn result_cascading_t(x: Result<Result<(), num::NonZero<u8>>, ()>);
+    //~^ ERROR `extern` block uses type
+
+    fn result_ref_e(x: Result<(), &'static u8>);
+    fn result_fn_e(x: Result<(), extern "C" fn()>);
+    fn result_nonnull_e(x: Result<(), std::ptr::NonNull<u8>>);
+    fn result_unique_e(x: Result<(), std::ptr::Unique<u8>>);
+    fn result_nonzero_u8_e(x: Result<(), num::NonZero<u8>>);
+    fn result_nonzero_u16_e(x: Result<(), num::NonZero<u16>>);
+    fn result_nonzero_u32_e(x: Result<(), num::NonZero<u32>>);
+    fn result_nonzero_u64_e(x: Result<(), num::NonZero<u64>>);
+    fn result_nonzero_u128_e(x: Result<(), num::NonZero<u128>>);
+    //~^ ERROR `extern` block uses type `u128`
+    fn result_nonzero_usize_e(x: Result<(), num::NonZero<usize>>);
+    fn result_nonzero_i8_e(x: Result<(), num::NonZero<i8>>);
+    fn result_nonzero_i16_e(x: Result<(), num::NonZero<i16>>);
+    fn result_nonzero_i32_e(x: Result<(), num::NonZero<i32>>);
+    fn result_nonzero_i64_e(x: Result<(), num::NonZero<i64>>);
+    fn result_nonzero_i128_e(x: Result<(), num::NonZero<i128>>);
+    //~^ ERROR `extern` block uses type `i128`
+    fn result_nonzero_isize_e(x: Result<(), num::NonZero<isize>>);
+    fn result_transparent_struct_e(x: Result<(), TransparentStruct<num::NonZero<u8>>>);
+    fn result_transparent_enum_e(x: Result<(), TransparentEnum<num::NonZero<u8>>>);
+    fn result_transparent_union_e(x: Result<(), TransparentUnion<num::NonZero<u8>>>);
+    //~^ ERROR `extern` block uses type
+    fn result_repr_rust_e(x: Result<(), Rust<num::NonZero<u8>>>);
+    //~^ ERROR `extern` block uses type
+    fn result_phantom_e(x: Result<num::NonZero<u8>, std::marker::PhantomData<()>>);
+    fn result_1zst_exhaustive_no_variant_e(x: Result<Z, num::NonZero<u8>>);
+    fn result_1zst_exhaustive_single_variant_e(x: Result<U, num::NonZero<u8>>);
+    fn result_1zst_exhaustive_multiple_variant_e(x: Result<B, num::NonZero<u8>>);
+    //~^ ERROR `extern` block uses type
+    fn result_1zst_non_exhaustive_no_variant_e(x: Result<NonExhaustive, num::NonZero<u8>>);
+    //~^ ERROR `extern` block uses type
+    fn result_1zst_exhaustive_no_field_e(x: Result<NoField, num::NonZero<u8>>);
+    fn result_1zst_exhaustive_single_field_e(x: Result<Field, num::NonZero<u8>>);
+    //~^ ERROR `extern` block uses type
+    fn result_cascading_e(x: Result<(), Result<(), num::NonZero<u8>>>);
+    //~^ ERROR `extern` block uses type
+
 }
 
 pub fn main() {}
diff --git a/tests/ui/lint/lint-ctypes-enum.stderr b/tests/ui/lint/lint-ctypes-enum.stderr
index 103fda8d40253..c982f040fb6fb 100644
--- a/tests/ui/lint/lint-ctypes-enum.stderr
+++ b/tests/ui/lint/lint-ctypes-enum.stderr
@@ -1,8 +1,8 @@
 error: `extern` block uses type `U`, which is not FFI-safe
-  --> $DIR/lint-ctypes-enum.rs:60:13
+  --> $DIR/lint-ctypes-enum.rs:68:14
    |
-LL |    fn uf(x: U);
-   |             ^ not FFI-safe
+LL |     fn uf(x: U);
+   |              ^ not FFI-safe
    |
    = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
    = note: enum has no representation hint
@@ -18,10 +18,10 @@ LL | #![deny(improper_ctypes)]
    |         ^^^^^^^^^^^^^^^
 
 error: `extern` block uses type `B`, which is not FFI-safe
-  --> $DIR/lint-ctypes-enum.rs:61:13
+  --> $DIR/lint-ctypes-enum.rs:69:14
    |
-LL |    fn bf(x: B);
-   |             ^ not FFI-safe
+LL |     fn bf(x: B);
+   |              ^ not FFI-safe
    |
    = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
    = note: enum has no representation hint
@@ -32,10 +32,10 @@ LL | enum B {
    | ^^^^^^
 
 error: `extern` block uses type `T`, which is not FFI-safe
-  --> $DIR/lint-ctypes-enum.rs:62:13
+  --> $DIR/lint-ctypes-enum.rs:70:14
    |
-LL |    fn tf(x: T);
-   |             ^ not FFI-safe
+LL |     fn tf(x: T);
+   |              ^ not FFI-safe
    |
    = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
    = note: enum has no representation hint
@@ -46,47 +46,178 @@ LL | enum T {
    | ^^^^^^
 
 error: `extern` block uses type `u128`, which is not FFI-safe
-  --> $DIR/lint-ctypes-enum.rs:74:23
+  --> $DIR/lint-ctypes-enum.rs:82:31
    |
-LL |    fn nonzero_u128(x: Option<num::NonZero<u128>>);
-   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
+LL |     fn option_nonzero_u128(x: Option<num::NonZero<u128>>);
+   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
    |
    = note: 128-bit integers don't currently have a known stable ABI
 
 error: `extern` block uses type `i128`, which is not FFI-safe
-  --> $DIR/lint-ctypes-enum.rs:81:23
+  --> $DIR/lint-ctypes-enum.rs:89:31
    |
-LL |    fn nonzero_i128(x: Option<num::NonZero<i128>>);
-   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
+LL |     fn option_nonzero_i128(x: Option<num::NonZero<i128>>);
+   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
    |
    = note: 128-bit integers don't currently have a known stable ABI
 
 error: `extern` block uses type `Option<TransparentUnion<NonZero<u8>>>`, which is not FFI-safe
-  --> $DIR/lint-ctypes-enum.rs:86:28
+  --> $DIR/lint-ctypes-enum.rs:94:36
    |
-LL |    fn transparent_union(x: Option<TransparentUnion<num::NonZero<u8>>>);
-   |                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
+LL |     fn option_transparent_union(x: Option<TransparentUnion<num::NonZero<u8>>>);
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
    |
    = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
    = note: enum has no representation hint
 
 error: `extern` block uses type `Option<Rust<NonZero<u8>>>`, which is not FFI-safe
-  --> $DIR/lint-ctypes-enum.rs:88:20
+  --> $DIR/lint-ctypes-enum.rs:96:28
    |
-LL |    fn repr_rust(x: Option<Rust<num::NonZero<u8>>>);
-   |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
+LL |     fn option_repr_rust(x: Option<Rust<num::NonZero<u8>>>);
+   |                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
    |
    = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
    = note: enum has no representation hint
 
-error: `extern` block uses type `Result<(), NonZero<i32>>`, which is not FFI-safe
-  --> $DIR/lint-ctypes-enum.rs:89:20
+error: `extern` block uses type `u128`, which is not FFI-safe
+  --> $DIR/lint-ctypes-enum.rs:106:33
+   |
+LL |     fn result_nonzero_u128_t(x: Result<num::NonZero<u128>, ()>);
+   |                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
+   |
+   = note: 128-bit integers don't currently have a known stable ABI
+
+error: `extern` block uses type `i128`, which is not FFI-safe
+  --> $DIR/lint-ctypes-enum.rs:113:33
+   |
+LL |     fn result_nonzero_i128_t(x: Result<num::NonZero<i128>, ()>);
+   |                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
+   |
+   = note: 128-bit integers don't currently have a known stable ABI
+
+error: `extern` block uses type `Result<TransparentUnion<NonZero<u8>>, ()>`, which is not FFI-safe
+  --> $DIR/lint-ctypes-enum.rs:118:38
+   |
+LL |     fn result_transparent_union_t(x: Result<TransparentUnion<num::NonZero<u8>>, ()>);
+   |                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
+   |
+   = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
+   = note: enum has no representation hint
+
+error: `extern` block uses type `Result<Rust<NonZero<u8>>, ()>`, which is not FFI-safe
+  --> $DIR/lint-ctypes-enum.rs:120:30
+   |
+LL |     fn result_repr_rust_t(x: Result<Rust<num::NonZero<u8>>, ()>);
+   |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
+   |
+   = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
+   = note: enum has no representation hint
+
+error: `extern` block uses type `Result<NonZero<u8>, B>`, which is not FFI-safe
+  --> $DIR/lint-ctypes-enum.rs:125:53
+   |
+LL |     fn result_1zst_exhaustive_multiple_variant_t(x: Result<num::NonZero<u8>, B>);
+   |                                                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
+   |
+   = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
+   = note: enum has no representation hint
+
+error: `extern` block uses type `Result<NonZero<u8>, NonExhaustive>`, which is not FFI-safe
+  --> $DIR/lint-ctypes-enum.rs:127:51
+   |
+LL |     fn result_1zst_non_exhaustive_no_variant_t(x: Result<num::NonZero<u8>, NonExhaustive>);
+   |                                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
+   |
+   = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
+   = note: enum has no representation hint
+
+error: `extern` block uses type `Result<NonZero<u8>, Field>`, which is not FFI-safe
+  --> $DIR/lint-ctypes-enum.rs:130:49
+   |
+LL |     fn result_1zst_exhaustive_single_field_t(x: Result<num::NonZero<u8>, Field>);
+   |                                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
+   |
+   = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
+   = note: enum has no representation hint
+
+error: `extern` block uses type `Result<Result<(), NonZero<u8>>, ()>`, which is not FFI-safe
+  --> $DIR/lint-ctypes-enum.rs:132:30
+   |
+LL |     fn result_cascading_t(x: Result<Result<(), num::NonZero<u8>>, ()>);
+   |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
+   |
+   = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
+   = note: enum has no representation hint
+
+error: `extern` block uses type `u128`, which is not FFI-safe
+  --> $DIR/lint-ctypes-enum.rs:143:33
+   |
+LL |     fn result_nonzero_u128_e(x: Result<(), num::NonZero<u128>>);
+   |                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
+   |
+   = note: 128-bit integers don't currently have a known stable ABI
+
+error: `extern` block uses type `i128`, which is not FFI-safe
+  --> $DIR/lint-ctypes-enum.rs:150:33
+   |
+LL |     fn result_nonzero_i128_e(x: Result<(), num::NonZero<i128>>);
+   |                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
+   |
+   = note: 128-bit integers don't currently have a known stable ABI
+
+error: `extern` block uses type `Result<(), TransparentUnion<NonZero<u8>>>`, which is not FFI-safe
+  --> $DIR/lint-ctypes-enum.rs:155:38
+   |
+LL |     fn result_transparent_union_e(x: Result<(), TransparentUnion<num::NonZero<u8>>>);
+   |                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
+   |
+   = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
+   = note: enum has no representation hint
+
+error: `extern` block uses type `Result<(), Rust<NonZero<u8>>>`, which is not FFI-safe
+  --> $DIR/lint-ctypes-enum.rs:157:30
+   |
+LL |     fn result_repr_rust_e(x: Result<(), Rust<num::NonZero<u8>>>);
+   |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
+   |
+   = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
+   = note: enum has no representation hint
+
+error: `extern` block uses type `Result<B, NonZero<u8>>`, which is not FFI-safe
+  --> $DIR/lint-ctypes-enum.rs:162:53
+   |
+LL |     fn result_1zst_exhaustive_multiple_variant_e(x: Result<B, num::NonZero<u8>>);
+   |                                                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
+   |
+   = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
+   = note: enum has no representation hint
+
+error: `extern` block uses type `Result<NonExhaustive, NonZero<u8>>`, which is not FFI-safe
+  --> $DIR/lint-ctypes-enum.rs:164:51
+   |
+LL |     fn result_1zst_non_exhaustive_no_variant_e(x: Result<NonExhaustive, num::NonZero<u8>>);
+   |                                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
+   |
+   = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
+   = note: enum has no representation hint
+
+error: `extern` block uses type `Result<Field, NonZero<u8>>`, which is not FFI-safe
+  --> $DIR/lint-ctypes-enum.rs:167:49
+   |
+LL |     fn result_1zst_exhaustive_single_field_e(x: Result<Field, num::NonZero<u8>>);
+   |                                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
+   |
+   = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
+   = note: enum has no representation hint
+
+error: `extern` block uses type `Result<(), Result<(), NonZero<u8>>>`, which is not FFI-safe
+  --> $DIR/lint-ctypes-enum.rs:169:30
    |
-LL |    fn no_result(x: Result<(), num::NonZero<i32>>);
-   |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
+LL |     fn result_cascading_e(x: Result<(), Result<(), num::NonZero<u8>>>);
+   |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
    |
    = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
    = note: enum has no representation hint
 
-error: aborting due to 8 previous errors
+error: aborting due to 23 previous errors
 

From 014ddac9c98d827237c1179050e5f96312884254 Mon Sep 17 00:00:00 2001
From: Arvind Mukund <armu30@gmail.com>
Date: Sat, 9 Mar 2024 15:13:29 -0800
Subject: [PATCH 5/9] Disallow single-variant enums

Couldn't find documentation supporting that single-variant
`#[repr(Rust)]` enums with RHS assigned work as expected with this
change.

```rust
enum Variants {
  A = 17,
} // Would this be zero sized optimized guaranteed?
```
---
 compiler/rustc_lint/src/types.rs      | 10 +++---
 tests/ui/lint/lint-ctypes-enum.rs     |  2 ++
 tests/ui/lint/lint-ctypes-enum.stderr | 44 +++++++++++++++++++--------
 3 files changed, 39 insertions(+), 17 deletions(-)

diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs
index 1fd358836a2cf..d491de7609beb 100644
--- a/compiler/rustc_lint/src/types.rs
+++ b/compiler/rustc_lint/src/types.rs
@@ -1102,22 +1102,24 @@ fn get_nullable_type<'tcx>(
 /// A type is niche_optimization_candiate iff:
 /// - Is a zero-sized type with alignment 1 (a “1-ZST”).
 /// - Has no fields.
-/// - Does not have the #[non_exhaustive] attribute.
+/// - Does not have the `#[non_exhaustive]` attribute.
 fn is_niche_optimization_candidate<'tcx>(
     tcx: TyCtxt<'tcx>,
     param_env: ty::ParamEnv<'tcx>,
     ty: Ty<'tcx>,
 ) -> bool {
-    if !tcx.layout_of(param_env.and(ty)).is_ok_and(|layout| layout.is_1zst()) {
+    if tcx.layout_of(param_env.and(ty)).is_ok_and(|layout| !layout.is_1zst()) {
         return false;
     }
 
     match ty.kind() {
         ty::Adt(ty_def, _) => {
             let non_exhaustive = ty_def.is_variant_list_non_exhaustive();
-            let contains_no_fields = ty_def.all_fields().next().is_none();
+            // Should single-variant enums be allowed?
+            let empty = (ty_def.is_struct() && ty_def.all_fields().next().is_none())
+                || (ty_def.is_enum() && ty_def.variants().is_empty());
 
-            !non_exhaustive && contains_no_fields
+            !non_exhaustive && empty
         }
         ty::Tuple(tys) => tys.is_empty(),
         _ => false,
diff --git a/tests/ui/lint/lint-ctypes-enum.rs b/tests/ui/lint/lint-ctypes-enum.rs
index 8d60a8dd3171f..b69ee82f8aeb1 100644
--- a/tests/ui/lint/lint-ctypes-enum.rs
+++ b/tests/ui/lint/lint-ctypes-enum.rs
@@ -122,6 +122,7 @@ extern "C" {
     fn result_phantom_t(x: Result<num::NonZero<u8>, std::marker::PhantomData<()>>);
     fn result_1zst_exhaustive_no_variant_t(x: Result<num::NonZero<u8>, Z>);
     fn result_1zst_exhaustive_single_variant_t(x: Result<num::NonZero<u8>, U>);
+    //~^ ERROR `extern` block uses type
     fn result_1zst_exhaustive_multiple_variant_t(x: Result<num::NonZero<u8>, B>);
     //~^ ERROR `extern` block uses type
     fn result_1zst_non_exhaustive_no_variant_t(x: Result<num::NonZero<u8>, NonExhaustive>);
@@ -159,6 +160,7 @@ extern "C" {
     fn result_phantom_e(x: Result<num::NonZero<u8>, std::marker::PhantomData<()>>);
     fn result_1zst_exhaustive_no_variant_e(x: Result<Z, num::NonZero<u8>>);
     fn result_1zst_exhaustive_single_variant_e(x: Result<U, num::NonZero<u8>>);
+    //~^ ERROR `extern` block uses type
     fn result_1zst_exhaustive_multiple_variant_e(x: Result<B, num::NonZero<u8>>);
     //~^ ERROR `extern` block uses type
     fn result_1zst_non_exhaustive_no_variant_e(x: Result<NonExhaustive, num::NonZero<u8>>);
diff --git a/tests/ui/lint/lint-ctypes-enum.stderr b/tests/ui/lint/lint-ctypes-enum.stderr
index c982f040fb6fb..ab1eb67c07510 100644
--- a/tests/ui/lint/lint-ctypes-enum.stderr
+++ b/tests/ui/lint/lint-ctypes-enum.stderr
@@ -113,8 +113,17 @@ LL |     fn result_repr_rust_t(x: Result<Rust<num::NonZero<u8>>, ()>);
    = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
    = note: enum has no representation hint
 
+error: `extern` block uses type `Result<NonZero<u8>, U>`, which is not FFI-safe
+  --> $DIR/lint-ctypes-enum.rs:124:51
+   |
+LL |     fn result_1zst_exhaustive_single_variant_t(x: Result<num::NonZero<u8>, U>);
+   |                                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
+   |
+   = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
+   = note: enum has no representation hint
+
 error: `extern` block uses type `Result<NonZero<u8>, B>`, which is not FFI-safe
-  --> $DIR/lint-ctypes-enum.rs:125:53
+  --> $DIR/lint-ctypes-enum.rs:126:53
    |
 LL |     fn result_1zst_exhaustive_multiple_variant_t(x: Result<num::NonZero<u8>, B>);
    |                                                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@@ -123,7 +132,7 @@ LL |     fn result_1zst_exhaustive_multiple_variant_t(x: Result<num::NonZero<u8>
    = note: enum has no representation hint
 
 error: `extern` block uses type `Result<NonZero<u8>, NonExhaustive>`, which is not FFI-safe
-  --> $DIR/lint-ctypes-enum.rs:127:51
+  --> $DIR/lint-ctypes-enum.rs:128:51
    |
 LL |     fn result_1zst_non_exhaustive_no_variant_t(x: Result<num::NonZero<u8>, NonExhaustive>);
    |                                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@@ -132,7 +141,7 @@ LL |     fn result_1zst_non_exhaustive_no_variant_t(x: Result<num::NonZero<u8>,
    = note: enum has no representation hint
 
 error: `extern` block uses type `Result<NonZero<u8>, Field>`, which is not FFI-safe
-  --> $DIR/lint-ctypes-enum.rs:130:49
+  --> $DIR/lint-ctypes-enum.rs:131:49
    |
 LL |     fn result_1zst_exhaustive_single_field_t(x: Result<num::NonZero<u8>, Field>);
    |                                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@@ -141,7 +150,7 @@ LL |     fn result_1zst_exhaustive_single_field_t(x: Result<num::NonZero<u8>, Fi
    = note: enum has no representation hint
 
 error: `extern` block uses type `Result<Result<(), NonZero<u8>>, ()>`, which is not FFI-safe
-  --> $DIR/lint-ctypes-enum.rs:132:30
+  --> $DIR/lint-ctypes-enum.rs:133:30
    |
 LL |     fn result_cascading_t(x: Result<Result<(), num::NonZero<u8>>, ()>);
    |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@@ -150,7 +159,7 @@ LL |     fn result_cascading_t(x: Result<Result<(), num::NonZero<u8>>, ()>);
    = note: enum has no representation hint
 
 error: `extern` block uses type `u128`, which is not FFI-safe
-  --> $DIR/lint-ctypes-enum.rs:143:33
+  --> $DIR/lint-ctypes-enum.rs:144:33
    |
 LL |     fn result_nonzero_u128_e(x: Result<(), num::NonZero<u128>>);
    |                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@@ -158,7 +167,7 @@ LL |     fn result_nonzero_u128_e(x: Result<(), num::NonZero<u128>>);
    = note: 128-bit integers don't currently have a known stable ABI
 
 error: `extern` block uses type `i128`, which is not FFI-safe
-  --> $DIR/lint-ctypes-enum.rs:150:33
+  --> $DIR/lint-ctypes-enum.rs:151:33
    |
 LL |     fn result_nonzero_i128_e(x: Result<(), num::NonZero<i128>>);
    |                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@@ -166,7 +175,7 @@ LL |     fn result_nonzero_i128_e(x: Result<(), num::NonZero<i128>>);
    = note: 128-bit integers don't currently have a known stable ABI
 
 error: `extern` block uses type `Result<(), TransparentUnion<NonZero<u8>>>`, which is not FFI-safe
-  --> $DIR/lint-ctypes-enum.rs:155:38
+  --> $DIR/lint-ctypes-enum.rs:156:38
    |
 LL |     fn result_transparent_union_e(x: Result<(), TransparentUnion<num::NonZero<u8>>>);
    |                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@@ -175,7 +184,7 @@ LL |     fn result_transparent_union_e(x: Result<(), TransparentUnion<num::NonZe
    = note: enum has no representation hint
 
 error: `extern` block uses type `Result<(), Rust<NonZero<u8>>>`, which is not FFI-safe
-  --> $DIR/lint-ctypes-enum.rs:157:30
+  --> $DIR/lint-ctypes-enum.rs:158:30
    |
 LL |     fn result_repr_rust_e(x: Result<(), Rust<num::NonZero<u8>>>);
    |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@@ -183,8 +192,17 @@ LL |     fn result_repr_rust_e(x: Result<(), Rust<num::NonZero<u8>>>);
    = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
    = note: enum has no representation hint
 
+error: `extern` block uses type `Result<U, NonZero<u8>>`, which is not FFI-safe
+  --> $DIR/lint-ctypes-enum.rs:162:51
+   |
+LL |     fn result_1zst_exhaustive_single_variant_e(x: Result<U, num::NonZero<u8>>);
+   |                                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
+   |
+   = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
+   = note: enum has no representation hint
+
 error: `extern` block uses type `Result<B, NonZero<u8>>`, which is not FFI-safe
-  --> $DIR/lint-ctypes-enum.rs:162:53
+  --> $DIR/lint-ctypes-enum.rs:164:53
    |
 LL |     fn result_1zst_exhaustive_multiple_variant_e(x: Result<B, num::NonZero<u8>>);
    |                                                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@@ -193,7 +211,7 @@ LL |     fn result_1zst_exhaustive_multiple_variant_e(x: Result<B, num::NonZero<
    = note: enum has no representation hint
 
 error: `extern` block uses type `Result<NonExhaustive, NonZero<u8>>`, which is not FFI-safe
-  --> $DIR/lint-ctypes-enum.rs:164:51
+  --> $DIR/lint-ctypes-enum.rs:166:51
    |
 LL |     fn result_1zst_non_exhaustive_no_variant_e(x: Result<NonExhaustive, num::NonZero<u8>>);
    |                                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@@ -202,7 +220,7 @@ LL |     fn result_1zst_non_exhaustive_no_variant_e(x: Result<NonExhaustive, num
    = note: enum has no representation hint
 
 error: `extern` block uses type `Result<Field, NonZero<u8>>`, which is not FFI-safe
-  --> $DIR/lint-ctypes-enum.rs:167:49
+  --> $DIR/lint-ctypes-enum.rs:169:49
    |
 LL |     fn result_1zst_exhaustive_single_field_e(x: Result<Field, num::NonZero<u8>>);
    |                                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@@ -211,7 +229,7 @@ LL |     fn result_1zst_exhaustive_single_field_e(x: Result<Field, num::NonZero<
    = note: enum has no representation hint
 
 error: `extern` block uses type `Result<(), Result<(), NonZero<u8>>>`, which is not FFI-safe
-  --> $DIR/lint-ctypes-enum.rs:169:30
+  --> $DIR/lint-ctypes-enum.rs:171:30
    |
 LL |     fn result_cascading_e(x: Result<(), Result<(), num::NonZero<u8>>>);
    |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@@ -219,5 +237,5 @@ LL |     fn result_cascading_e(x: Result<(), Result<(), num::NonZero<u8>>>);
    = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
    = note: enum has no representation hint
 
-error: aborting due to 23 previous errors
+error: aborting due to 25 previous errors
 

From b3f6511755228ee3ff2e59c69f575454f6eb3108 Mon Sep 17 00:00:00 2001
From: Arvind Mukund <armu30@gmail.com>
Date: Mon, 18 Mar 2024 19:45:40 -0700
Subject: [PATCH 6/9] Add a test against Result<(), ()>

---
 tests/ui/lint/lint-ctypes-enum.rs     |  3 ++-
 tests/ui/lint/lint-ctypes-enum.stderr | 11 ++++++++++-
 2 files changed, 12 insertions(+), 2 deletions(-)

diff --git a/tests/ui/lint/lint-ctypes-enum.rs b/tests/ui/lint/lint-ctypes-enum.rs
index b69ee82f8aeb1..19af1de95760b 100644
--- a/tests/ui/lint/lint-ctypes-enum.rs
+++ b/tests/ui/lint/lint-ctypes-enum.rs
@@ -170,7 +170,8 @@ extern "C" {
     //~^ ERROR `extern` block uses type
     fn result_cascading_e(x: Result<(), Result<(), num::NonZero<u8>>>);
     //~^ ERROR `extern` block uses type
-
+    fn result_unit_t_e(x: Result<(), ()>);
+    //~^ ERROR `extern` block uses type
 }
 
 pub fn main() {}
diff --git a/tests/ui/lint/lint-ctypes-enum.stderr b/tests/ui/lint/lint-ctypes-enum.stderr
index ab1eb67c07510..8d7b28bfb7ddf 100644
--- a/tests/ui/lint/lint-ctypes-enum.stderr
+++ b/tests/ui/lint/lint-ctypes-enum.stderr
@@ -237,5 +237,14 @@ LL |     fn result_cascading_e(x: Result<(), Result<(), num::NonZero<u8>>>);
    = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
    = note: enum has no representation hint
 
-error: aborting due to 25 previous errors
+error: `extern` block uses type `Result<(), ()>`, which is not FFI-safe
+  --> $DIR/lint-ctypes-enum.rs:174:27
+   |
+LL |     fn result_unit_t_e(x: Result<(), ()>);
+   |                           ^^^^^^^^^^^^^^ not FFI-safe
+   |
+   = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
+   = note: enum has no representation hint
+
+error: aborting due to 26 previous errors
 

From 764f64f0d7e8a51adb05f29bee11909b4f446579 Mon Sep 17 00:00:00 2001
From: Arvind Mukund <armu30@gmail.com>
Date: Mon, 18 Mar 2024 19:47:43 -0700
Subject: [PATCH 7/9] Reword `is_niche_optimization_candidate` doc

---
 compiler/rustc_lint/src/types.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs
index d491de7609beb..5db5f4ab9eedc 100644
--- a/compiler/rustc_lint/src/types.rs
+++ b/compiler/rustc_lint/src/types.rs
@@ -1099,7 +1099,7 @@ fn get_nullable_type<'tcx>(
     })
 }
 
-/// A type is niche_optimization_candiate iff:
+/// A type is niche-optimization candidate iff:
 /// - Is a zero-sized type with alignment 1 (a “1-ZST”).
 /// - Has no fields.
 /// - Does not have the `#[non_exhaustive]` attribute.

From 437ca26de5d2fe25a37f88956b6225344084fd1d Mon Sep 17 00:00:00 2001
From: Arvind Mukund <armu30@gmail.com>
Date: Mon, 18 Mar 2024 19:48:40 -0700
Subject: [PATCH 8/9] Remove comment out of RFC's scope

---
 compiler/rustc_lint/src/types.rs | 1 -
 1 file changed, 1 deletion(-)

diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs
index 5db5f4ab9eedc..09fdceb156cf6 100644
--- a/compiler/rustc_lint/src/types.rs
+++ b/compiler/rustc_lint/src/types.rs
@@ -1115,7 +1115,6 @@ fn is_niche_optimization_candidate<'tcx>(
     match ty.kind() {
         ty::Adt(ty_def, _) => {
             let non_exhaustive = ty_def.is_variant_list_non_exhaustive();
-            // Should single-variant enums be allowed?
             let empty = (ty_def.is_struct() && ty_def.all_fields().next().is_none())
                 || (ty_def.is_enum() && ty_def.variants().is_empty());
 

From ed532cc186a651a3e4b848ffbef8c080018f1732 Mon Sep 17 00:00:00 2001
From: Arvind Mukund <armu30@gmail.com>
Date: Mon, 18 Mar 2024 20:31:48 -0700
Subject: [PATCH 9/9] Put the RFC behind a feature gate `result_ffi_guarantees`

---
 compiler/rustc_feature/src/unstable.rs        |   3 +
 compiler/rustc_lint/src/types.rs              |   4 +
 compiler/rustc_span/src/symbol.rs             |   1 +
 .../result-ffi-guarantees.md                  |  14 +
 .../feature-gate-result_ffi_guarantees.rs     |  99 +++++
 .../feature-gate-result_ffi_guarantees.stderr | 349 ++++++++++++++++++
 tests/ui/lint/lint-ctypes-enum.rs             |   1 +
 tests/ui/lint/lint-ctypes-enum.stderr         |  56 +--
 8 files changed, 499 insertions(+), 28 deletions(-)
 create mode 100644 src/doc/unstable-book/src/language-features/result-ffi-guarantees.md
 create mode 100644 tests/ui/feature-gates/feature-gate-result_ffi_guarantees.rs
 create mode 100644 tests/ui/feature-gates/feature-gate-result_ffi_guarantees.stderr

diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs
index 9641d336c3f3c..eec0d0eb5298a 100644
--- a/compiler/rustc_feature/src/unstable.rs
+++ b/compiler/rustc_feature/src/unstable.rs
@@ -585,6 +585,9 @@ declare_features! (
     (incomplete, repr128, "1.16.0", Some(56071)),
     /// Allows `repr(simd)` and importing the various simd intrinsics.
     (unstable, repr_simd, "1.4.0", Some(27731)),
+    /// Allows enums like Result<T, E> to be used across FFI, if T's niche value can
+    /// be used to describe E or vise-versa.
+    (unstable, result_ffi_guarantees, "CURRENT_RUSTC_VERSION", Some(110503)),
     /// Allows bounding the return type of AFIT/RPITIT.
     (incomplete, return_type_notation, "1.70.0", Some(109417)),
     /// Allows `extern "rust-cold"`.
diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs
index 09fdceb156cf6..b3fd03d3f78bf 100644
--- a/compiler/rustc_lint/src/types.rs
+++ b/compiler/rustc_lint/src/types.rs
@@ -1142,6 +1142,10 @@ pub(crate) fn repr_nullable_ptr<'tcx>(
             [var_one, var_two] => match (&var_one.fields.raw[..], &var_two.fields.raw[..]) {
                 ([], [field]) | ([field], []) => field.ty(tcx, args),
                 ([field1], [field2]) => {
+                    if !tcx.features().result_ffi_guarantees {
+                        return None;
+                    }
+
                     let ty1 = field1.ty(tcx, args);
                     let ty2 = field2.ty(tcx, args);
 
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 8abf42e2c1392..ff9b2a413c952 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -1509,6 +1509,7 @@ symbols! {
         require,
         residual,
         result,
+        result_ffi_guarantees,
         resume,
         return_position_impl_trait_in_trait,
         return_type_notation,
diff --git a/src/doc/unstable-book/src/language-features/result-ffi-guarantees.md b/src/doc/unstable-book/src/language-features/result-ffi-guarantees.md
new file mode 100644
index 0000000000000..dc9c196524ed4
--- /dev/null
+++ b/src/doc/unstable-book/src/language-features/result-ffi-guarantees.md
@@ -0,0 +1,14 @@
+# `result_ffi_guarantees`
+
+The tracking issue for this feature is: [#110503]
+
+[#110503]: https://github.com/rust-lang/rust/issues/110503
+
+------------------------
+
+This feature adds the possibility of using `Result<T, E>` in FFI if T's niche
+value can be used to describe E or vise-versa.
+
+See [RFC 3391] for more information.
+
+[RFC 3391]: https://github.com/rust-lang/rfcs/blob/master/text/3391-result_ffi_guarantees.md
diff --git a/tests/ui/feature-gates/feature-gate-result_ffi_guarantees.rs b/tests/ui/feature-gates/feature-gate-result_ffi_guarantees.rs
new file mode 100644
index 0000000000000..dda317aecc3c3
--- /dev/null
+++ b/tests/ui/feature-gates/feature-gate-result_ffi_guarantees.rs
@@ -0,0 +1,99 @@
+#![allow(dead_code)]
+#![deny(improper_ctypes)]
+#![feature(ptr_internals)]
+
+use std::num;
+
+enum Z {}
+
+#[repr(transparent)]
+struct TransparentStruct<T>(T, std::marker::PhantomData<Z>);
+
+#[repr(transparent)]
+enum TransparentEnum<T> {
+    Variant(T, std::marker::PhantomData<Z>),
+}
+
+struct NoField;
+
+extern "C" {
+    fn result_ref_t(x: Result<&'static u8, ()>);
+    //~^ ERROR `extern` block uses type `Result
+    fn result_fn_t(x: Result<extern "C" fn(), ()>);
+    //~^ ERROR `extern` block uses type `Result
+    fn result_nonnull_t(x: Result<std::ptr::NonNull<u8>, ()>);
+    //~^ ERROR `extern` block uses type `Result
+    fn result_unique_t(x: Result<std::ptr::Unique<u8>, ()>);
+    //~^ ERROR `extern` block uses type `Result
+    fn result_nonzero_u8_t(x: Result<num::NonZero<u8>, ()>);
+    //~^ ERROR `extern` block uses type `Result
+    fn result_nonzero_u16_t(x: Result<num::NonZero<u16>, ()>);
+    //~^ ERROR `extern` block uses type `Result
+    fn result_nonzero_u32_t(x: Result<num::NonZero<u32>, ()>);
+    //~^ ERROR `extern` block uses type `Result
+    fn result_nonzero_u64_t(x: Result<num::NonZero<u64>, ()>);
+    //~^ ERROR `extern` block uses type `Result
+    fn result_nonzero_usize_t(x: Result<num::NonZero<usize>, ()>);
+    //~^ ERROR `extern` block uses type `Result
+    fn result_nonzero_i8_t(x: Result<num::NonZero<i8>, ()>);
+    //~^ ERROR `extern` block uses type `Result
+    fn result_nonzero_i16_t(x: Result<num::NonZero<i16>, ()>);
+    //~^ ERROR `extern` block uses type `Result
+    fn result_nonzero_i32_t(x: Result<num::NonZero<i32>, ()>);
+    //~^ ERROR `extern` block uses type `Result
+    fn result_nonzero_i64_t(x: Result<num::NonZero<i64>, ()>);
+    //~^ ERROR `extern` block uses type `Result
+    fn result_nonzero_isize_t(x: Result<num::NonZero<isize>, ()>);
+    //~^ ERROR `extern` block uses type `Result
+    fn result_transparent_struct_t(x: Result<TransparentStruct<num::NonZero<u8>>, ()>);
+    //~^ ERROR `extern` block uses type `Result
+    fn result_transparent_enum_t(x: Result<TransparentEnum<num::NonZero<u8>>, ()>);
+    //~^ ERROR `extern` block uses type `Result
+    fn result_phantom_t(x: Result<num::NonZero<u8>, std::marker::PhantomData<()>>);
+    //~^ ERROR `extern` block uses type `Result
+    fn result_1zst_exhaustive_no_variant_t(x: Result<num::NonZero<u8>, Z>);
+    //~^ ERROR `extern` block uses type `Result
+    fn result_1zst_exhaustive_no_field_t(x: Result<num::NonZero<u8>, NoField>);
+    //~^ ERROR `extern` block uses type `Result
+
+    fn result_ref_e(x: Result<(), &'static u8>);
+    //~^ ERROR `extern` block uses type `Result
+    fn result_fn_e(x: Result<(), extern "C" fn()>);
+    //~^ ERROR `extern` block uses type `Result
+    fn result_nonnull_e(x: Result<(), std::ptr::NonNull<u8>>);
+    //~^ ERROR `extern` block uses type `Result
+    fn result_unique_e(x: Result<(), std::ptr::Unique<u8>>);
+    //~^ ERROR `extern` block uses type `Result
+    fn result_nonzero_u8_e(x: Result<(), num::NonZero<u8>>);
+    //~^ ERROR `extern` block uses type `Result
+    fn result_nonzero_u16_e(x: Result<(), num::NonZero<u16>>);
+    //~^ ERROR `extern` block uses type `Result
+    fn result_nonzero_u32_e(x: Result<(), num::NonZero<u32>>);
+    //~^ ERROR `extern` block uses type `Result
+    fn result_nonzero_u64_e(x: Result<(), num::NonZero<u64>>);
+    //~^ ERROR `extern` block uses type `Result
+    fn result_nonzero_usize_e(x: Result<(), num::NonZero<usize>>);
+    //~^ ERROR `extern` block uses type `Result
+    fn result_nonzero_i8_e(x: Result<(), num::NonZero<i8>>);
+    //~^ ERROR `extern` block uses type `Result
+    fn result_nonzero_i16_e(x: Result<(), num::NonZero<i16>>);
+    //~^ ERROR `extern` block uses type `Result
+    fn result_nonzero_i32_e(x: Result<(), num::NonZero<i32>>);
+    //~^ ERROR `extern` block uses type `Result
+    fn result_nonzero_i64_e(x: Result<(), num::NonZero<i64>>);
+    //~^ ERROR `extern` block uses type `Result
+    fn result_nonzero_isize_e(x: Result<(), num::NonZero<isize>>);
+    //~^ ERROR `extern` block uses type `Result
+    fn result_transparent_struct_e(x: Result<(), TransparentStruct<num::NonZero<u8>>>);
+    //~^ ERROR `extern` block uses type `Result
+    fn result_transparent_enum_e(x: Result<(), TransparentEnum<num::NonZero<u8>>>);
+    //~^ ERROR `extern` block uses type `Result
+    fn result_phantom_e(x: Result<num::NonZero<u8>, std::marker::PhantomData<()>>);
+    //~^ ERROR `extern` block uses type `Result
+    fn result_1zst_exhaustive_no_variant_e(x: Result<Z, num::NonZero<u8>>);
+    //~^ ERROR `extern` block uses type `Result
+    fn result_1zst_exhaustive_no_field_e(x: Result<NoField, num::NonZero<u8>>);
+    //~^ ERROR `extern` block uses type `Result
+}
+
+pub fn main() {}
diff --git a/tests/ui/feature-gates/feature-gate-result_ffi_guarantees.stderr b/tests/ui/feature-gates/feature-gate-result_ffi_guarantees.stderr
new file mode 100644
index 0000000000000..94416eb99c878
--- /dev/null
+++ b/tests/ui/feature-gates/feature-gate-result_ffi_guarantees.stderr
@@ -0,0 +1,349 @@
+error: `extern` block uses type `Result<&u8, ()>`, which is not FFI-safe
+  --> $DIR/feature-gate-result_ffi_guarantees.rs:20:24
+   |
+LL |     fn result_ref_t(x: Result<&'static u8, ()>);
+   |                        ^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
+   |
+   = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
+   = note: enum has no representation hint
+note: the lint level is defined here
+  --> $DIR/feature-gate-result_ffi_guarantees.rs:2:9
+   |
+LL | #![deny(improper_ctypes)]
+   |         ^^^^^^^^^^^^^^^
+
+error: `extern` block uses type `Result<extern "C" fn(), ()>`, which is not FFI-safe
+  --> $DIR/feature-gate-result_ffi_guarantees.rs:22:23
+   |
+LL |     fn result_fn_t(x: Result<extern "C" fn(), ()>);
+   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
+   |
+   = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
+   = note: enum has no representation hint
+
+error: `extern` block uses type `Result<NonNull<u8>, ()>`, which is not FFI-safe
+  --> $DIR/feature-gate-result_ffi_guarantees.rs:24:28
+   |
+LL |     fn result_nonnull_t(x: Result<std::ptr::NonNull<u8>, ()>);
+   |                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
+   |
+   = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
+   = note: enum has no representation hint
+
+error: `extern` block uses type `Result<Unique<u8>, ()>`, which is not FFI-safe
+  --> $DIR/feature-gate-result_ffi_guarantees.rs:26:27
+   |
+LL |     fn result_unique_t(x: Result<std::ptr::Unique<u8>, ()>);
+   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
+   |
+   = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
+   = note: enum has no representation hint
+
+error: `extern` block uses type `Result<NonZero<u8>, ()>`, which is not FFI-safe
+  --> $DIR/feature-gate-result_ffi_guarantees.rs:28:31
+   |
+LL |     fn result_nonzero_u8_t(x: Result<num::NonZero<u8>, ()>);
+   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
+   |
+   = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
+   = note: enum has no representation hint
+
+error: `extern` block uses type `Result<NonZero<u16>, ()>`, which is not FFI-safe
+  --> $DIR/feature-gate-result_ffi_guarantees.rs:30:32
+   |
+LL |     fn result_nonzero_u16_t(x: Result<num::NonZero<u16>, ()>);
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
+   |
+   = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
+   = note: enum has no representation hint
+
+error: `extern` block uses type `Result<NonZero<u32>, ()>`, which is not FFI-safe
+  --> $DIR/feature-gate-result_ffi_guarantees.rs:32:32
+   |
+LL |     fn result_nonzero_u32_t(x: Result<num::NonZero<u32>, ()>);
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
+   |
+   = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
+   = note: enum has no representation hint
+
+error: `extern` block uses type `Result<NonZero<u64>, ()>`, which is not FFI-safe
+  --> $DIR/feature-gate-result_ffi_guarantees.rs:34:32
+   |
+LL |     fn result_nonzero_u64_t(x: Result<num::NonZero<u64>, ()>);
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
+   |
+   = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
+   = note: enum has no representation hint
+
+error: `extern` block uses type `Result<NonZero<usize>, ()>`, which is not FFI-safe
+  --> $DIR/feature-gate-result_ffi_guarantees.rs:36:34
+   |
+LL |     fn result_nonzero_usize_t(x: Result<num::NonZero<usize>, ()>);
+   |                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
+   |
+   = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
+   = note: enum has no representation hint
+
+error: `extern` block uses type `Result<NonZero<i8>, ()>`, which is not FFI-safe
+  --> $DIR/feature-gate-result_ffi_guarantees.rs:38:31
+   |
+LL |     fn result_nonzero_i8_t(x: Result<num::NonZero<i8>, ()>);
+   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
+   |
+   = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
+   = note: enum has no representation hint
+
+error: `extern` block uses type `Result<NonZero<i16>, ()>`, which is not FFI-safe
+  --> $DIR/feature-gate-result_ffi_guarantees.rs:40:32
+   |
+LL |     fn result_nonzero_i16_t(x: Result<num::NonZero<i16>, ()>);
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
+   |
+   = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
+   = note: enum has no representation hint
+
+error: `extern` block uses type `Result<NonZero<i32>, ()>`, which is not FFI-safe
+  --> $DIR/feature-gate-result_ffi_guarantees.rs:42:32
+   |
+LL |     fn result_nonzero_i32_t(x: Result<num::NonZero<i32>, ()>);
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
+   |
+   = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
+   = note: enum has no representation hint
+
+error: `extern` block uses type `Result<NonZero<i64>, ()>`, which is not FFI-safe
+  --> $DIR/feature-gate-result_ffi_guarantees.rs:44:32
+   |
+LL |     fn result_nonzero_i64_t(x: Result<num::NonZero<i64>, ()>);
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
+   |
+   = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
+   = note: enum has no representation hint
+
+error: `extern` block uses type `Result<NonZero<isize>, ()>`, which is not FFI-safe
+  --> $DIR/feature-gate-result_ffi_guarantees.rs:46:34
+   |
+LL |     fn result_nonzero_isize_t(x: Result<num::NonZero<isize>, ()>);
+   |                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
+   |
+   = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
+   = note: enum has no representation hint
+
+error: `extern` block uses type `Result<TransparentStruct<NonZero<u8>>, ()>`, which is not FFI-safe
+  --> $DIR/feature-gate-result_ffi_guarantees.rs:48:39
+   |
+LL |     fn result_transparent_struct_t(x: Result<TransparentStruct<num::NonZero<u8>>, ()>);
+   |                                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
+   |
+   = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
+   = note: enum has no representation hint
+
+error: `extern` block uses type `Result<TransparentEnum<NonZero<u8>>, ()>`, which is not FFI-safe
+  --> $DIR/feature-gate-result_ffi_guarantees.rs:50:37
+   |
+LL |     fn result_transparent_enum_t(x: Result<TransparentEnum<num::NonZero<u8>>, ()>);
+   |                                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
+   |
+   = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
+   = note: enum has no representation hint
+
+error: `extern` block uses type `Result<NonZero<u8>, PhantomData<()>>`, which is not FFI-safe
+  --> $DIR/feature-gate-result_ffi_guarantees.rs:52:28
+   |
+LL |     fn result_phantom_t(x: Result<num::NonZero<u8>, std::marker::PhantomData<()>>);
+   |                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
+   |
+   = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
+   = note: enum has no representation hint
+
+error: `extern` block uses type `Result<NonZero<u8>, Z>`, which is not FFI-safe
+  --> $DIR/feature-gate-result_ffi_guarantees.rs:54:47
+   |
+LL |     fn result_1zst_exhaustive_no_variant_t(x: Result<num::NonZero<u8>, Z>);
+   |                                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
+   |
+   = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
+   = note: enum has no representation hint
+
+error: `extern` block uses type `Result<NonZero<u8>, NoField>`, which is not FFI-safe
+  --> $DIR/feature-gate-result_ffi_guarantees.rs:56:45
+   |
+LL |     fn result_1zst_exhaustive_no_field_t(x: Result<num::NonZero<u8>, NoField>);
+   |                                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
+   |
+   = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
+   = note: enum has no representation hint
+
+error: `extern` block uses type `Result<(), &u8>`, which is not FFI-safe
+  --> $DIR/feature-gate-result_ffi_guarantees.rs:59:24
+   |
+LL |     fn result_ref_e(x: Result<(), &'static u8>);
+   |                        ^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
+   |
+   = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
+   = note: enum has no representation hint
+
+error: `extern` block uses type `Result<(), extern "C" fn()>`, which is not FFI-safe
+  --> $DIR/feature-gate-result_ffi_guarantees.rs:61:23
+   |
+LL |     fn result_fn_e(x: Result<(), extern "C" fn()>);
+   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
+   |
+   = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
+   = note: enum has no representation hint
+
+error: `extern` block uses type `Result<(), NonNull<u8>>`, which is not FFI-safe
+  --> $DIR/feature-gate-result_ffi_guarantees.rs:63:28
+   |
+LL |     fn result_nonnull_e(x: Result<(), std::ptr::NonNull<u8>>);
+   |                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
+   |
+   = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
+   = note: enum has no representation hint
+
+error: `extern` block uses type `Result<(), Unique<u8>>`, which is not FFI-safe
+  --> $DIR/feature-gate-result_ffi_guarantees.rs:65:27
+   |
+LL |     fn result_unique_e(x: Result<(), std::ptr::Unique<u8>>);
+   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
+   |
+   = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
+   = note: enum has no representation hint
+
+error: `extern` block uses type `Result<(), NonZero<u8>>`, which is not FFI-safe
+  --> $DIR/feature-gate-result_ffi_guarantees.rs:67:31
+   |
+LL |     fn result_nonzero_u8_e(x: Result<(), num::NonZero<u8>>);
+   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
+   |
+   = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
+   = note: enum has no representation hint
+
+error: `extern` block uses type `Result<(), NonZero<u16>>`, which is not FFI-safe
+  --> $DIR/feature-gate-result_ffi_guarantees.rs:69:32
+   |
+LL |     fn result_nonzero_u16_e(x: Result<(), num::NonZero<u16>>);
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
+   |
+   = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
+   = note: enum has no representation hint
+
+error: `extern` block uses type `Result<(), NonZero<u32>>`, which is not FFI-safe
+  --> $DIR/feature-gate-result_ffi_guarantees.rs:71:32
+   |
+LL |     fn result_nonzero_u32_e(x: Result<(), num::NonZero<u32>>);
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
+   |
+   = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
+   = note: enum has no representation hint
+
+error: `extern` block uses type `Result<(), NonZero<u64>>`, which is not FFI-safe
+  --> $DIR/feature-gate-result_ffi_guarantees.rs:73:32
+   |
+LL |     fn result_nonzero_u64_e(x: Result<(), num::NonZero<u64>>);
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
+   |
+   = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
+   = note: enum has no representation hint
+
+error: `extern` block uses type `Result<(), NonZero<usize>>`, which is not FFI-safe
+  --> $DIR/feature-gate-result_ffi_guarantees.rs:75:34
+   |
+LL |     fn result_nonzero_usize_e(x: Result<(), num::NonZero<usize>>);
+   |                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
+   |
+   = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
+   = note: enum has no representation hint
+
+error: `extern` block uses type `Result<(), NonZero<i8>>`, which is not FFI-safe
+  --> $DIR/feature-gate-result_ffi_guarantees.rs:77:31
+   |
+LL |     fn result_nonzero_i8_e(x: Result<(), num::NonZero<i8>>);
+   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
+   |
+   = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
+   = note: enum has no representation hint
+
+error: `extern` block uses type `Result<(), NonZero<i16>>`, which is not FFI-safe
+  --> $DIR/feature-gate-result_ffi_guarantees.rs:79:32
+   |
+LL |     fn result_nonzero_i16_e(x: Result<(), num::NonZero<i16>>);
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
+   |
+   = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
+   = note: enum has no representation hint
+
+error: `extern` block uses type `Result<(), NonZero<i32>>`, which is not FFI-safe
+  --> $DIR/feature-gate-result_ffi_guarantees.rs:81:32
+   |
+LL |     fn result_nonzero_i32_e(x: Result<(), num::NonZero<i32>>);
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
+   |
+   = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
+   = note: enum has no representation hint
+
+error: `extern` block uses type `Result<(), NonZero<i64>>`, which is not FFI-safe
+  --> $DIR/feature-gate-result_ffi_guarantees.rs:83:32
+   |
+LL |     fn result_nonzero_i64_e(x: Result<(), num::NonZero<i64>>);
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
+   |
+   = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
+   = note: enum has no representation hint
+
+error: `extern` block uses type `Result<(), NonZero<isize>>`, which is not FFI-safe
+  --> $DIR/feature-gate-result_ffi_guarantees.rs:85:34
+   |
+LL |     fn result_nonzero_isize_e(x: Result<(), num::NonZero<isize>>);
+   |                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
+   |
+   = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
+   = note: enum has no representation hint
+
+error: `extern` block uses type `Result<(), TransparentStruct<NonZero<u8>>>`, which is not FFI-safe
+  --> $DIR/feature-gate-result_ffi_guarantees.rs:87:39
+   |
+LL |     fn result_transparent_struct_e(x: Result<(), TransparentStruct<num::NonZero<u8>>>);
+   |                                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
+   |
+   = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
+   = note: enum has no representation hint
+
+error: `extern` block uses type `Result<(), TransparentEnum<NonZero<u8>>>`, which is not FFI-safe
+  --> $DIR/feature-gate-result_ffi_guarantees.rs:89:37
+   |
+LL |     fn result_transparent_enum_e(x: Result<(), TransparentEnum<num::NonZero<u8>>>);
+   |                                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
+   |
+   = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
+   = note: enum has no representation hint
+
+error: `extern` block uses type `Result<NonZero<u8>, PhantomData<()>>`, which is not FFI-safe
+  --> $DIR/feature-gate-result_ffi_guarantees.rs:91:28
+   |
+LL |     fn result_phantom_e(x: Result<num::NonZero<u8>, std::marker::PhantomData<()>>);
+   |                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
+   |
+   = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
+   = note: enum has no representation hint
+
+error: `extern` block uses type `Result<Z, NonZero<u8>>`, which is not FFI-safe
+  --> $DIR/feature-gate-result_ffi_guarantees.rs:93:47
+   |
+LL |     fn result_1zst_exhaustive_no_variant_e(x: Result<Z, num::NonZero<u8>>);
+   |                                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
+   |
+   = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
+   = note: enum has no representation hint
+
+error: `extern` block uses type `Result<NoField, NonZero<u8>>`, which is not FFI-safe
+  --> $DIR/feature-gate-result_ffi_guarantees.rs:95:45
+   |
+LL |     fn result_1zst_exhaustive_no_field_e(x: Result<NoField, num::NonZero<u8>>);
+   |                                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
+   |
+   = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
+   = note: enum has no representation hint
+
+error: aborting due to 38 previous errors
+
diff --git a/tests/ui/lint/lint-ctypes-enum.rs b/tests/ui/lint/lint-ctypes-enum.rs
index 19af1de95760b..cb8e9e8067513 100644
--- a/tests/ui/lint/lint-ctypes-enum.rs
+++ b/tests/ui/lint/lint-ctypes-enum.rs
@@ -2,6 +2,7 @@
 #![deny(improper_ctypes)]
 #![feature(ptr_internals)]
 #![feature(transparent_unions)]
+#![feature(result_ffi_guarantees)]
 
 use std::num;
 
diff --git a/tests/ui/lint/lint-ctypes-enum.stderr b/tests/ui/lint/lint-ctypes-enum.stderr
index 8d7b28bfb7ddf..bba5b09b69cc9 100644
--- a/tests/ui/lint/lint-ctypes-enum.stderr
+++ b/tests/ui/lint/lint-ctypes-enum.stderr
@@ -1,5 +1,5 @@
 error: `extern` block uses type `U`, which is not FFI-safe
-  --> $DIR/lint-ctypes-enum.rs:68:14
+  --> $DIR/lint-ctypes-enum.rs:69:14
    |
 LL |     fn uf(x: U);
    |              ^ not FFI-safe
@@ -7,7 +7,7 @@ LL |     fn uf(x: U);
    = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
    = note: enum has no representation hint
 note: the type is defined here
-  --> $DIR/lint-ctypes-enum.rs:9:1
+  --> $DIR/lint-ctypes-enum.rs:10:1
    |
 LL | enum U {
    | ^^^^^^
@@ -18,7 +18,7 @@ LL | #![deny(improper_ctypes)]
    |         ^^^^^^^^^^^^^^^
 
 error: `extern` block uses type `B`, which is not FFI-safe
-  --> $DIR/lint-ctypes-enum.rs:69:14
+  --> $DIR/lint-ctypes-enum.rs:70:14
    |
 LL |     fn bf(x: B);
    |              ^ not FFI-safe
@@ -26,13 +26,13 @@ LL |     fn bf(x: B);
    = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
    = note: enum has no representation hint
 note: the type is defined here
-  --> $DIR/lint-ctypes-enum.rs:12:1
+  --> $DIR/lint-ctypes-enum.rs:13:1
    |
 LL | enum B {
    | ^^^^^^
 
 error: `extern` block uses type `T`, which is not FFI-safe
-  --> $DIR/lint-ctypes-enum.rs:70:14
+  --> $DIR/lint-ctypes-enum.rs:71:14
    |
 LL |     fn tf(x: T);
    |              ^ not FFI-safe
@@ -40,13 +40,13 @@ LL |     fn tf(x: T);
    = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
    = note: enum has no representation hint
 note: the type is defined here
-  --> $DIR/lint-ctypes-enum.rs:16:1
+  --> $DIR/lint-ctypes-enum.rs:17:1
    |
 LL | enum T {
    | ^^^^^^
 
 error: `extern` block uses type `u128`, which is not FFI-safe
-  --> $DIR/lint-ctypes-enum.rs:82:31
+  --> $DIR/lint-ctypes-enum.rs:83:31
    |
 LL |     fn option_nonzero_u128(x: Option<num::NonZero<u128>>);
    |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@@ -54,7 +54,7 @@ LL |     fn option_nonzero_u128(x: Option<num::NonZero<u128>>);
    = note: 128-bit integers don't currently have a known stable ABI
 
 error: `extern` block uses type `i128`, which is not FFI-safe
-  --> $DIR/lint-ctypes-enum.rs:89:31
+  --> $DIR/lint-ctypes-enum.rs:90:31
    |
 LL |     fn option_nonzero_i128(x: Option<num::NonZero<i128>>);
    |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@@ -62,7 +62,7 @@ LL |     fn option_nonzero_i128(x: Option<num::NonZero<i128>>);
    = note: 128-bit integers don't currently have a known stable ABI
 
 error: `extern` block uses type `Option<TransparentUnion<NonZero<u8>>>`, which is not FFI-safe
-  --> $DIR/lint-ctypes-enum.rs:94:36
+  --> $DIR/lint-ctypes-enum.rs:95:36
    |
 LL |     fn option_transparent_union(x: Option<TransparentUnion<num::NonZero<u8>>>);
    |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@@ -71,7 +71,7 @@ LL |     fn option_transparent_union(x: Option<TransparentUnion<num::NonZero<u8>
    = note: enum has no representation hint
 
 error: `extern` block uses type `Option<Rust<NonZero<u8>>>`, which is not FFI-safe
-  --> $DIR/lint-ctypes-enum.rs:96:28
+  --> $DIR/lint-ctypes-enum.rs:97:28
    |
 LL |     fn option_repr_rust(x: Option<Rust<num::NonZero<u8>>>);
    |                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@@ -80,7 +80,7 @@ LL |     fn option_repr_rust(x: Option<Rust<num::NonZero<u8>>>);
    = note: enum has no representation hint
 
 error: `extern` block uses type `u128`, which is not FFI-safe
-  --> $DIR/lint-ctypes-enum.rs:106:33
+  --> $DIR/lint-ctypes-enum.rs:107:33
    |
 LL |     fn result_nonzero_u128_t(x: Result<num::NonZero<u128>, ()>);
    |                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@@ -88,7 +88,7 @@ LL |     fn result_nonzero_u128_t(x: Result<num::NonZero<u128>, ()>);
    = note: 128-bit integers don't currently have a known stable ABI
 
 error: `extern` block uses type `i128`, which is not FFI-safe
-  --> $DIR/lint-ctypes-enum.rs:113:33
+  --> $DIR/lint-ctypes-enum.rs:114:33
    |
 LL |     fn result_nonzero_i128_t(x: Result<num::NonZero<i128>, ()>);
    |                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@@ -96,7 +96,7 @@ LL |     fn result_nonzero_i128_t(x: Result<num::NonZero<i128>, ()>);
    = note: 128-bit integers don't currently have a known stable ABI
 
 error: `extern` block uses type `Result<TransparentUnion<NonZero<u8>>, ()>`, which is not FFI-safe
-  --> $DIR/lint-ctypes-enum.rs:118:38
+  --> $DIR/lint-ctypes-enum.rs:119:38
    |
 LL |     fn result_transparent_union_t(x: Result<TransparentUnion<num::NonZero<u8>>, ()>);
    |                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@@ -105,7 +105,7 @@ LL |     fn result_transparent_union_t(x: Result<TransparentUnion<num::NonZero<u
    = note: enum has no representation hint
 
 error: `extern` block uses type `Result<Rust<NonZero<u8>>, ()>`, which is not FFI-safe
-  --> $DIR/lint-ctypes-enum.rs:120:30
+  --> $DIR/lint-ctypes-enum.rs:121:30
    |
 LL |     fn result_repr_rust_t(x: Result<Rust<num::NonZero<u8>>, ()>);
    |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@@ -114,7 +114,7 @@ LL |     fn result_repr_rust_t(x: Result<Rust<num::NonZero<u8>>, ()>);
    = note: enum has no representation hint
 
 error: `extern` block uses type `Result<NonZero<u8>, U>`, which is not FFI-safe
-  --> $DIR/lint-ctypes-enum.rs:124:51
+  --> $DIR/lint-ctypes-enum.rs:125:51
    |
 LL |     fn result_1zst_exhaustive_single_variant_t(x: Result<num::NonZero<u8>, U>);
    |                                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@@ -123,7 +123,7 @@ LL |     fn result_1zst_exhaustive_single_variant_t(x: Result<num::NonZero<u8>,
    = note: enum has no representation hint
 
 error: `extern` block uses type `Result<NonZero<u8>, B>`, which is not FFI-safe
-  --> $DIR/lint-ctypes-enum.rs:126:53
+  --> $DIR/lint-ctypes-enum.rs:127:53
    |
 LL |     fn result_1zst_exhaustive_multiple_variant_t(x: Result<num::NonZero<u8>, B>);
    |                                                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@@ -132,7 +132,7 @@ LL |     fn result_1zst_exhaustive_multiple_variant_t(x: Result<num::NonZero<u8>
    = note: enum has no representation hint
 
 error: `extern` block uses type `Result<NonZero<u8>, NonExhaustive>`, which is not FFI-safe
-  --> $DIR/lint-ctypes-enum.rs:128:51
+  --> $DIR/lint-ctypes-enum.rs:129:51
    |
 LL |     fn result_1zst_non_exhaustive_no_variant_t(x: Result<num::NonZero<u8>, NonExhaustive>);
    |                                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@@ -141,7 +141,7 @@ LL |     fn result_1zst_non_exhaustive_no_variant_t(x: Result<num::NonZero<u8>,
    = note: enum has no representation hint
 
 error: `extern` block uses type `Result<NonZero<u8>, Field>`, which is not FFI-safe
-  --> $DIR/lint-ctypes-enum.rs:131:49
+  --> $DIR/lint-ctypes-enum.rs:132:49
    |
 LL |     fn result_1zst_exhaustive_single_field_t(x: Result<num::NonZero<u8>, Field>);
    |                                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@@ -150,7 +150,7 @@ LL |     fn result_1zst_exhaustive_single_field_t(x: Result<num::NonZero<u8>, Fi
    = note: enum has no representation hint
 
 error: `extern` block uses type `Result<Result<(), NonZero<u8>>, ()>`, which is not FFI-safe
-  --> $DIR/lint-ctypes-enum.rs:133:30
+  --> $DIR/lint-ctypes-enum.rs:134:30
    |
 LL |     fn result_cascading_t(x: Result<Result<(), num::NonZero<u8>>, ()>);
    |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@@ -159,7 +159,7 @@ LL |     fn result_cascading_t(x: Result<Result<(), num::NonZero<u8>>, ()>);
    = note: enum has no representation hint
 
 error: `extern` block uses type `u128`, which is not FFI-safe
-  --> $DIR/lint-ctypes-enum.rs:144:33
+  --> $DIR/lint-ctypes-enum.rs:145:33
    |
 LL |     fn result_nonzero_u128_e(x: Result<(), num::NonZero<u128>>);
    |                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@@ -167,7 +167,7 @@ LL |     fn result_nonzero_u128_e(x: Result<(), num::NonZero<u128>>);
    = note: 128-bit integers don't currently have a known stable ABI
 
 error: `extern` block uses type `i128`, which is not FFI-safe
-  --> $DIR/lint-ctypes-enum.rs:151:33
+  --> $DIR/lint-ctypes-enum.rs:152:33
    |
 LL |     fn result_nonzero_i128_e(x: Result<(), num::NonZero<i128>>);
    |                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@@ -175,7 +175,7 @@ LL |     fn result_nonzero_i128_e(x: Result<(), num::NonZero<i128>>);
    = note: 128-bit integers don't currently have a known stable ABI
 
 error: `extern` block uses type `Result<(), TransparentUnion<NonZero<u8>>>`, which is not FFI-safe
-  --> $DIR/lint-ctypes-enum.rs:156:38
+  --> $DIR/lint-ctypes-enum.rs:157:38
    |
 LL |     fn result_transparent_union_e(x: Result<(), TransparentUnion<num::NonZero<u8>>>);
    |                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@@ -184,7 +184,7 @@ LL |     fn result_transparent_union_e(x: Result<(), TransparentUnion<num::NonZe
    = note: enum has no representation hint
 
 error: `extern` block uses type `Result<(), Rust<NonZero<u8>>>`, which is not FFI-safe
-  --> $DIR/lint-ctypes-enum.rs:158:30
+  --> $DIR/lint-ctypes-enum.rs:159:30
    |
 LL |     fn result_repr_rust_e(x: Result<(), Rust<num::NonZero<u8>>>);
    |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@@ -193,7 +193,7 @@ LL |     fn result_repr_rust_e(x: Result<(), Rust<num::NonZero<u8>>>);
    = note: enum has no representation hint
 
 error: `extern` block uses type `Result<U, NonZero<u8>>`, which is not FFI-safe
-  --> $DIR/lint-ctypes-enum.rs:162:51
+  --> $DIR/lint-ctypes-enum.rs:163:51
    |
 LL |     fn result_1zst_exhaustive_single_variant_e(x: Result<U, num::NonZero<u8>>);
    |                                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@@ -202,7 +202,7 @@ LL |     fn result_1zst_exhaustive_single_variant_e(x: Result<U, num::NonZero<u8
    = note: enum has no representation hint
 
 error: `extern` block uses type `Result<B, NonZero<u8>>`, which is not FFI-safe
-  --> $DIR/lint-ctypes-enum.rs:164:53
+  --> $DIR/lint-ctypes-enum.rs:165:53
    |
 LL |     fn result_1zst_exhaustive_multiple_variant_e(x: Result<B, num::NonZero<u8>>);
    |                                                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@@ -211,7 +211,7 @@ LL |     fn result_1zst_exhaustive_multiple_variant_e(x: Result<B, num::NonZero<
    = note: enum has no representation hint
 
 error: `extern` block uses type `Result<NonExhaustive, NonZero<u8>>`, which is not FFI-safe
-  --> $DIR/lint-ctypes-enum.rs:166:51
+  --> $DIR/lint-ctypes-enum.rs:167:51
    |
 LL |     fn result_1zst_non_exhaustive_no_variant_e(x: Result<NonExhaustive, num::NonZero<u8>>);
    |                                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@@ -220,7 +220,7 @@ LL |     fn result_1zst_non_exhaustive_no_variant_e(x: Result<NonExhaustive, num
    = note: enum has no representation hint
 
 error: `extern` block uses type `Result<Field, NonZero<u8>>`, which is not FFI-safe
-  --> $DIR/lint-ctypes-enum.rs:169:49
+  --> $DIR/lint-ctypes-enum.rs:170:49
    |
 LL |     fn result_1zst_exhaustive_single_field_e(x: Result<Field, num::NonZero<u8>>);
    |                                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@@ -229,7 +229,7 @@ LL |     fn result_1zst_exhaustive_single_field_e(x: Result<Field, num::NonZero<
    = note: enum has no representation hint
 
 error: `extern` block uses type `Result<(), Result<(), NonZero<u8>>>`, which is not FFI-safe
-  --> $DIR/lint-ctypes-enum.rs:171:30
+  --> $DIR/lint-ctypes-enum.rs:172:30
    |
 LL |     fn result_cascading_e(x: Result<(), Result<(), num::NonZero<u8>>>);
    |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe