@@ -624,7 +624,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
624
624
AdtKind :: Struct => {
625
625
if !def. repr . c ( ) && !def. repr . transparent ( ) {
626
626
return FfiUnsafe {
627
- ty : ty ,
627
+ ty,
628
628
reason : "this struct has unspecified layout" ,
629
629
help : Some ( "consider adding a `#[repr(C)]` or \
630
630
`#[repr(transparent)]` attribute to this struct") ,
@@ -633,7 +633,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
633
633
634
634
if def. non_enum_variant ( ) . fields . is_empty ( ) {
635
635
return FfiUnsafe {
636
- ty : ty ,
636
+ ty,
637
637
reason : "this struct has no fields" ,
638
638
help : Some ( "consider adding a member to this struct" ) ,
639
639
} ;
@@ -669,7 +669,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
669
669
AdtKind :: Union => {
670
670
if !def. repr . c ( ) && !def. repr . transparent ( ) {
671
671
return FfiUnsafe {
672
- ty : ty ,
672
+ ty,
673
673
reason : "this union has unspecified layout" ,
674
674
help : Some ( "consider adding a `#[repr(C)]` or \
675
675
`#[repr(transparent)]` attribute to this union") ,
@@ -678,7 +678,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
678
678
679
679
if def. non_enum_variant ( ) . fields . is_empty ( ) {
680
680
return FfiUnsafe {
681
- ty : ty ,
681
+ ty,
682
682
reason : "this union has no fields" ,
683
683
help : Some ( "consider adding a field to this union" ) ,
684
684
} ;
@@ -721,7 +721,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
721
721
// Special-case types like `Option<extern fn()>`.
722
722
if !is_repr_nullable_ptr ( cx, ty, def, substs) {
723
723
return FfiUnsafe {
724
- ty : ty ,
724
+ ty,
725
725
reason : "enum has no representation hint" ,
726
726
help : Some ( "consider adding a `#[repr(C)]`, \
727
727
`#[repr(transparent)]`, or integer `#[repr(...)]` \
@@ -750,7 +750,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
750
750
}
751
751
FfiPhantom ( ..) => {
752
752
return FfiUnsafe {
753
- ty : ty ,
753
+ ty,
754
754
reason : "this enum contains a PhantomData field" ,
755
755
help : None ,
756
756
} ;
@@ -764,13 +764,13 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
764
764
}
765
765
766
766
ty:: Char => FfiUnsafe {
767
- ty : ty ,
767
+ ty,
768
768
reason : "the `char` type has no C equivalent" ,
769
769
help : Some ( "consider using `u32` or `libc::wchar_t` instead" ) ,
770
770
} ,
771
771
772
772
ty:: Int ( ast:: IntTy :: I128 ) | ty:: Uint ( ast:: UintTy :: U128 ) => FfiUnsafe {
773
- ty : ty ,
773
+ ty,
774
774
reason : "128-bit integers don't currently have a known stable ABI" ,
775
775
help : None ,
776
776
} ,
@@ -779,25 +779,25 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
779
779
ty:: Bool | ty:: Int ( ..) | ty:: Uint ( ..) | ty:: Float ( ..) | ty:: Never => FfiSafe ,
780
780
781
781
ty:: Slice ( _) => FfiUnsafe {
782
- ty : ty ,
782
+ ty,
783
783
reason : "slices have no C equivalent" ,
784
784
help : Some ( "consider using a raw pointer instead" ) ,
785
785
} ,
786
786
787
787
ty:: Dynamic ( ..) => FfiUnsafe {
788
- ty : ty ,
788
+ ty,
789
789
reason : "trait objects have no C equivalent" ,
790
790
help : None ,
791
791
} ,
792
792
793
793
ty:: Str => FfiUnsafe {
794
- ty : ty ,
794
+ ty,
795
795
reason : "string slices have no C equivalent" ,
796
796
help : Some ( "consider using `*const u8` and a length instead" ) ,
797
797
} ,
798
798
799
799
ty:: Tuple ( ..) => FfiUnsafe {
800
- ty : ty ,
800
+ ty,
801
801
reason : "tuples have unspecified layout" ,
802
802
help : Some ( "consider using a struct instead" ) ,
803
803
} ,
@@ -811,7 +811,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
811
811
match sig. abi ( ) {
812
812
Abi :: Rust | Abi :: RustIntrinsic | Abi :: PlatformIntrinsic | Abi :: RustCall => {
813
813
return FfiUnsafe {
814
- ty : ty ,
814
+ ty,
815
815
reason : "this function pointer has Rust-specific calling convention" ,
816
816
help : Some ( "consider using an `extern fn(...) -> ...` \
817
817
function pointer instead") ,
@@ -855,36 +855,87 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
855
855
ty:: UnnormalizedProjection ( ..) |
856
856
ty:: Projection ( ..) |
857
857
ty:: Opaque ( ..) |
858
- ty:: FnDef ( ..) => bug ! ( "Unexpected type in foreign function" ) ,
858
+ ty:: FnDef ( ..) => bug ! ( "unexpected type in foreign function: {:?}" , ty) ,
859
+ }
860
+ }
861
+
862
+ fn emit_ffi_unsafe_type_lint (
863
+ & mut self ,
864
+ ty : Ty < ' tcx > ,
865
+ sp : Span ,
866
+ note : & str ,
867
+ help : Option < & str > ,
868
+ ) {
869
+ let mut diag = self . cx . struct_span_lint (
870
+ IMPROPER_CTYPES ,
871
+ sp,
872
+ & format ! ( "`extern` block uses type `{}`, which is not FFI-safe" , ty) ,
873
+ ) ;
874
+ diag. span_label ( sp, "not FFI-safe" ) ;
875
+ if let Some ( help) = help {
876
+ diag. help ( help) ;
877
+ }
878
+ diag. note ( note) ;
879
+ if let ty:: Adt ( def, _) = ty. sty {
880
+ if let Some ( sp) = self . cx . tcx . hir ( ) . span_if_local ( def. did ) {
881
+ diag. span_note ( sp, "type defined here" ) ;
882
+ }
883
+ }
884
+ diag. emit ( ) ;
885
+ }
886
+
887
+ fn check_for_opaque_ty ( & mut self , sp : Span , ty : Ty < ' tcx > ) -> bool {
888
+ use crate :: rustc:: ty:: TypeFoldable ;
889
+
890
+ struct ProhibitOpaqueTypes < ' tcx > {
891
+ ty : Option < Ty < ' tcx > > ,
892
+ } ;
893
+
894
+ impl < ' tcx > ty:: fold:: TypeVisitor < ' tcx > for ProhibitOpaqueTypes < ' tcx > {
895
+ fn visit_ty ( & mut self , ty : Ty < ' tcx > ) -> bool {
896
+ if let ty:: Opaque ( ..) = ty. sty {
897
+ self . ty = Some ( ty) ;
898
+ true
899
+ } else {
900
+ ty. super_visit_with ( self )
901
+ }
902
+ }
903
+ }
904
+
905
+ let mut visitor = ProhibitOpaqueTypes { ty : None } ;
906
+ ty. visit_with ( & mut visitor) ;
907
+ if let Some ( ty) = visitor. ty {
908
+ self . emit_ffi_unsafe_type_lint (
909
+ ty,
910
+ sp,
911
+ "opaque types have no C equivalent" ,
912
+ None ,
913
+ ) ;
914
+ true
915
+ } else {
916
+ false
859
917
}
860
918
}
861
919
862
920
fn check_type_for_ffi_and_report_errors ( & mut self , sp : Span , ty : Ty < ' tcx > ) {
921
+ // We have to check for opaque types before `normalize_erasing_regions`,
922
+ // which will replace opaque types with their underlying concrete type.
923
+ if self . check_for_opaque_ty ( sp, ty) {
924
+ // We've already emitted an error due to an opaque type.
925
+ return ;
926
+ }
927
+
863
928
// it is only OK to use this function because extern fns cannot have
864
929
// any generic types right now:
865
930
let ty = self . cx . tcx . normalize_erasing_regions ( ParamEnv :: reveal_all ( ) , ty) ;
866
931
867
932
match self . check_type_for_ffi ( & mut FxHashSet :: default ( ) , ty) {
868
933
FfiResult :: FfiSafe => { }
869
934
FfiResult :: FfiPhantom ( ty) => {
870
- self . cx . span_lint ( IMPROPER_CTYPES ,
871
- sp,
872
- & format ! ( "`extern` block uses type `{}` which is not FFI-safe: \
873
- composed only of PhantomData", ty) ) ;
935
+ self . emit_ffi_unsafe_type_lint ( ty, sp, "composed only of `PhantomData`" , None ) ;
874
936
}
875
- FfiResult :: FfiUnsafe { ty : unsafe_ty, reason, help } => {
876
- let msg = format ! ( "`extern` block uses type `{}` which is not FFI-safe: {}" ,
877
- unsafe_ty, reason) ;
878
- let mut diag = self . cx . struct_span_lint ( IMPROPER_CTYPES , sp, & msg) ;
879
- if let Some ( s) = help {
880
- diag. help ( s) ;
881
- }
882
- if let ty:: Adt ( def, _) = unsafe_ty. sty {
883
- if let Some ( sp) = self . cx . tcx . hir ( ) . span_if_local ( def. did ) {
884
- diag. span_note ( sp, "type defined here" ) ;
885
- }
886
- }
887
- diag. emit ( ) ;
937
+ FfiResult :: FfiUnsafe { ty, reason, help } => {
938
+ self . emit_ffi_unsafe_type_lint ( ty, sp, reason, help) ;
888
939
}
889
940
}
890
941
}
0 commit comments