@@ -507,7 +507,7 @@ struct ImproperCTypesVisitor<'a, 'tcx> {
507
507
enum FfiResult < ' tcx > {
508
508
FfiSafe ,
509
509
FfiPhantom ( Ty < ' tcx > ) ,
510
- FfiUnsafe { ty : Ty < ' tcx > , reason : & ' static str , help : Option < & ' static str > } ,
510
+ FfiUnsafe { ty : Ty < ' tcx > , reason : String , help : Option < String > } ,
511
511
}
512
512
513
513
fn ty_is_known_nonnull < ' tcx > ( tcx : TyCtxt < ' tcx > , ty : Ty < ' tcx > ) -> bool {
@@ -613,6 +613,50 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
613
613
}
614
614
}
615
615
616
+ /// Checks if the given `VariantDef`'s field types are "ffi-safe".
617
+ fn check_variant_for_ffi (
618
+ & self ,
619
+ cache : & mut FxHashSet < Ty < ' tcx > > ,
620
+ ty : Ty < ' tcx > ,
621
+ def : & ty:: AdtDef ,
622
+ variant : & ty:: VariantDef ,
623
+ substs : SubstsRef < ' tcx > ,
624
+ ) -> FfiResult < ' tcx > {
625
+ use FfiResult :: * ;
626
+
627
+ if def. repr . transparent ( ) {
628
+ // Can assume that only one field is not a ZST, so only check
629
+ // that field's type for FFI-safety.
630
+ if let Some ( field) = variant. transparent_newtype_field ( self . cx . tcx , self . cx . param_env ) {
631
+ self . check_field_type_for_ffi ( cache, field, substs)
632
+ } else {
633
+ bug ! ( "malformed transparent type" ) ;
634
+ }
635
+ } else {
636
+ // We can't completely trust repr(C) markings; make sure the fields are
637
+ // actually safe.
638
+ let mut all_phantom = !variant. fields . is_empty ( ) ;
639
+ for field in & variant. fields {
640
+ match self . check_field_type_for_ffi ( cache, & field, substs) {
641
+ FfiSafe => {
642
+ all_phantom = false ;
643
+ }
644
+ FfiPhantom ( ..) if def. is_enum ( ) => {
645
+ return FfiUnsafe {
646
+ ty,
647
+ reason : "this enum contains a PhantomData field" . into ( ) ,
648
+ help : None ,
649
+ } ;
650
+ }
651
+ FfiPhantom ( ..) => { }
652
+ r => return r,
653
+ }
654
+ }
655
+
656
+ if all_phantom { FfiPhantom ( ty) } else { FfiSafe }
657
+ }
658
+ }
659
+
616
660
/// Checks if the given type is "ffi-safe" (has a stable, well-defined
617
661
/// representation which can be exported to C code).
618
662
fn check_type_for_ffi ( & self , cache : & mut FxHashSet < Ty < ' tcx > > , ty : Ty < ' tcx > ) -> FfiResult < ' tcx > {
@@ -634,15 +678,18 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
634
678
return FfiPhantom ( ty) ;
635
679
}
636
680
match def. adt_kind ( ) {
637
- AdtKind :: Struct => {
681
+ AdtKind :: Struct | AdtKind :: Union => {
682
+ let kind = if def. is_struct ( ) { "struct" } else { "union" } ;
683
+
638
684
if !def. repr . c ( ) && !def. repr . transparent ( ) {
639
685
return FfiUnsafe {
640
686
ty,
641
- reason : "this struct has unspecified layout" ,
642
- help : Some (
687
+ reason : format ! ( "this {} has unspecified layout" , kind ) ,
688
+ help : Some ( format ! (
643
689
"consider adding a `#[repr(C)]` or \
644
- `#[repr(transparent)]` attribute to this struct",
645
- ) ,
690
+ `#[repr(transparent)]` attribute to this {}",
691
+ kind
692
+ ) ) ,
646
693
} ;
647
694
}
648
695
@@ -651,93 +698,20 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
651
698
if is_non_exhaustive && !def. did . is_local ( ) {
652
699
return FfiUnsafe {
653
700
ty,
654
- reason : "this struct is non-exhaustive" ,
701
+ reason : format ! ( "this {} is non-exhaustive" , kind ) ,
655
702
help : None ,
656
703
} ;
657
704
}
658
705
659
706
if def. non_enum_variant ( ) . fields . is_empty ( ) {
660
707
return FfiUnsafe {
661
708
ty,
662
- reason : "this struct has no fields" ,
663
- help : Some ( "consider adding a member to this struct" ) ,
709
+ reason : format ! ( "this {} has no fields" , kind ) ,
710
+ help : Some ( format ! ( "consider adding a member to this {}" , kind ) ) ,
664
711
} ;
665
712
}
666
713
667
- if def. repr . transparent ( ) {
668
- // Can assume that only one field is not a ZST, so only check
669
- // that field's type for FFI-safety.
670
- if let Some ( field) =
671
- def. transparent_newtype_field ( cx, self . cx . param_env )
672
- {
673
- self . check_field_type_for_ffi ( cache, field, substs)
674
- } else {
675
- FfiSafe
676
- }
677
- } else {
678
- // We can't completely trust repr(C) markings; make sure the fields are
679
- // actually safe.
680
- let mut all_phantom = true ;
681
- for field in & def. non_enum_variant ( ) . fields {
682
- let r = self . check_field_type_for_ffi ( cache, field, substs) ;
683
- match r {
684
- FfiSafe => {
685
- all_phantom = false ;
686
- }
687
- FfiPhantom ( ..) => { }
688
- FfiUnsafe { .. } => {
689
- return r;
690
- }
691
- }
692
- }
693
-
694
- if all_phantom { FfiPhantom ( ty) } else { FfiSafe }
695
- }
696
- }
697
- AdtKind :: Union => {
698
- if !def. repr . c ( ) && !def. repr . transparent ( ) {
699
- return FfiUnsafe {
700
- ty,
701
- reason : "this union has unspecified layout" ,
702
- help : Some (
703
- "consider adding a `#[repr(C)]` or \
704
- `#[repr(transparent)]` attribute to this union",
705
- ) ,
706
- } ;
707
- }
708
-
709
- if def. non_enum_variant ( ) . fields . is_empty ( ) {
710
- return FfiUnsafe {
711
- ty,
712
- reason : "this union has no fields" ,
713
- help : Some ( "consider adding a field to this union" ) ,
714
- } ;
715
- }
716
-
717
- let mut all_phantom = true ;
718
- for field in & def. non_enum_variant ( ) . fields {
719
- let field_ty = cx. normalize_erasing_regions (
720
- ParamEnv :: reveal_all ( ) ,
721
- field. ty ( cx, substs) ,
722
- ) ;
723
- // repr(transparent) types are allowed to have arbitrary ZSTs, not just
724
- // PhantomData -- skip checking all ZST fields.
725
- if def. repr . transparent ( ) && field_ty. is_zst ( cx, field. did ) {
726
- continue ;
727
- }
728
- let r = self . check_type_for_ffi ( cache, field_ty) ;
729
- match r {
730
- FfiSafe => {
731
- all_phantom = false ;
732
- }
733
- FfiPhantom ( ..) => { }
734
- FfiUnsafe { .. } => {
735
- return r;
736
- }
737
- }
738
- }
739
-
740
- if all_phantom { FfiPhantom ( ty) } else { FfiSafe }
714
+ self . check_variant_for_ffi ( cache, ty, def, def. non_enum_variant ( ) , substs)
741
715
}
742
716
AdtKind :: Enum => {
743
717
if def. variants . is_empty ( ) {
@@ -752,11 +726,12 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
752
726
if !is_repr_nullable_ptr ( cx, ty, def, substs) {
753
727
return FfiUnsafe {
754
728
ty,
755
- reason : "enum has no representation hint" ,
729
+ reason : "enum has no representation hint" . into ( ) ,
756
730
help : Some (
757
731
"consider adding a `#[repr(C)]`, \
758
732
`#[repr(transparent)]`, or integer `#[repr(...)]` \
759
- attribute to this enum",
733
+ attribute to this enum"
734
+ . into ( ) ,
760
735
) ,
761
736
} ;
762
737
}
@@ -765,7 +740,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
765
740
if def. is_variant_list_non_exhaustive ( ) && !def. did . is_local ( ) {
766
741
return FfiUnsafe {
767
742
ty,
768
- reason : "this enum is non-exhaustive" ,
743
+ reason : "this enum is non-exhaustive" . into ( ) ,
769
744
help : None ,
770
745
} ;
771
746
}
@@ -776,51 +751,31 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
776
751
if is_non_exhaustive && !variant. def_id . is_local ( ) {
777
752
return FfiUnsafe {
778
753
ty,
779
- reason : "this enum has non-exhaustive variants" ,
754
+ reason : "this enum has non-exhaustive variants" . into ( ) ,
780
755
help : None ,
781
756
} ;
782
757
}
783
758
784
- for field in & variant. fields {
785
- let field_ty = cx. normalize_erasing_regions (
786
- ParamEnv :: reveal_all ( ) ,
787
- field. ty ( cx, substs) ,
788
- ) ;
789
- // repr(transparent) types are allowed to have arbitrary ZSTs, not
790
- // just PhantomData -- skip checking all ZST fields.
791
- if def. repr . transparent ( ) && field_ty. is_zst ( cx, field. did ) {
792
- continue ;
793
- }
794
- let r = self . check_type_for_ffi ( cache, field_ty) ;
795
- match r {
796
- FfiSafe => { }
797
- FfiUnsafe { .. } => {
798
- return r;
799
- }
800
- FfiPhantom ( ..) => {
801
- return FfiUnsafe {
802
- ty,
803
- reason : "this enum contains a PhantomData field" ,
804
- help : None ,
805
- } ;
806
- }
807
- }
759
+ match self . check_variant_for_ffi ( cache, ty, def, variant, substs) {
760
+ FfiSafe => ( ) ,
761
+ r => return r,
808
762
}
809
763
}
764
+
810
765
FfiSafe
811
766
}
812
767
}
813
768
}
814
769
815
770
ty:: Char => FfiUnsafe {
816
771
ty,
817
- reason : "the `char` type has no C equivalent" ,
818
- help : Some ( "consider using `u32` or `libc::wchar_t` instead" ) ,
772
+ reason : "the `char` type has no C equivalent" . into ( ) ,
773
+ help : Some ( "consider using `u32` or `libc::wchar_t` instead" . into ( ) ) ,
819
774
} ,
820
775
821
776
ty:: Int ( ast:: IntTy :: I128 ) | ty:: Uint ( ast:: UintTy :: U128 ) => FfiUnsafe {
822
777
ty,
823
- reason : "128-bit integers don't currently have a known stable ABI" ,
778
+ reason : "128-bit integers don't currently have a known stable ABI" . into ( ) ,
824
779
help : None ,
825
780
} ,
826
781
@@ -829,24 +784,24 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
829
784
830
785
ty:: Slice ( _) => FfiUnsafe {
831
786
ty,
832
- reason : "slices have no C equivalent" ,
833
- help : Some ( "consider using a raw pointer instead" ) ,
787
+ reason : "slices have no C equivalent" . into ( ) ,
788
+ help : Some ( "consider using a raw pointer instead" . into ( ) ) ,
834
789
} ,
835
790
836
791
ty:: Dynamic ( ..) => {
837
- FfiUnsafe { ty, reason : "trait objects have no C equivalent" , help : None }
792
+ FfiUnsafe { ty, reason : "trait objects have no C equivalent" . into ( ) , help : None }
838
793
}
839
794
840
795
ty:: Str => FfiUnsafe {
841
796
ty,
842
- reason : "string slices have no C equivalent" ,
843
- help : Some ( "consider using `*const u8` and a length instead" ) ,
797
+ reason : "string slices have no C equivalent" . into ( ) ,
798
+ help : Some ( "consider using `*const u8` and a length instead" . into ( ) ) ,
844
799
} ,
845
800
846
801
ty:: Tuple ( ..) => FfiUnsafe {
847
802
ty,
848
- reason : "tuples have unspecified layout" ,
849
- help : Some ( "consider using a struct instead" ) ,
803
+ reason : "tuples have unspecified layout" . into ( ) ,
804
+ help : Some ( "consider using a struct instead" . into ( ) ) ,
850
805
} ,
851
806
852
807
ty:: RawPtr ( ty:: TypeAndMut { ty, .. } ) | ty:: Ref ( _, ty, _) => {
@@ -860,10 +815,12 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
860
815
Abi :: Rust | Abi :: RustIntrinsic | Abi :: PlatformIntrinsic | Abi :: RustCall => {
861
816
return FfiUnsafe {
862
817
ty,
863
- reason : "this function pointer has Rust-specific calling convention" ,
818
+ reason : "this function pointer has Rust-specific calling convention"
819
+ . into ( ) ,
864
820
help : Some (
865
821
"consider using an `extern fn(...) -> ...` \
866
- function pointer instead",
822
+ function pointer instead"
823
+ . into ( ) ,
867
824
) ,
868
825
} ;
869
826
}
@@ -897,7 +854,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
897
854
// While opaque types are checked for earlier, if a projection in a struct field
898
855
// normalizes to an opaque type, then it will reach this branch.
899
856
ty:: Opaque ( ..) => {
900
- FfiUnsafe { ty, reason : "opaque types have no C equivalent" , help : None }
857
+ FfiUnsafe { ty, reason : "opaque types have no C equivalent" . into ( ) , help : None }
901
858
}
902
859
903
860
ty:: Param ( ..)
@@ -1004,7 +961,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
1004
961
// argument, which after substitution, is `()`, then this branch can be hit.
1005
962
FfiResult :: FfiUnsafe { ty, .. } if is_return_type && ty. is_unit ( ) => return ,
1006
963
FfiResult :: FfiUnsafe { ty, reason, help } => {
1007
- self . emit_ffi_unsafe_type_lint ( ty, sp, reason, help) ;
964
+ self . emit_ffi_unsafe_type_lint ( ty, sp, & reason, help. as_deref ( ) ) ;
1008
965
}
1009
966
}
1010
967
}
0 commit comments