@@ -861,6 +861,37 @@ fn ty_is_known_nonnull<'tcx>(
861861 . filter_map ( |variant| transparent_newtype_field ( tcx, variant) )
862862 . any ( |field| ty_is_known_nonnull ( tcx, typing_env, field. ty ( tcx, args) , mode) )
863863 }
864+ ty:: Pat ( base, pat) => {
865+ ty_is_known_nonnull ( tcx, typing_env, * base, mode)
866+ || Option :: unwrap_or_default (
867+ try {
868+ match * * pat {
869+ ty:: PatternKind :: Range { start, end, include_end } => {
870+ match ( start, end) {
871+ ( Some ( start) , None ) => {
872+ start. try_to_value ( ) ?. try_to_bits ( tcx, typing_env) ? > 0
873+ }
874+ ( Some ( start) , Some ( end) ) => {
875+ let start =
876+ start. try_to_value ( ) ?. try_to_bits ( tcx, typing_env) ?;
877+ let end =
878+ end. try_to_value ( ) ?. try_to_bits ( tcx, typing_env) ?;
879+
880+ if include_end {
881+ // This also works for negative numbers, as we just need
882+ // to ensure we aren't wrapping over zero.
883+ start > 0 && end >= start
884+ } else {
885+ start > 0 && end > start
886+ }
887+ }
888+ _ => false ,
889+ }
890+ }
891+ }
892+ } ,
893+ )
894+ }
864895 _ => false ,
865896 }
866897}
@@ -891,9 +922,8 @@ fn get_nullable_type<'tcx>(
891922 } ;
892923 return get_nullable_type ( tcx, typing_env, inner_field_ty) ;
893924 }
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) ,
925+ ty:: Pat ( base, ..) => return get_nullable_type ( tcx, typing_env, base) ,
926+ ty:: Int ( _) | ty:: Uint ( _) | ty:: RawPtr ( ..) => ty,
897927 // As these types are always non-null, the nullable equivalent of
898928 // `Option<T>` of these types are their raw pointer counterparts.
899929 ty:: Ref ( _region, ty, mutbl) => Ty :: new_ptr ( tcx, ty, mutbl) ,
@@ -949,63 +979,69 @@ pub(crate) fn repr_nullable_ptr<'tcx>(
949979 ckind : CItemKind ,
950980) -> Option < Ty < ' tcx > > {
951981 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 ;
982+ match ty. kind ( ) {
983+ ty:: Adt ( ty_def, args) => {
984+ let field_ty = match & ty_def. variants ( ) . raw [ ..] {
985+ [ var_one, var_two] => match ( & var_one. fields . raw [ ..] , & var_two. fields . raw [ ..] ) {
986+ ( [ ] , [ field] ) | ( [ field] , [ ] ) => field. ty ( tcx, args) ,
987+ ( [ field1] , [ field2] ) => {
988+ let ty1 = field1. ty ( tcx, args) ;
989+ let ty2 = field2. ty ( tcx, args) ;
990+
991+ if is_niche_optimization_candidate ( tcx, typing_env, ty1) {
992+ ty2
993+ } else if is_niche_optimization_candidate ( tcx, typing_env, ty2) {
994+ ty1
995+ } else {
996+ return None ;
997+ }
966998 }
967- }
999+ _ => return None ,
1000+ } ,
9681001 _ => return None ,
969- } ,
970- _ => return None ,
971- } ;
1002+ } ;
9721003
973- if !ty_is_known_nonnull ( tcx, typing_env, field_ty, ckind) {
974- return None ;
975- }
1004+ if !ty_is_known_nonnull ( tcx, typing_env, field_ty, ckind) {
1005+ return None ;
1006+ }
9761007
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- }
1008+ // At this point, the field's type is known to be nonnull and the parent enum is Option-like.
1009+ // If the computed size for the field and the enum are different, the nonnull optimization isn't
1010+ // being applied (and we've got a problem somewhere).
1011+ let compute_size_skeleton = |t| SizeSkeleton :: compute ( t, tcx, typing_env) . ok ( ) ;
1012+ if !compute_size_skeleton ( ty) ?. same_size ( compute_size_skeleton ( field_ty) ?) {
1013+ bug ! ( "improper_ctypes: Option nonnull optimization not applied?" ) ;
1014+ }
9841015
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- }
1016+ // Return the nullable type this Option-like enum can be safely represented with.
1017+ let field_ty_layout = tcx. layout_of ( typing_env. as_query_input ( field_ty) ) ;
1018+ if field_ty_layout. is_err ( ) && !field_ty. has_non_region_param ( ) {
1019+ bug ! ( "should be able to compute the layout of non-polymorphic type" ) ;
1020+ }
9901021
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- } ;
1022+ let field_ty_abi = & field_ty_layout. ok ( ) ?. backend_repr ;
1023+ if let BackendRepr :: Scalar ( field_ty_scalar) = field_ty_abi {
1024+ match field_ty_scalar. valid_range ( & tcx) {
1025+ WrappingRange { start : 0 , end }
1026+ if end == field_ty_scalar. size ( & tcx) . unsigned_int_max ( ) - 1 =>
1027+ {
1028+ return Some ( get_nullable_type ( tcx, typing_env, field_ty) . unwrap ( ) ) ;
1029+ }
1030+ WrappingRange { start : 1 , .. } => {
1031+ return Some ( get_nullable_type ( tcx, typing_env, field_ty) . unwrap ( ) ) ;
1032+ }
1033+ WrappingRange { start, end } => {
1034+ unreachable ! ( "Unhandled start and end range: ({}, {})" , start, end)
1035+ }
1036+ } ;
1037+ }
1038+ None
10061039 }
1040+ ty:: Pat ( base, pat) => match * * pat {
1041+ ty:: PatternKind :: Range { .. } => get_nullable_type ( tcx, typing_env, * base) ,
1042+ } ,
1043+ _ => None ,
10071044 }
1008- None
10091045}
10101046
10111047impl < ' a , ' tcx > ImproperCTypesVisitor < ' a , ' tcx > {
@@ -1240,11 +1276,9 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
12401276 help : Some ( fluent:: lint_improper_ctypes_char_help) ,
12411277 } ,
12421278
1243- ty:: Pat ( ..) => FfiUnsafe {
1244- ty,
1245- reason : fluent:: lint_improper_ctypes_pat_reason,
1246- help : Some ( fluent:: lint_improper_ctypes_pat_help) ,
1247- } ,
1279+ // It's just extra invariants on the type that you need to uphold,
1280+ // but only the base type is relevant for being representable in FFI.
1281+ ty:: Pat ( base, ..) => self . check_type_for_ffi ( acc, base) ,
12481282
12491283 ty:: Int ( ty:: IntTy :: I128 ) | ty:: Uint ( ty:: UintTy :: U128 ) => {
12501284 FfiUnsafe { ty, reason : fluent:: lint_improper_ctypes_128bit, help : None }
0 commit comments