@@ -1101,6 +1101,32 @@ fn get_nullable_type<'tcx>(
11011101 } )
11021102}
11031103
1104+ /// A type is niche-optimization candidate iff:
1105+ /// - Is a zero-sized type with alignment 1 (a “1-ZST”).
1106+ /// - Has no fields.
1107+ /// - Does not have the `#[non_exhaustive]` attribute.
1108+ fn is_niche_optimization_candidate < ' tcx > (
1109+ tcx : TyCtxt < ' tcx > ,
1110+ param_env : ty:: ParamEnv < ' tcx > ,
1111+ ty : Ty < ' tcx > ,
1112+ ) -> bool {
1113+ if tcx. layout_of ( param_env. and ( ty) ) . is_ok_and ( |layout| !layout. is_1zst ( ) ) {
1114+ return false ;
1115+ }
1116+
1117+ match ty. kind ( ) {
1118+ ty:: Adt ( ty_def, _) => {
1119+ let non_exhaustive = ty_def. is_variant_list_non_exhaustive ( ) ;
1120+ let empty = ( ty_def. is_struct ( ) && ty_def. all_fields ( ) . next ( ) . is_none ( ) )
1121+ || ( ty_def. is_enum ( ) && ty_def. variants ( ) . is_empty ( ) ) ;
1122+
1123+ !non_exhaustive && empty
1124+ }
1125+ ty:: Tuple ( tys) => tys. is_empty ( ) ,
1126+ _ => false ,
1127+ }
1128+ }
1129+
11041130/// Check if this enum can be safely exported based on the "nullable pointer optimization". If it
11051131/// can, return the type that `ty` can be safely converted to, otherwise return `None`.
11061132/// Currently restricted to function pointers, boxes, references, `core::num::NonZero`,
@@ -1117,6 +1143,22 @@ pub(crate) fn repr_nullable_ptr<'tcx>(
11171143 let field_ty = match & ty_def. variants ( ) . raw [ ..] {
11181144 [ var_one, var_two] => match ( & var_one. fields . raw [ ..] , & var_two. fields . raw [ ..] ) {
11191145 ( [ ] , [ field] ) | ( [ field] , [ ] ) => field. ty ( tcx, args) ,
1146+ ( [ field1] , [ field2] ) => {
1147+ if !tcx. features ( ) . result_ffi_guarantees {
1148+ return None ;
1149+ }
1150+
1151+ let ty1 = field1. ty ( tcx, args) ;
1152+ let ty2 = field2. ty ( tcx, args) ;
1153+
1154+ if is_niche_optimization_candidate ( tcx, param_env, ty1) {
1155+ ty2
1156+ } else if is_niche_optimization_candidate ( tcx, param_env, ty2) {
1157+ ty1
1158+ } else {
1159+ return None ;
1160+ }
1161+ }
11201162 _ => return None ,
11211163 } ,
11221164 _ => return None ,
@@ -1202,7 +1244,6 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
12021244 args : GenericArgsRef < ' tcx > ,
12031245 ) -> FfiResult < ' tcx > {
12041246 use FfiResult :: * ;
1205-
12061247 let transparent_with_all_zst_fields = if def. repr ( ) . transparent ( ) {
12071248 if let Some ( field) = transparent_newtype_field ( self . cx . tcx , variant) {
12081249 // Transparent newtypes have at most one non-ZST field which needs to be checked..
@@ -1329,27 +1370,29 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
13291370 return FfiSafe ;
13301371 }
13311372
1373+ if def. is_variant_list_non_exhaustive ( ) && !def. did ( ) . is_local ( ) {
1374+ return FfiUnsafe {
1375+ ty,
1376+ reason : fluent:: lint_improper_ctypes_non_exhaustive,
1377+ help : None ,
1378+ } ;
1379+ }
1380+
13321381 // Check for a repr() attribute to specify the size of the
13331382 // discriminant.
13341383 if !def. repr ( ) . c ( ) && !def. repr ( ) . transparent ( ) && def. repr ( ) . int . is_none ( )
13351384 {
1336- // Special-case types like `Option<extern fn()>`.
1337- if repr_nullable_ptr ( self . cx . tcx , self . cx . param_env , ty , self . mode )
1338- . is_none ( )
1385+ // Special-case types like `Option<extern fn()>` and `Result<extern fn(), ()>`
1386+ if let Some ( ty ) =
1387+ repr_nullable_ptr ( self . cx . tcx , self . cx . param_env , ty , self . mode )
13391388 {
1340- return FfiUnsafe {
1341- ty,
1342- reason : fluent:: lint_improper_ctypes_enum_repr_reason,
1343- help : Some ( fluent:: lint_improper_ctypes_enum_repr_help) ,
1344- } ;
1389+ return self . check_type_for_ffi ( cache, ty) ;
13451390 }
1346- }
13471391
1348- if def. is_variant_list_non_exhaustive ( ) && !def. did ( ) . is_local ( ) {
13491392 return FfiUnsafe {
13501393 ty,
1351- reason : fluent:: lint_improper_ctypes_non_exhaustive ,
1352- help : None ,
1394+ reason : fluent:: lint_improper_ctypes_enum_repr_reason ,
1395+ help : Some ( fluent :: lint_improper_ctypes_enum_repr_help ) ,
13531396 } ;
13541397 }
13551398
0 commit comments