@@ -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 } ;
@@ -524,78 +524,82 @@ enum FfiResult<'tcx> {
524524 FfiUnsafe { ty : Ty < ' tcx > , reason : String , help : Option < String > } ,
525525}
526526
527- fn ty_is_known_nonnull < ' tcx > ( tcx : TyCtxt < ' tcx > , ty : Ty < ' tcx > ) -> bool {
528- match ty. kind {
529- ty:: FnPtr ( _) => true ,
530- ty:: Ref ( ..) => true ,
531- ty:: Adt ( field_def, substs) if field_def. repr . transparent ( ) && !field_def. is_union ( ) => {
532- for field in field_def. all_fields ( ) {
533- let field_ty =
534- tcx. normalize_erasing_regions ( ParamEnv :: reveal_all ( ) , field. ty ( tcx, substs) ) ;
535- if field_ty. is_zst ( tcx, field. did ) {
536- continue ;
537- }
527+ impl < ' a , ' tcx > ImproperCTypesVisitor < ' a , ' tcx > {
528+ /// Is type known to be non-null?
529+ fn ty_is_known_nonnull ( & self , ty : Ty < ' tcx > ) -> bool {
530+ match ty. kind {
531+ ty:: FnPtr ( _) => true ,
532+ ty:: Ref ( ..) => true ,
533+ ty:: Adt ( field_def, substs) if field_def. repr . transparent ( ) && !field_def. is_union ( ) => {
534+ for field in field_def. all_fields ( ) {
535+ let field_ty = self . cx . tcx . normalize_erasing_regions (
536+ self . cx . param_env ,
537+ field. ty ( self . cx . tcx , substs) ,
538+ ) ;
539+ if field_ty. is_zst ( self . cx . tcx , field. did ) {
540+ continue ;
541+ }
538542
539- let attrs = tcx. get_attrs ( field_def. did ) ;
540- if attrs. iter ( ) . any ( |a| a. check_name ( sym:: rustc_nonnull_optimization_guaranteed) )
541- || ty_is_known_nonnull ( tcx, field_ty)
542- {
543- return true ;
543+ let attrs = self . cx . tcx . get_attrs ( field_def. did ) ;
544+ if attrs
545+ . iter ( )
546+ . any ( |a| a. check_name ( sym:: rustc_nonnull_optimization_guaranteed) )
547+ || self . ty_is_known_nonnull ( field_ty)
548+ {
549+ return true ;
550+ }
544551 }
545- }
546552
547- false
553+ false
554+ }
555+ _ => false ,
548556 }
549- _ => false ,
550557 }
551- }
552558
553- /// Check if this enum can be safely exported based on the
554- /// "nullable pointer optimization". Currently restricted
555- /// to function pointers, references, core::num::NonZero*,
556- /// core::ptr::NonNull, and #[repr(transparent)] newtypes.
557- /// FIXME: This duplicates code in codegen.
558- fn is_repr_nullable_ptr < ' tcx > (
559- tcx : TyCtxt < ' tcx > ,
560- ty : Ty < ' tcx > ,
561- ty_def : & ' tcx ty:: AdtDef ,
562- substs : SubstsRef < ' tcx > ,
563- ) -> bool {
564- if ty_def. variants . len ( ) != 2 {
565- return false ;
566- }
559+ /// Check if this enum can be safely exported based on the "nullable pointer optimization".
560+ /// Currently restricted to function pointers, references, `core::num::NonZero*`,
561+ /// `core::ptr::NonNull`, and `#[repr(transparent)]` newtypes.
562+ fn is_repr_nullable_ptr (
563+ & self ,
564+ ty : Ty < ' tcx > ,
565+ ty_def : & ' tcx ty:: AdtDef ,
566+ substs : SubstsRef < ' tcx > ,
567+ ) -> bool {
568+ if ty_def. variants . len ( ) != 2 {
569+ return false ;
570+ }
567571
568- let get_variant_fields = |index| & ty_def. variants [ VariantIdx :: new ( index) ] . fields ;
569- let variant_fields = [ get_variant_fields ( 0 ) , get_variant_fields ( 1 ) ] ;
570- let fields = if variant_fields[ 0 ] . is_empty ( ) {
571- & variant_fields[ 1 ]
572- } else if variant_fields[ 1 ] . is_empty ( ) {
573- & variant_fields[ 0 ]
574- } else {
575- return false ;
576- } ;
572+ let get_variant_fields = |index| & ty_def. variants [ VariantIdx :: new ( index) ] . fields ;
573+ let variant_fields = [ get_variant_fields ( 0 ) , get_variant_fields ( 1 ) ] ;
574+ let fields = if variant_fields[ 0 ] . is_empty ( ) {
575+ & variant_fields[ 1 ]
576+ } else if variant_fields[ 1 ] . is_empty ( ) {
577+ & variant_fields[ 0 ]
578+ } else {
579+ return false ;
580+ } ;
577581
578- if fields. len ( ) != 1 {
579- return false ;
580- }
582+ if fields. len ( ) != 1 {
583+ return false ;
584+ }
581585
582- let field_ty = fields[ 0 ] . ty ( tcx, substs) ;
583- if !ty_is_known_nonnull ( tcx , field_ty) {
584- return false ;
585- }
586+ let field_ty = fields[ 0 ] . ty ( self . cx . tcx , substs) ;
587+ if !self . ty_is_known_nonnull ( field_ty) {
588+ return false ;
589+ }
586590
587- // At this point, the field's type is known to be nonnull and the parent enum is Option-like.
588- // If the computed size for the field and the enum are different, the nonnull optimization isn't
589- // being applied (and we've got a problem somewhere).
590- let compute_size_skeleton = |t| SizeSkeleton :: compute ( t, tcx, ParamEnv :: reveal_all ( ) ) . unwrap ( ) ;
591- if !compute_size_skeleton ( ty) . same_size ( compute_size_skeleton ( field_ty) ) {
592- bug ! ( "improper_ctypes: Option nonnull optimization not applied?" ) ;
593- }
591+ // At this point, the field's type is known to be nonnull and the parent enum is
592+ // Option-like. If the computed size for the field and the enum are different, the non-null
593+ // optimization isn't being applied (and we've got a problem somewhere).
594+ let compute_size_skeleton =
595+ |t| SizeSkeleton :: compute ( t, self . cx . tcx , self . cx . param_env ) . unwrap ( ) ;
596+ if !compute_size_skeleton ( ty) . same_size ( compute_size_skeleton ( field_ty) ) {
597+ bug ! ( "improper_ctypes: Option nonnull optimization not applied?" ) ;
598+ }
594599
595- true
596- }
600+ true
601+ }
597602
598- impl < ' a , ' tcx > ImproperCTypesVisitor < ' a , ' tcx > {
599603 /// Check if the type is array and emit an unsafe type lint.
600604 fn check_for_array_ty ( & mut self , sp : Span , ty : Ty < ' tcx > ) -> bool {
601605 if let ty:: Array ( ..) = ty. kind {
@@ -737,7 +741,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
737741 // discriminant.
738742 if !def. repr . c ( ) && !def. repr . transparent ( ) && def. repr . int . is_none ( ) {
739743 // Special-case types like `Option<extern fn()>`.
740- if !is_repr_nullable_ptr ( cx , ty, def, substs) {
744+ if !self . is_repr_nullable_ptr ( ty, def, substs) {
741745 return FfiUnsafe {
742746 ty,
743747 reason : "enum has no representation hint" . into ( ) ,
0 commit comments