@@ -870,6 +870,37 @@ fn ty_is_known_nonnull<'tcx>(
870870 . filter_map ( |variant| transparent_newtype_field ( tcx, variant) )
871871 . any ( |field| ty_is_known_nonnull ( tcx, typing_env, field. ty ( tcx, args) , mode) )
872872 }
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+ }
873904 _ => false ,
874905 }
875906}
@@ -900,9 +931,8 @@ fn get_nullable_type<'tcx>(
900931 } ;
901932 return get_nullable_type ( tcx, typing_env, inner_field_ty) ;
902933 }
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,
906936 // As these types are always non-null, the nullable equivalent of
907937 // `Option<T>` of these types are their raw pointer counterparts.
908938 ty:: Ref ( _region, ty, mutbl) => Ty :: new_ptr ( tcx, ty, mutbl) ,
@@ -958,63 +988,69 @@ pub(crate) fn repr_nullable_ptr<'tcx>(
958988 ckind : CItemKind ,
959989) -> Option < Ty < ' tcx > > {
960990 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+ }
9751007 }
976- }
1008+ _ => return None ,
1009+ } ,
9771010 _ => return None ,
978- } ,
979- _ => return None ,
980- } ;
1011+ } ;
9811012
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+ }
9851016
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+ }
9931024
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+ }
9991030
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
10151048 }
1049+ ty:: Pat ( base, pat) => match * * pat {
1050+ ty:: PatternKind :: Range { .. } => get_nullable_type ( tcx, typing_env, * base) ,
1051+ } ,
1052+ _ => None ,
10161053 }
1017- None
10181054}
10191055
10201056impl < ' a , ' tcx > ImproperCTypesVisitor < ' a , ' tcx > {
@@ -1249,11 +1285,9 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
12491285 help : Some ( fluent:: lint_improper_ctypes_char_help) ,
12501286 } ,
12511287
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) ,
12571291
12581292 ty:: Int ( ty:: IntTy :: I128 ) | ty:: Uint ( ty:: UintTy :: U128 ) => {
12591293 FfiUnsafe { ty, reason : fluent:: lint_improper_ctypes_128bit, help : None }
0 commit comments