@@ -861,6 +861,31 @@ fn ty_is_known_nonnull<'tcx>(
861
861
. filter_map ( |variant| transparent_newtype_field ( tcx, variant) )
862
862
. any ( |field| ty_is_known_nonnull ( tcx, typing_env, field. ty ( tcx, args) , mode) )
863
863
}
864
+ ty:: Pat ( base, pat) => {
865
+ ty_is_known_nonnull ( tcx, typing_env, * base, mode)
866
+ || match * * pat {
867
+ ty:: PatternKind :: Range { start, end, include_end } => match ( start, end) {
868
+ ( Some ( start) , None ) => {
869
+ start. try_to_bits ( tcx, typing_env) . is_some_and ( |i| i > 0 )
870
+ }
871
+ ( Some ( start) , Some ( end) ) => {
872
+ if let Some ( start) = start. try_to_bits ( tcx, typing_env) {
873
+ if let Some ( end) = end. try_to_bits ( tcx, typing_env) {
874
+ return if include_end {
875
+ // This also works for negative numbers, as we just need
876
+ // to ensure we aren't wrapping over zero.
877
+ start > 0 && end >= start
878
+ } else {
879
+ start > 0 && end > start
880
+ } ;
881
+ }
882
+ }
883
+ false
884
+ }
885
+ _ => false ,
886
+ } ,
887
+ }
888
+ }
864
889
_ => false ,
865
890
}
866
891
}
@@ -891,9 +916,8 @@ fn get_nullable_type<'tcx>(
891
916
} ;
892
917
return get_nullable_type ( tcx, typing_env, inner_field_ty) ;
893
918
}
894
- ty:: Int ( ty) => Ty :: new_int ( tcx, ty) ,
895
- ty:: Uint ( ty) => Ty :: new_uint ( tcx, ty) ,
896
- ty:: RawPtr ( ty, mutbl) => Ty :: new_ptr ( tcx, ty, mutbl) ,
919
+ ty:: Pat ( base, ..) => return get_nullable_type ( tcx, typing_env, base) ,
920
+ ty:: Int ( _) | ty:: Uint ( _) | ty:: RawPtr ( ..) => ty,
897
921
// As these types are always non-null, the nullable equivalent of
898
922
// `Option<T>` of these types are their raw pointer counterparts.
899
923
ty:: Ref ( _region, ty, mutbl) => Ty :: new_ptr ( tcx, ty, mutbl) ,
@@ -949,63 +973,69 @@ pub(crate) fn repr_nullable_ptr<'tcx>(
949
973
ckind : CItemKind ,
950
974
) -> Option < Ty < ' tcx > > {
951
975
debug ! ( "is_repr_nullable_ptr(tcx, ty = {:?})" , ty) ;
952
- if let ty:: Adt ( ty_def, args) = ty. kind ( ) {
953
- let field_ty = match & ty_def. variants ( ) . raw [ ..] {
954
- [ var_one, var_two] => match ( & var_one. fields . raw [ ..] , & var_two. fields . raw [ ..] ) {
955
- ( [ ] , [ field] ) | ( [ field] , [ ] ) => field. ty ( tcx, args) ,
956
- ( [ field1] , [ field2] ) => {
957
- let ty1 = field1. ty ( tcx, args) ;
958
- let ty2 = field2. ty ( tcx, args) ;
959
-
960
- if is_niche_optimization_candidate ( tcx, typing_env, ty1) {
961
- ty2
962
- } else if is_niche_optimization_candidate ( tcx, typing_env, ty2) {
963
- ty1
964
- } else {
965
- return None ;
976
+ match ty. kind ( ) {
977
+ ty:: Adt ( ty_def, args) => {
978
+ let field_ty = match & ty_def. variants ( ) . raw [ ..] {
979
+ [ var_one, var_two] => match ( & var_one. fields . raw [ ..] , & var_two. fields . raw [ ..] ) {
980
+ ( [ ] , [ field] ) | ( [ field] , [ ] ) => field. ty ( tcx, args) ,
981
+ ( [ field1] , [ field2] ) => {
982
+ let ty1 = field1. ty ( tcx, args) ;
983
+ let ty2 = field2. ty ( tcx, args) ;
984
+
985
+ if is_niche_optimization_candidate ( tcx, typing_env, ty1) {
986
+ ty2
987
+ } else if is_niche_optimization_candidate ( tcx, typing_env, ty2) {
988
+ ty1
989
+ } else {
990
+ return None ;
991
+ }
966
992
}
967
- }
993
+ _ => return None ,
994
+ } ,
968
995
_ => return None ,
969
- } ,
970
- _ => return None ,
971
- } ;
996
+ } ;
972
997
973
- if !ty_is_known_nonnull ( tcx, typing_env, field_ty, ckind) {
974
- return None ;
975
- }
998
+ if !ty_is_known_nonnull ( tcx, typing_env, field_ty, ckind) {
999
+ return None ;
1000
+ }
976
1001
977
- // At this point, the field's type is known to be nonnull and the parent enum is Option-like.
978
- // If the computed size for the field and the enum are different, the nonnull optimization isn't
979
- // being applied (and we've got a problem somewhere).
980
- let compute_size_skeleton = |t| SizeSkeleton :: compute ( t, tcx, typing_env) . ok ( ) ;
981
- if !compute_size_skeleton ( ty) ?. same_size ( compute_size_skeleton ( field_ty) ?) {
982
- bug ! ( "improper_ctypes: Option nonnull optimization not applied?" ) ;
983
- }
1002
+ // At this point, the field's type is known to be nonnull and the parent enum is Option-like.
1003
+ // If the computed size for the field and the enum are different, the nonnull optimization isn't
1004
+ // being applied (and we've got a problem somewhere).
1005
+ let compute_size_skeleton = |t| SizeSkeleton :: compute ( t, tcx, typing_env) . ok ( ) ;
1006
+ if !compute_size_skeleton ( ty) ?. same_size ( compute_size_skeleton ( field_ty) ?) {
1007
+ bug ! ( "improper_ctypes: Option nonnull optimization not applied?" ) ;
1008
+ }
984
1009
985
- // Return the nullable type this Option-like enum can be safely represented with.
986
- let field_ty_layout = tcx. layout_of ( typing_env. as_query_input ( field_ty) ) ;
987
- if field_ty_layout. is_err ( ) && !field_ty. has_non_region_param ( ) {
988
- bug ! ( "should be able to compute the layout of non-polymorphic type" ) ;
989
- }
1010
+ // Return the nullable type this Option-like enum can be safely represented with.
1011
+ let field_ty_layout = tcx. layout_of ( typing_env. as_query_input ( field_ty) ) ;
1012
+ if field_ty_layout. is_err ( ) && !field_ty. has_non_region_param ( ) {
1013
+ bug ! ( "should be able to compute the layout of non-polymorphic type" ) ;
1014
+ }
990
1015
991
- let field_ty_abi = & field_ty_layout. ok ( ) ?. backend_repr ;
992
- if let BackendRepr :: Scalar ( field_ty_scalar) = field_ty_abi {
993
- match field_ty_scalar. valid_range ( & tcx) {
994
- WrappingRange { start : 0 , end }
995
- if end == field_ty_scalar. size ( & tcx) . unsigned_int_max ( ) - 1 =>
996
- {
997
- return Some ( get_nullable_type ( tcx, typing_env, field_ty) . unwrap ( ) ) ;
998
- }
999
- WrappingRange { start : 1 , .. } => {
1000
- return Some ( get_nullable_type ( tcx, typing_env, field_ty) . unwrap ( ) ) ;
1001
- }
1002
- WrappingRange { start, end } => {
1003
- unreachable ! ( "Unhandled start and end range: ({}, {})" , start, end)
1004
- }
1005
- } ;
1016
+ let field_ty_abi = & field_ty_layout. ok ( ) ?. backend_repr ;
1017
+ if let BackendRepr :: Scalar ( field_ty_scalar) = field_ty_abi {
1018
+ match field_ty_scalar. valid_range ( & tcx) {
1019
+ WrappingRange { start : 0 , end }
1020
+ if end == field_ty_scalar. size ( & tcx) . unsigned_int_max ( ) - 1 =>
1021
+ {
1022
+ return Some ( get_nullable_type ( tcx, typing_env, field_ty) . unwrap ( ) ) ;
1023
+ }
1024
+ WrappingRange { start : 1 , .. } => {
1025
+ return Some ( get_nullable_type ( tcx, typing_env, field_ty) . unwrap ( ) ) ;
1026
+ }
1027
+ WrappingRange { start, end } => {
1028
+ unreachable ! ( "Unhandled start and end range: ({}, {})" , start, end)
1029
+ }
1030
+ } ;
1031
+ }
1032
+ None
1006
1033
}
1034
+ ty:: Pat ( base, pat) => match * * pat {
1035
+ ty:: PatternKind :: Range { .. } => get_nullable_type ( tcx, typing_env, * base) ,
1036
+ } ,
1037
+ _ => None ,
1007
1038
}
1008
- None
1009
1039
}
1010
1040
1011
1041
impl < ' a , ' tcx > ImproperCTypesVisitor < ' a , ' tcx > {
@@ -1240,11 +1270,9 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
1240
1270
help : Some ( fluent:: lint_improper_ctypes_char_help) ,
1241
1271
} ,
1242
1272
1243
- ty:: Pat ( ..) => FfiUnsafe {
1244
- ty,
1245
- reason : fluent:: lint_improper_ctypes_pat_reason,
1246
- help : Some ( fluent:: lint_improper_ctypes_pat_help) ,
1247
- } ,
1273
+ // It's just extra invariants on the type that you need to uphold,
1274
+ // but only the base type is relevant for being representable in FFI.
1275
+ ty:: Pat ( base, ..) => self . check_type_for_ffi ( acc, base) ,
1248
1276
1249
1277
ty:: Int ( ty:: IntTy :: I128 ) | ty:: Uint ( ty:: UintTy :: U128 ) => {
1250
1278
FfiUnsafe { ty, reason : fluent:: lint_improper_ctypes_128bit, help : None }
0 commit comments