//@ build-pass /*! The guarantees in RFC 3391 were strengthened as a result of the 2024 Oct 09 T-lang meeting[^1] following the precedent of T-lang's guaranteeing[^2] ABI compatibility for "Option-like" enums[^2]. We now guarantee ABI compatibility for enums that conform to these rules described by scottmcm: * The enum `E` has exactly two variants. * One variant has exactly one field, of type `T`. * `T` is a `rustc_nonnull_optimization_guaranteed` type. * All fields of the other variant are 1-ZSTs. Where "all" fields includes "there aren't any fields, so they're vacuously all 1-ZSTs". Note: "1-ZST" means a type of size 0 and alignment 1. The reason alignment of the zero-sized type matters is it can affect the alignment of the enum, which also will affect its size if the enum has a non-zero size. [^1]: [^2]: */ #![allow(dead_code)] #![deny(improper_ctypes)] #![feature(ptr_internals)] use std::num; enum Z {} #[repr(transparent)] struct TransparentStruct(T, std::marker::PhantomData); #[repr(transparent)] enum TransparentEnum { Variant(T, std::marker::PhantomData), } struct NoField; extern "C" { fn result_ref_t(x: Result<&'static u8, ()>); fn result_fn_t(x: Result); fn result_nonnull_t(x: Result, ()>); fn result_unique_t(x: Result, ()>); fn result_nonzero_u8_t(x: Result, ()>); fn result_nonzero_u16_t(x: Result, ()>); fn result_nonzero_u32_t(x: Result, ()>); fn result_nonzero_u64_t(x: Result, ()>); fn result_nonzero_usize_t(x: Result, ()>); fn result_nonzero_i8_t(x: Result, ()>); fn result_nonzero_i16_t(x: Result, ()>); fn result_nonzero_i32_t(x: Result, ()>); fn result_nonzero_i64_t(x: Result, ()>); fn result_nonzero_isize_t(x: Result, ()>); fn result_transparent_struct_t(x: Result>, ()>); fn result_transparent_enum_t(x: Result>, ()>); fn result_phantom_t(x: Result, std::marker::PhantomData<()>>); fn result_1zst_exhaustive_no_variant_t(x: Result, Z>); fn result_1zst_exhaustive_no_field_t(x: Result, NoField>); 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>); fn result_unique_e(x: Result<(), std::ptr::Unique>); fn result_nonzero_u8_e(x: Result<(), num::NonZero>); fn result_nonzero_u16_e(x: Result<(), num::NonZero>); fn result_nonzero_u32_e(x: Result<(), num::NonZero>); fn result_nonzero_u64_e(x: Result<(), num::NonZero>); fn result_nonzero_usize_e(x: Result<(), num::NonZero>); fn result_nonzero_i8_e(x: Result<(), num::NonZero>); fn result_nonzero_i16_e(x: Result<(), num::NonZero>); fn result_nonzero_i32_e(x: Result<(), num::NonZero>); fn result_nonzero_i64_e(x: Result<(), num::NonZero>); fn result_nonzero_isize_e(x: Result<(), num::NonZero>); fn result_transparent_struct_e(x: Result<(), TransparentStruct>>); fn result_transparent_enum_e(x: Result<(), TransparentEnum>>); fn result_phantom_e(x: Result, std::marker::PhantomData<()>>); fn result_1zst_exhaustive_no_variant_e(x: Result>); fn result_1zst_exhaustive_no_field_e(x: Result>); } // Custom "Result-like" enum for testing custom "Option-like" types are also accepted enum Either { Left(L), Right(R), } extern "C" { fn either_ref_t(x: Either<&'static u8, ()>); fn either_fn_t(x: Either); fn either_nonnull_t(x: Either, ()>); fn either_unique_t(x: Either, ()>); fn either_nonzero_u8_t(x: Either, ()>); fn either_nonzero_u16_t(x: Either, ()>); fn either_nonzero_u32_t(x: Either, ()>); fn either_nonzero_u64_t(x: Either, ()>); fn either_nonzero_usize_t(x: Either, ()>); fn either_nonzero_i8_t(x: Either, ()>); fn either_nonzero_i16_t(x: Either, ()>); fn either_nonzero_i32_t(x: Either, ()>); fn either_nonzero_i64_t(x: Either, ()>); fn either_nonzero_isize_t(x: Either, ()>); fn either_transparent_struct_t(x: Either>, ()>); fn either_transparent_enum_t(x: Either>, ()>); fn either_phantom_t(x: Either, std::marker::PhantomData<()>>); fn either_1zst_exhaustive_no_variant_t(x: Either, Z>); fn either_1zst_exhaustive_no_field_t(x: Either, NoField>); fn either_ref_e(x: Either<(), &'static u8>); fn either_fn_e(x: Either<(), extern "C" fn()>); fn either_nonnull_e(x: Either<(), std::ptr::NonNull>); fn either_unique_e(x: Either<(), std::ptr::Unique>); fn either_nonzero_u8_e(x: Either<(), num::NonZero>); fn either_nonzero_u16_e(x: Either<(), num::NonZero>); fn either_nonzero_u32_e(x: Either<(), num::NonZero>); fn either_nonzero_u64_e(x: Either<(), num::NonZero>); fn either_nonzero_usize_e(x: Either<(), num::NonZero>); fn either_nonzero_i8_e(x: Either<(), num::NonZero>); fn either_nonzero_i16_e(x: Either<(), num::NonZero>); fn either_nonzero_i32_e(x: Either<(), num::NonZero>); fn either_nonzero_i64_e(x: Either<(), num::NonZero>); fn either_nonzero_isize_e(x: Either<(), num::NonZero>); fn either_transparent_struct_e(x: Either<(), TransparentStruct>>); fn either_transparent_enum_e(x: Either<(), TransparentEnum>>); fn either_phantom_e(x: Either, std::marker::PhantomData<()>>); fn either_1zst_exhaustive_no_variant_e(x: Either>); fn either_1zst_exhaustive_no_field_e(x: Either>); } pub fn main() {}