@@ -870,6 +870,37 @@ fn ty_is_known_nonnull<'tcx>(
870
870
. filter_map ( |variant| transparent_newtype_field ( tcx, variant) )
871
871
. any ( |field| ty_is_known_nonnull ( tcx, typing_env, field. ty ( tcx, args) , mode) )
872
872
}
873
+ ty:: Pat ( base, pat) => {
874
+ ty_is_known_nonnull ( tcx, typing_env, * base, mode)
875
+ || Option :: unwrap_or_default (
876
+ try {
877
+ match * * pat {
878
+ ty:: PatternKind :: Range { start, end, include_end } => {
879
+ match ( start, end) {
880
+ ( Some ( start) , None ) => {
881
+ start. try_to_value ( ) ?. try_to_bits ( tcx, typing_env) ? > 0
882
+ }
883
+ ( Some ( start) , Some ( end) ) => {
884
+ let start =
885
+ start. try_to_value ( ) ?. try_to_bits ( tcx, typing_env) ?;
886
+ let end =
887
+ end. try_to_value ( ) ?. try_to_bits ( tcx, typing_env) ?;
888
+
889
+ if include_end {
890
+ // This also works for negative numbers, as we just need
891
+ // to ensure we aren't wrapping over zero.
892
+ start > 0 && end >= start
893
+ } else {
894
+ start > 0 && end > start
895
+ }
896
+ }
897
+ _ => false ,
898
+ }
899
+ }
900
+ }
901
+ } ,
902
+ )
903
+ }
873
904
_ => false ,
874
905
}
875
906
}
@@ -900,9 +931,8 @@ fn get_nullable_type<'tcx>(
900
931
} ;
901
932
return get_nullable_type ( tcx, typing_env, inner_field_ty) ;
902
933
}
903
- ty:: Int ( ty) => Ty :: new_int ( tcx, ty) ,
904
- ty:: Uint ( ty) => Ty :: new_uint ( tcx, ty) ,
905
- ty:: RawPtr ( ty, mutbl) => Ty :: new_ptr ( tcx, ty, mutbl) ,
934
+ ty:: Pat ( base, ..) => return get_nullable_type ( tcx, typing_env, base) ,
935
+ ty:: Int ( _) | ty:: Uint ( _) | ty:: RawPtr ( ..) => ty,
906
936
// As these types are always non-null, the nullable equivalent of
907
937
// `Option<T>` of these types are their raw pointer counterparts.
908
938
ty:: Ref ( _region, ty, mutbl) => Ty :: new_ptr ( tcx, ty, mutbl) ,
@@ -958,63 +988,69 @@ pub(crate) fn repr_nullable_ptr<'tcx>(
958
988
ckind : CItemKind ,
959
989
) -> Option < Ty < ' tcx > > {
960
990
debug ! ( "is_repr_nullable_ptr(tcx, ty = {:?})" , ty) ;
961
- if let ty:: Adt ( ty_def, args) = ty. kind ( ) {
962
- let field_ty = match & ty_def. variants ( ) . raw [ ..] {
963
- [ var_one, var_two] => match ( & var_one. fields . raw [ ..] , & var_two. fields . raw [ ..] ) {
964
- ( [ ] , [ field] ) | ( [ field] , [ ] ) => field. ty ( tcx, args) ,
965
- ( [ field1] , [ field2] ) => {
966
- let ty1 = field1. ty ( tcx, args) ;
967
- let ty2 = field2. ty ( tcx, args) ;
968
-
969
- if is_niche_optimization_candidate ( tcx, typing_env, ty1) {
970
- ty2
971
- } else if is_niche_optimization_candidate ( tcx, typing_env, ty2) {
972
- ty1
973
- } else {
974
- return None ;
991
+ match ty. kind ( ) {
992
+ ty:: Adt ( ty_def, args) => {
993
+ let field_ty = match & ty_def. variants ( ) . raw [ ..] {
994
+ [ var_one, var_two] => match ( & var_one. fields . raw [ ..] , & var_two. fields . raw [ ..] ) {
995
+ ( [ ] , [ field] ) | ( [ field] , [ ] ) => field. ty ( tcx, args) ,
996
+ ( [ field1] , [ field2] ) => {
997
+ let ty1 = field1. ty ( tcx, args) ;
998
+ let ty2 = field2. ty ( tcx, args) ;
999
+
1000
+ if is_niche_optimization_candidate ( tcx, typing_env, ty1) {
1001
+ ty2
1002
+ } else if is_niche_optimization_candidate ( tcx, typing_env, ty2) {
1003
+ ty1
1004
+ } else {
1005
+ return None ;
1006
+ }
975
1007
}
976
- }
1008
+ _ => return None ,
1009
+ } ,
977
1010
_ => return None ,
978
- } ,
979
- _ => return None ,
980
- } ;
1011
+ } ;
981
1012
982
- if !ty_is_known_nonnull ( tcx, typing_env, field_ty, ckind) {
983
- return None ;
984
- }
1013
+ if !ty_is_known_nonnull ( tcx, typing_env, field_ty, ckind) {
1014
+ return None ;
1015
+ }
985
1016
986
- // At this point, the field's type is known to be nonnull and the parent enum is Option-like.
987
- // If the computed size for the field and the enum are different, the nonnull optimization isn't
988
- // being applied (and we've got a problem somewhere).
989
- let compute_size_skeleton = |t| SizeSkeleton :: compute ( t, tcx, typing_env) . ok ( ) ;
990
- if !compute_size_skeleton ( ty) ?. same_size ( compute_size_skeleton ( field_ty) ?) {
991
- bug ! ( "improper_ctypes: Option nonnull optimization not applied?" ) ;
992
- }
1017
+ // At this point, the field's type is known to be nonnull and the parent enum is Option-like.
1018
+ // If the computed size for the field and the enum are different, the nonnull optimization isn't
1019
+ // being applied (and we've got a problem somewhere).
1020
+ let compute_size_skeleton = |t| SizeSkeleton :: compute ( t, tcx, typing_env) . ok ( ) ;
1021
+ if !compute_size_skeleton ( ty) ?. same_size ( compute_size_skeleton ( field_ty) ?) {
1022
+ bug ! ( "improper_ctypes: Option nonnull optimization not applied?" ) ;
1023
+ }
993
1024
994
- // Return the nullable type this Option-like enum can be safely represented with.
995
- let field_ty_layout = tcx. layout_of ( typing_env. as_query_input ( field_ty) ) ;
996
- if field_ty_layout. is_err ( ) && !field_ty. has_non_region_param ( ) {
997
- bug ! ( "should be able to compute the layout of non-polymorphic type" ) ;
998
- }
1025
+ // Return the nullable type this Option-like enum can be safely represented with.
1026
+ let field_ty_layout = tcx. layout_of ( typing_env. as_query_input ( field_ty) ) ;
1027
+ if field_ty_layout. is_err ( ) && !field_ty. has_non_region_param ( ) {
1028
+ bug ! ( "should be able to compute the layout of non-polymorphic type" ) ;
1029
+ }
999
1030
1000
- let field_ty_abi = & field_ty_layout. ok ( ) ?. backend_repr ;
1001
- if let BackendRepr :: Scalar ( field_ty_scalar) = field_ty_abi {
1002
- match field_ty_scalar. valid_range ( & tcx) {
1003
- WrappingRange { start : 0 , end }
1004
- if end == field_ty_scalar. size ( & tcx) . unsigned_int_max ( ) - 1 =>
1005
- {
1006
- return Some ( get_nullable_type ( tcx, typing_env, field_ty) . unwrap ( ) ) ;
1007
- }
1008
- WrappingRange { start : 1 , .. } => {
1009
- return Some ( get_nullable_type ( tcx, typing_env, field_ty) . unwrap ( ) ) ;
1010
- }
1011
- WrappingRange { start, end } => {
1012
- unreachable ! ( "Unhandled start and end range: ({}, {})" , start, end)
1013
- }
1014
- } ;
1031
+ let field_ty_abi = & field_ty_layout. ok ( ) ?. backend_repr ;
1032
+ if let BackendRepr :: Scalar ( field_ty_scalar) = field_ty_abi {
1033
+ match field_ty_scalar. valid_range ( & tcx) {
1034
+ WrappingRange { start : 0 , end }
1035
+ if end == field_ty_scalar. size ( & tcx) . unsigned_int_max ( ) - 1 =>
1036
+ {
1037
+ return Some ( get_nullable_type ( tcx, typing_env, field_ty) . unwrap ( ) ) ;
1038
+ }
1039
+ WrappingRange { start : 1 , .. } => {
1040
+ return Some ( get_nullable_type ( tcx, typing_env, field_ty) . unwrap ( ) ) ;
1041
+ }
1042
+ WrappingRange { start, end } => {
1043
+ unreachable ! ( "Unhandled start and end range: ({}, {})" , start, end)
1044
+ }
1045
+ } ;
1046
+ }
1047
+ None
1015
1048
}
1049
+ ty:: Pat ( base, pat) => match * * pat {
1050
+ ty:: PatternKind :: Range { .. } => get_nullable_type ( tcx, typing_env, * base) ,
1051
+ } ,
1052
+ _ => None ,
1016
1053
}
1017
- None
1018
1054
}
1019
1055
1020
1056
impl < ' a , ' tcx > ImproperCTypesVisitor < ' a , ' tcx > {
@@ -1249,11 +1285,9 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
1249
1285
help : Some ( fluent:: lint_improper_ctypes_char_help) ,
1250
1286
} ,
1251
1287
1252
- ty:: Pat ( ..) => FfiUnsafe {
1253
- ty,
1254
- reason : fluent:: lint_improper_ctypes_pat_reason,
1255
- help : Some ( fluent:: lint_improper_ctypes_pat_help) ,
1256
- } ,
1288
+ // It's just extra invariants on the type that you need to uphold,
1289
+ // but only the base type is relevant for being representable in FFI.
1290
+ ty:: Pat ( base, ..) => self . check_type_for_ffi ( acc, base) ,
1257
1291
1258
1292
ty:: Int ( ty:: IntTy :: I128 ) | ty:: Uint ( ty:: UintTy :: U128 ) => {
1259
1293
FfiUnsafe { ty, reason : fluent:: lint_improper_ctypes_128bit, help : None }
0 commit comments