@@ -877,6 +877,37 @@ fn ty_is_known_nonnull<'tcx>(
877877 . filter_map ( |variant| transparent_newtype_field ( tcx, variant) )
878878 . any ( |field| ty_is_known_nonnull ( tcx, typing_env, field. ty ( tcx, args) , mode) )
879879 }
880+ ty:: Pat ( base, pat) => {
881+ ty_is_known_nonnull ( tcx, typing_env, * base, mode)
882+ || Option :: unwrap_or_default (
883+ try {
884+ match * * pat {
885+ ty:: PatternKind :: Range { start, end, include_end } => {
886+ match ( start, end) {
887+ ( Some ( start) , None ) => {
888+ start. try_to_value ( ) ?. try_to_bits ( tcx, typing_env) ? > 0
889+ }
890+ ( Some ( start) , Some ( end) ) => {
891+ let start =
892+ start. try_to_value ( ) ?. try_to_bits ( tcx, typing_env) ?;
893+ let end =
894+ end. try_to_value ( ) ?. try_to_bits ( tcx, typing_env) ?;
895+
896+ if include_end {
897+ // This also works for negative numbers, as we just need
898+ // to ensure we aren't wrapping over zero.
899+ start > 0 && end >= start
900+ } else {
901+ start > 0 && end > start
902+ }
903+ }
904+ _ => false ,
905+ }
906+ }
907+ }
908+ } ,
909+ )
910+ }
880911 _ => false ,
881912 }
882913}
@@ -907,9 +938,8 @@ fn get_nullable_type<'tcx>(
907938 } ;
908939 return get_nullable_type ( tcx, typing_env, inner_field_ty) ;
909940 }
910- ty:: Int ( ty) => Ty :: new_int ( tcx, ty) ,
911- ty:: Uint ( ty) => Ty :: new_uint ( tcx, ty) ,
912- ty:: RawPtr ( ty, mutbl) => Ty :: new_ptr ( tcx, ty, mutbl) ,
941+ ty:: Pat ( base, ..) => return get_nullable_type ( tcx, typing_env, base) ,
942+ ty:: Int ( _) | ty:: Uint ( _) | ty:: RawPtr ( ..) => ty,
913943 // As these types are always non-null, the nullable equivalent of
914944 // `Option<T>` of these types are their raw pointer counterparts.
915945 ty:: Ref ( _region, ty, mutbl) => Ty :: new_ptr ( tcx, ty, mutbl) ,
@@ -965,63 +995,69 @@ pub(crate) fn repr_nullable_ptr<'tcx>(
965995 ckind : CItemKind ,
966996) -> Option < Ty < ' tcx > > {
967997 debug ! ( "is_repr_nullable_ptr(tcx, ty = {:?})" , ty) ;
968- if let ty:: Adt ( ty_def, args) = ty. kind ( ) {
969- let field_ty = match & ty_def. variants ( ) . raw [ ..] {
970- [ var_one, var_two] => match ( & var_one. fields . raw [ ..] , & var_two. fields . raw [ ..] ) {
971- ( [ ] , [ field] ) | ( [ field] , [ ] ) => field. ty ( tcx, args) ,
972- ( [ field1] , [ field2] ) => {
973- let ty1 = field1. ty ( tcx, args) ;
974- let ty2 = field2. ty ( tcx, args) ;
975-
976- if is_niche_optimization_candidate ( tcx, typing_env, ty1) {
977- ty2
978- } else if is_niche_optimization_candidate ( tcx, typing_env, ty2) {
979- ty1
980- } else {
981- return None ;
998+ match ty. kind ( ) {
999+ ty:: Adt ( ty_def, args) => {
1000+ let field_ty = match & ty_def. variants ( ) . raw [ ..] {
1001+ [ var_one, var_two] => match ( & var_one. fields . raw [ ..] , & var_two. fields . raw [ ..] ) {
1002+ ( [ ] , [ field] ) | ( [ field] , [ ] ) => field. ty ( tcx, args) ,
1003+ ( [ field1] , [ field2] ) => {
1004+ let ty1 = field1. ty ( tcx, args) ;
1005+ let ty2 = field2. ty ( tcx, args) ;
1006+
1007+ if is_niche_optimization_candidate ( tcx, typing_env, ty1) {
1008+ ty2
1009+ } else if is_niche_optimization_candidate ( tcx, typing_env, ty2) {
1010+ ty1
1011+ } else {
1012+ return None ;
1013+ }
9821014 }
983- }
1015+ _ => return None ,
1016+ } ,
9841017 _ => return None ,
985- } ,
986- _ => return None ,
987- } ;
1018+ } ;
9881019
989- if !ty_is_known_nonnull ( tcx, typing_env, field_ty, ckind) {
990- return None ;
991- }
1020+ if !ty_is_known_nonnull ( tcx, typing_env, field_ty, ckind) {
1021+ return None ;
1022+ }
9921023
993- // At this point, the field's type is known to be nonnull and the parent enum is Option-like.
994- // If the computed size for the field and the enum are different, the nonnull optimization isn't
995- // being applied (and we've got a problem somewhere).
996- let compute_size_skeleton = |t| SizeSkeleton :: compute ( t, tcx, typing_env) . ok ( ) ;
997- if !compute_size_skeleton ( ty) ?. same_size ( compute_size_skeleton ( field_ty) ?) {
998- bug ! ( "improper_ctypes: Option nonnull optimization not applied?" ) ;
999- }
1024+ // At this point, the field's type is known to be nonnull and the parent enum is Option-like.
1025+ // If the computed size for the field and the enum are different, the nonnull optimization isn't
1026+ // being applied (and we've got a problem somewhere).
1027+ let compute_size_skeleton = |t| SizeSkeleton :: compute ( t, tcx, typing_env) . ok ( ) ;
1028+ if !compute_size_skeleton ( ty) ?. same_size ( compute_size_skeleton ( field_ty) ?) {
1029+ bug ! ( "improper_ctypes: Option nonnull optimization not applied?" ) ;
1030+ }
10001031
1001- // Return the nullable type this Option-like enum can be safely represented with.
1002- let field_ty_layout = tcx. layout_of ( typing_env. as_query_input ( field_ty) ) ;
1003- if field_ty_layout. is_err ( ) && !field_ty. has_non_region_param ( ) {
1004- bug ! ( "should be able to compute the layout of non-polymorphic type" ) ;
1005- }
1032+ // Return the nullable type this Option-like enum can be safely represented with.
1033+ let field_ty_layout = tcx. layout_of ( typing_env. as_query_input ( field_ty) ) ;
1034+ if field_ty_layout. is_err ( ) && !field_ty. has_non_region_param ( ) {
1035+ bug ! ( "should be able to compute the layout of non-polymorphic type" ) ;
1036+ }
10061037
1007- let field_ty_abi = & field_ty_layout. ok ( ) ?. backend_repr ;
1008- if let BackendRepr :: Scalar ( field_ty_scalar) = field_ty_abi {
1009- match field_ty_scalar. valid_range ( & tcx) {
1010- WrappingRange { start : 0 , end }
1011- if end == field_ty_scalar. size ( & tcx) . unsigned_int_max ( ) - 1 =>
1012- {
1013- return Some ( get_nullable_type ( tcx, typing_env, field_ty) . unwrap ( ) ) ;
1014- }
1015- WrappingRange { start : 1 , .. } => {
1016- return Some ( get_nullable_type ( tcx, typing_env, field_ty) . unwrap ( ) ) ;
1017- }
1018- WrappingRange { start, end } => {
1019- unreachable ! ( "Unhandled start and end range: ({}, {})" , start, end)
1020- }
1021- } ;
1038+ let field_ty_abi = & field_ty_layout. ok ( ) ?. backend_repr ;
1039+ if let BackendRepr :: Scalar ( field_ty_scalar) = field_ty_abi {
1040+ match field_ty_scalar. valid_range ( & tcx) {
1041+ WrappingRange { start : 0 , end }
1042+ if end == field_ty_scalar. size ( & tcx) . unsigned_int_max ( ) - 1 =>
1043+ {
1044+ return Some ( get_nullable_type ( tcx, typing_env, field_ty) . unwrap ( ) ) ;
1045+ }
1046+ WrappingRange { start : 1 , .. } => {
1047+ return Some ( get_nullable_type ( tcx, typing_env, field_ty) . unwrap ( ) ) ;
1048+ }
1049+ WrappingRange { start, end } => {
1050+ unreachable ! ( "Unhandled start and end range: ({}, {})" , start, end)
1051+ }
1052+ } ;
1053+ }
1054+ None
10221055 }
1056+ ty:: Pat ( base, pat) => match * * pat {
1057+ ty:: PatternKind :: Range { .. } => get_nullable_type ( tcx, typing_env, * base) ,
1058+ } ,
1059+ _ => None ,
10231060 }
1024- None
10251061}
10261062
10271063impl < ' a , ' tcx > ImproperCTypesVisitor < ' a , ' tcx > {
@@ -1256,11 +1292,9 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
12561292 help : Some ( fluent:: lint_improper_ctypes_char_help) ,
12571293 } ,
12581294
1259- ty:: Pat ( ..) => FfiUnsafe {
1260- ty,
1261- reason : fluent:: lint_improper_ctypes_pat_reason,
1262- help : Some ( fluent:: lint_improper_ctypes_pat_help) ,
1263- } ,
1295+ // It's just extra invariants on the type that you need to uphold,
1296+ // but only the base type is relevant for being representable in FFI.
1297+ ty:: Pat ( base, ..) => self . check_type_for_ffi ( acc, base) ,
12641298
12651299 ty:: Int ( ty:: IntTy :: I128 ) | ty:: Uint ( ty:: UintTy :: U128 ) => {
12661300 FfiUnsafe { ty, reason : fluent:: lint_improper_ctypes_128bit, help : None }
0 commit comments