@@ -11,7 +11,7 @@ use rustc_index::vec::Idx;
1111use rustc_middle:: mir:: interpret:: { sign_extend, truncate} ;
1212use rustc_middle:: ty:: layout:: { IntegerExt , SizeSkeleton } ;
1313use rustc_middle:: ty:: subst:: SubstsRef ;
14- use rustc_middle:: ty:: { self , AdtKind , ParamEnv , Ty , TyCtxt , TypeFoldable } ;
14+ use rustc_middle:: ty:: { self , AdtKind , Ty , TypeFoldable } ;
1515use rustc_span:: source_map;
1616use rustc_span:: symbol:: sym;
1717use rustc_span:: { Span , DUMMY_SP } ;
@@ -525,78 +525,82 @@ enum FfiResult<'tcx> {
525525 FfiUnsafe { ty : Ty < ' tcx > , reason : String , help : Option < String > } ,
526526}
527527
528- fn ty_is_known_nonnull < ' tcx > ( tcx : TyCtxt < ' tcx > , ty : Ty < ' tcx > ) -> bool {
529- match ty. kind {
530- ty:: FnPtr ( _) => true ,
531- ty:: Ref ( ..) => true ,
532- ty:: Adt ( field_def, substs) if field_def. repr . transparent ( ) && !field_def. is_union ( ) => {
533- for field in field_def. all_fields ( ) {
534- let field_ty =
535- tcx. normalize_erasing_regions ( ParamEnv :: reveal_all ( ) , field. ty ( tcx, substs) ) ;
536- if field_ty. is_zst ( tcx, field. did ) {
537- continue ;
538- }
528+ impl < ' a , ' tcx > ImproperCTypesVisitor < ' a , ' tcx > {
529+ /// Is type known to be non-null?
530+ fn ty_is_known_nonnull ( & self , ty : Ty < ' tcx > ) -> bool {
531+ match ty. kind {
532+ ty:: FnPtr ( _) => true ,
533+ ty:: Ref ( ..) => true ,
534+ ty:: Adt ( field_def, substs) if field_def. repr . transparent ( ) && !field_def. is_union ( ) => {
535+ for field in field_def. all_fields ( ) {
536+ let field_ty = self . cx . tcx . normalize_erasing_regions (
537+ self . cx . param_env ,
538+ field. ty ( self . cx . tcx , substs) ,
539+ ) ;
540+ if field_ty. is_zst ( self . cx . tcx , field. did ) {
541+ continue ;
542+ }
539543
540- let attrs = tcx. get_attrs ( field_def. did ) ;
541- if attrs. iter ( ) . any ( |a| a. check_name ( sym:: rustc_nonnull_optimization_guaranteed) )
542- || ty_is_known_nonnull ( tcx, field_ty)
543- {
544- return true ;
544+ let attrs = self . cx . tcx . get_attrs ( field_def. did ) ;
545+ if attrs
546+ . iter ( )
547+ . any ( |a| a. check_name ( sym:: rustc_nonnull_optimization_guaranteed) )
548+ || self . ty_is_known_nonnull ( field_ty)
549+ {
550+ return true ;
551+ }
545552 }
546- }
547553
548- false
554+ false
555+ }
556+ _ => false ,
549557 }
550- _ => false ,
551558 }
552- }
553559
554- /// Check if this enum can be safely exported based on the
555- /// "nullable pointer optimization". Currently restricted
556- /// to function pointers, references, core::num::NonZero*,
557- /// core::ptr::NonNull, and #[repr(transparent)] newtypes.
558- /// FIXME: This duplicates code in codegen.
559- fn is_repr_nullable_ptr < ' tcx > (
560- tcx : TyCtxt < ' tcx > ,
561- ty : Ty < ' tcx > ,
562- ty_def : & ' tcx ty:: AdtDef ,
563- substs : SubstsRef < ' tcx > ,
564- ) -> bool {
565- if ty_def. variants . len ( ) != 2 {
566- return false ;
567- }
560+ /// Check if this enum can be safely exported based on the "nullable pointer optimization".
561+ /// Currently restricted to function pointers, references, `core::num::NonZero*`,
562+ /// `core::ptr::NonNull`, and `#[repr(transparent)]` newtypes.
563+ fn is_repr_nullable_ptr (
564+ & self ,
565+ ty : Ty < ' tcx > ,
566+ ty_def : & ' tcx ty:: AdtDef ,
567+ substs : SubstsRef < ' tcx > ,
568+ ) -> bool {
569+ if ty_def. variants . len ( ) != 2 {
570+ return false ;
571+ }
568572
569- let get_variant_fields = |index| & ty_def. variants [ VariantIdx :: new ( index) ] . fields ;
570- let variant_fields = [ get_variant_fields ( 0 ) , get_variant_fields ( 1 ) ] ;
571- let fields = if variant_fields[ 0 ] . is_empty ( ) {
572- & variant_fields[ 1 ]
573- } else if variant_fields[ 1 ] . is_empty ( ) {
574- & variant_fields[ 0 ]
575- } else {
576- return false ;
577- } ;
573+ let get_variant_fields = |index| & ty_def. variants [ VariantIdx :: new ( index) ] . fields ;
574+ let variant_fields = [ get_variant_fields ( 0 ) , get_variant_fields ( 1 ) ] ;
575+ let fields = if variant_fields[ 0 ] . is_empty ( ) {
576+ & variant_fields[ 1 ]
577+ } else if variant_fields[ 1 ] . is_empty ( ) {
578+ & variant_fields[ 0 ]
579+ } else {
580+ return false ;
581+ } ;
578582
579- if fields. len ( ) != 1 {
580- return false ;
581- }
583+ if fields. len ( ) != 1 {
584+ return false ;
585+ }
582586
583- let field_ty = fields[ 0 ] . ty ( tcx, substs) ;
584- if !ty_is_known_nonnull ( tcx , field_ty) {
585- return false ;
586- }
587+ let field_ty = fields[ 0 ] . ty ( self . cx . tcx , substs) ;
588+ if !self . ty_is_known_nonnull ( field_ty) {
589+ return false ;
590+ }
587591
588- // At this point, the field's type is known to be nonnull and the parent enum is Option-like.
589- // If the computed size for the field and the enum are different, the nonnull optimization isn't
590- // being applied (and we've got a problem somewhere).
591- let compute_size_skeleton = |t| SizeSkeleton :: compute ( t, tcx, ParamEnv :: reveal_all ( ) ) . unwrap ( ) ;
592- if !compute_size_skeleton ( ty) . same_size ( compute_size_skeleton ( field_ty) ) {
593- bug ! ( "improper_ctypes: Option nonnull optimization not applied?" ) ;
594- }
592+ // At this point, the field's type is known to be nonnull and the parent enum is
593+ // Option-like. If the computed size for the field and the enum are different, the non-null
594+ // optimization isn't being applied (and we've got a problem somewhere).
595+ let compute_size_skeleton =
596+ |t| SizeSkeleton :: compute ( t, self . cx . tcx , self . cx . param_env ) . unwrap ( ) ;
597+ if !compute_size_skeleton ( ty) . same_size ( compute_size_skeleton ( field_ty) ) {
598+ bug ! ( "improper_ctypes: Option nonnull optimization not applied?" ) ;
599+ }
595600
596- true
597- }
601+ true
602+ }
598603
599- impl < ' a , ' tcx > ImproperCTypesVisitor < ' a , ' tcx > {
600604 /// Check if the type is array and emit an unsafe type lint.
601605 fn check_for_array_ty ( & mut self , sp : Span , ty : Ty < ' tcx > ) -> bool {
602606 if let ty:: Array ( ..) = ty. kind {
@@ -738,7 +742,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
738742 // discriminant.
739743 if !def. repr . c ( ) && !def. repr . transparent ( ) && def. repr . int . is_none ( ) {
740744 // Special-case types like `Option<extern fn()>`.
741- if !is_repr_nullable_ptr ( cx , ty, def, substs) {
745+ if !self . is_repr_nullable_ptr ( ty, def, substs) {
742746 return FfiUnsafe {
743747 ty,
744748 reason : "enum has no representation hint" . into ( ) ,
0 commit comments