@@ -877,6 +877,37 @@ fn ty_is_known_nonnull<'tcx>(
877
877
. filter_map ( |variant| transparent_newtype_field ( tcx, variant) )
878
878
. any ( |field| ty_is_known_nonnull ( tcx, typing_env, field. ty ( tcx, args) , mode) )
879
879
}
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
+ }
880
911
_ => false ,
881
912
}
882
913
}
@@ -907,9 +938,8 @@ fn get_nullable_type<'tcx>(
907
938
} ;
908
939
return get_nullable_type ( tcx, typing_env, inner_field_ty) ;
909
940
}
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,
913
943
// As these types are always non-null, the nullable equivalent of
914
944
// `Option<T>` of these types are their raw pointer counterparts.
915
945
ty:: Ref ( _region, ty, mutbl) => Ty :: new_ptr ( tcx, ty, mutbl) ,
@@ -965,63 +995,69 @@ pub(crate) fn repr_nullable_ptr<'tcx>(
965
995
ckind : CItemKind ,
966
996
) -> Option < Ty < ' tcx > > {
967
997
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
+ }
982
1014
}
983
- }
1015
+ _ => return None ,
1016
+ } ,
984
1017
_ => return None ,
985
- } ,
986
- _ => return None ,
987
- } ;
1018
+ } ;
988
1019
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
+ }
992
1023
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
+ }
1000
1031
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
+ }
1006
1037
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
1022
1055
}
1056
+ ty:: Pat ( base, pat) => match * * pat {
1057
+ ty:: PatternKind :: Range { .. } => get_nullable_type ( tcx, typing_env, * base) ,
1058
+ } ,
1059
+ _ => None ,
1023
1060
}
1024
- None
1025
1061
}
1026
1062
1027
1063
impl < ' a , ' tcx > ImproperCTypesVisitor < ' a , ' tcx > {
@@ -1256,11 +1292,9 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
1256
1292
help : Some ( fluent:: lint_improper_ctypes_char_help) ,
1257
1293
} ,
1258
1294
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) ,
1264
1298
1265
1299
ty:: Int ( ty:: IntTy :: I128 ) | ty:: Uint ( ty:: UintTy :: U128 ) => {
1266
1300
FfiUnsafe { ty, reason : fluent:: lint_improper_ctypes_128bit, help : None }
0 commit comments