@@ -877,6 +877,37 @@ fn ty_is_known_nonnull<'tcx>(
877877                . filter_map ( |variant| transparent_newtype_field ( tcx,  variant) ) 
878878                . any ( |field| ty_is_known_nonnull ( tcx,  typing_env,  field. ty ( tcx,  args) ,  mode) ) 
879879        } 
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+         } 
880911        _ => false , 
881912    } 
882913} 
@@ -907,9 +938,8 @@ fn get_nullable_type<'tcx>(
907938            } ; 
908939            return  get_nullable_type ( tcx,  typing_env,  inner_field_ty) ; 
909940        } 
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, 
913943        // As these types are always non-null, the nullable equivalent of 
914944        // `Option<T>` of these types are their raw pointer counterparts. 
915945        ty:: Ref ( _region,  ty,  mutbl)  => Ty :: new_ptr ( tcx,  ty,  mutbl) , 
@@ -965,63 +995,69 @@ pub(crate) fn repr_nullable_ptr<'tcx>(
965995    ckind :  CItemKind , 
966996)  -> Option < Ty < ' tcx > >  { 
967997    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+                         } 
9821014                    } 
983-                 } 
1015+                     _ => return  None , 
1016+                 } , 
9841017                _ => return  None , 
985-             } , 
986-             _ => return  None , 
987-         } ; 
1018+             } ; 
9881019
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+              } 
9921023
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+              } 
10001031
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+              } 
10061037
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 
10221055        } 
1056+         ty:: Pat ( base,  pat)  => match  * * pat { 
1057+             ty:: PatternKind :: Range  {  .. }  => get_nullable_type ( tcx,  typing_env,  * base) , 
1058+         } , 
1059+         _ => None , 
10231060    } 
1024-     None 
10251061} 
10261062
10271063impl < ' a ,  ' tcx >  ImproperCTypesVisitor < ' a ,  ' tcx >  { 
@@ -1256,11 +1292,9 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
12561292                help :  Some ( fluent:: lint_improper_ctypes_char_help) , 
12571293            } , 
12581294
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) , 
12641298
12651299            ty:: Int ( ty:: IntTy :: I128 )  | ty:: Uint ( ty:: UintTy :: U128 )  => { 
12661300                FfiUnsafe  {  ty,  reason :  fluent:: lint_improper_ctypes_128bit,  help :  None  } 
0 commit comments