@@ -2,7 +2,7 @@ use crate::{LateContext, LateLintPass, LintContext};
2
2
use rustc_ast as ast;
3
3
use rustc_attr as attr;
4
4
use rustc_data_structures:: fx:: FxHashSet ;
5
- use rustc_errors:: { fluent, Applicability } ;
5
+ use rustc_errors:: { fluent, Applicability , DiagnosticMessage } ;
6
6
use rustc_hir as hir;
7
7
use rustc_hir:: { is_range_literal, Expr , ExprKind , Node } ;
8
8
use rustc_middle:: ty:: layout:: { IntegerExt , LayoutOf , SizeSkeleton } ;
@@ -664,7 +664,7 @@ struct ImproperCTypesVisitor<'a, 'tcx> {
664
664
enum FfiResult < ' tcx > {
665
665
FfiSafe ,
666
666
FfiPhantom ( Ty < ' tcx > ) ,
667
- FfiUnsafe { ty : Ty < ' tcx > , reason : String , help : Option < String > } ,
667
+ FfiUnsafe { ty : Ty < ' tcx > , reason : DiagnosticMessage , help : Option < DiagnosticMessage > } ,
668
668
}
669
669
670
670
pub ( crate ) fn nonnull_optimization_guaranteed < ' tcx > (
@@ -824,8 +824,8 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
824
824
self . emit_ffi_unsafe_type_lint (
825
825
ty,
826
826
sp,
827
- "passing raw arrays by value is not FFI-safe" ,
828
- Some ( "consider passing a pointer to the array" ) ,
827
+ fluent :: lint :: improper_ctypes_array_reason ,
828
+ Some ( fluent :: lint :: improper_ctypes_array_help ) ,
829
829
) ;
830
830
true
831
831
} else {
@@ -868,11 +868,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
868
868
} else {
869
869
// All fields are ZSTs; this means that the type should behave
870
870
// like (), which is FFI-unsafe
871
- FfiUnsafe {
872
- ty,
873
- reason : "this struct contains only zero-sized fields" . into ( ) ,
874
- help : None ,
875
- }
871
+ FfiUnsafe { ty, reason : fluent:: lint:: improper_ctypes_struct_zst, help : None }
876
872
}
877
873
} else {
878
874
// We can't completely trust repr(C) markings; make sure the fields are
@@ -886,7 +882,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
886
882
FfiPhantom ( ..) if def. is_enum ( ) => {
887
883
return FfiUnsafe {
888
884
ty,
889
- reason : "this enum contains a PhantomData field" . into ( ) ,
885
+ reason : fluent :: lint :: improper_ctypes_enum_phantomdata ,
890
886
help : None ,
891
887
} ;
892
888
}
@@ -922,7 +918,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
922
918
} else {
923
919
return FfiUnsafe {
924
920
ty,
925
- reason : "box cannot be represented as a single pointer" . to_string ( ) ,
921
+ reason : fluent :: lint :: improper_ctypes_box ,
926
922
help : None ,
927
923
} ;
928
924
}
@@ -932,17 +928,19 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
932
928
}
933
929
match def. adt_kind ( ) {
934
930
AdtKind :: Struct | AdtKind :: Union => {
935
- let kind = if def. is_struct ( ) { "struct" } else { "union" } ;
936
-
937
931
if !def. repr ( ) . c ( ) && !def. repr ( ) . transparent ( ) {
938
932
return FfiUnsafe {
939
933
ty,
940
- reason : format ! ( "this {} has unspecified layout" , kind) ,
941
- help : Some ( format ! (
942
- "consider adding a `#[repr(C)]` or \
943
- `#[repr(transparent)]` attribute to this {}",
944
- kind
945
- ) ) ,
934
+ reason : if def. is_struct ( ) {
935
+ fluent:: lint:: improper_ctypes_struct_layout_reason
936
+ } else {
937
+ fluent:: lint:: improper_ctypes_union_layout_reason
938
+ } ,
939
+ help : if def. is_struct ( ) {
940
+ Some ( fluent:: lint:: improper_ctypes_struct_layout_help)
941
+ } else {
942
+ Some ( fluent:: lint:: improper_ctypes_union_layout_help)
943
+ } ,
946
944
} ;
947
945
}
948
946
@@ -951,16 +949,28 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
951
949
if is_non_exhaustive && !def. did ( ) . is_local ( ) {
952
950
return FfiUnsafe {
953
951
ty,
954
- reason : format ! ( "this {} is non-exhaustive" , kind) ,
952
+ reason : if def. is_struct ( ) {
953
+ fluent:: lint:: improper_ctypes_struct_non_exhaustive
954
+ } else {
955
+ fluent:: lint:: improper_ctypes_union_non_exhaustive
956
+ } ,
955
957
help : None ,
956
958
} ;
957
959
}
958
960
959
961
if def. non_enum_variant ( ) . fields . is_empty ( ) {
960
962
return FfiUnsafe {
961
963
ty,
962
- reason : format ! ( "this {} has no fields" , kind) ,
963
- help : Some ( format ! ( "consider adding a member to this {}" , kind) ) ,
964
+ reason : if def. is_struct ( ) {
965
+ fluent:: lint:: improper_ctypes_struct_fieldless_reason
966
+ } else {
967
+ fluent:: lint:: improper_ctypes_union_fieldless_reason
968
+ } ,
969
+ help : if def. is_struct ( ) {
970
+ Some ( fluent:: lint:: improper_ctypes_struct_fieldless_help)
971
+ } else {
972
+ Some ( fluent:: lint:: improper_ctypes_union_fieldless_help)
973
+ } ,
964
974
} ;
965
975
}
966
976
@@ -980,21 +990,16 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
980
990
if repr_nullable_ptr ( self . cx , ty, self . mode ) . is_none ( ) {
981
991
return FfiUnsafe {
982
992
ty,
983
- reason : "enum has no representation hint" . into ( ) ,
984
- help : Some (
985
- "consider adding a `#[repr(C)]`, \
986
- `#[repr(transparent)]`, or integer `#[repr(...)]` \
987
- attribute to this enum"
988
- . into ( ) ,
989
- ) ,
993
+ reason : fluent:: lint:: improper_ctypes_enum_repr_reason,
994
+ help : Some ( fluent:: lint:: improper_ctypes_enum_repr_help) ,
990
995
} ;
991
996
}
992
997
}
993
998
994
999
if def. is_variant_list_non_exhaustive ( ) && !def. did ( ) . is_local ( ) {
995
1000
return FfiUnsafe {
996
1001
ty,
997
- reason : "this enum is non-exhaustive" . into ( ) ,
1002
+ reason : fluent :: lint :: improper_ctypes_non_exhaustive ,
998
1003
help : None ,
999
1004
} ;
1000
1005
}
@@ -1005,7 +1010,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
1005
1010
if is_non_exhaustive && !variant. def_id . is_local ( ) {
1006
1011
return FfiUnsafe {
1007
1012
ty,
1008
- reason : "this enum has non-exhaustive variants" . into ( ) ,
1013
+ reason : fluent :: lint :: improper_ctypes_non_exhaustive_variant ,
1009
1014
help : None ,
1010
1015
} ;
1011
1016
}
@@ -1023,39 +1028,37 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
1023
1028
1024
1029
ty:: Char => FfiUnsafe {
1025
1030
ty,
1026
- reason : "the `char` type has no C equivalent" . into ( ) ,
1027
- help : Some ( "consider using `u32` or `libc::wchar_t` instead" . into ( ) ) ,
1031
+ reason : fluent :: lint :: improper_ctypes_char_reason ,
1032
+ help : Some ( fluent :: lint :: improper_ctypes_char_help ) ,
1028
1033
} ,
1029
1034
1030
- ty:: Int ( ty:: IntTy :: I128 ) | ty:: Uint ( ty:: UintTy :: U128 ) => FfiUnsafe {
1031
- ty,
1032
- reason : "128-bit integers don't currently have a known stable ABI" . into ( ) ,
1033
- help : None ,
1034
- } ,
1035
+ ty:: Int ( ty:: IntTy :: I128 ) | ty:: Uint ( ty:: UintTy :: U128 ) => {
1036
+ FfiUnsafe { ty, reason : fluent:: lint:: improper_ctypes_128bit, help : None }
1037
+ }
1035
1038
1036
1039
// Primitive types with a stable representation.
1037
1040
ty:: Bool | ty:: Int ( ..) | ty:: Uint ( ..) | ty:: Float ( ..) | ty:: Never => FfiSafe ,
1038
1041
1039
1042
ty:: Slice ( _) => FfiUnsafe {
1040
1043
ty,
1041
- reason : "slices have no C equivalent" . into ( ) ,
1042
- help : Some ( "consider using a raw pointer instead" . into ( ) ) ,
1044
+ reason : fluent :: lint :: improper_ctypes_slice_reason ,
1045
+ help : Some ( fluent :: lint :: improper_ctypes_slice_help ) ,
1043
1046
} ,
1044
1047
1045
1048
ty:: Dynamic ( ..) => {
1046
- FfiUnsafe { ty, reason : "trait objects have no C equivalent" . into ( ) , help : None }
1049
+ FfiUnsafe { ty, reason : fluent :: lint :: improper_ctypes_dyn , help : None }
1047
1050
}
1048
1051
1049
1052
ty:: Str => FfiUnsafe {
1050
1053
ty,
1051
- reason : "string slices have no C equivalent" . into ( ) ,
1052
- help : Some ( "consider using `*const u8` and a length instead" . into ( ) ) ,
1054
+ reason : fluent :: lint :: improper_ctypes_str_reason ,
1055
+ help : Some ( fluent :: lint :: improper_ctypes_str_help ) ,
1053
1056
} ,
1054
1057
1055
1058
ty:: Tuple ( ..) => FfiUnsafe {
1056
1059
ty,
1057
- reason : "tuples have unspecified layout" . into ( ) ,
1058
- help : Some ( "consider using a struct instead" . into ( ) ) ,
1060
+ reason : fluent :: lint :: improper_ctypes_tuple_reason ,
1061
+ help : Some ( fluent :: lint :: improper_ctypes_tuple_help ) ,
1059
1062
} ,
1060
1063
1061
1064
ty:: RawPtr ( ty:: TypeAndMut { ty, .. } ) | ty:: Ref ( _, ty, _)
@@ -1086,12 +1089,8 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
1086
1089
if self . is_internal_abi ( sig. abi ( ) ) {
1087
1090
return FfiUnsafe {
1088
1091
ty,
1089
- reason : "this function pointer has Rust-specific calling convention" . into ( ) ,
1090
- help : Some (
1091
- "consider using an `extern fn(...) -> ...` \
1092
- function pointer instead"
1093
- . into ( ) ,
1094
- ) ,
1092
+ reason : fluent:: lint:: improper_ctypes_fnptr_reason,
1093
+ help : Some ( fluent:: lint:: improper_ctypes_fnptr_help) ,
1095
1094
} ;
1096
1095
}
1097
1096
@@ -1122,7 +1121,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
1122
1121
// While opaque types are checked for earlier, if a projection in a struct field
1123
1122
// normalizes to an opaque type, then it will reach this branch.
1124
1123
ty:: Opaque ( ..) => {
1125
- FfiUnsafe { ty, reason : "opaque types have no C equivalent" . into ( ) , help : None }
1124
+ FfiUnsafe { ty, reason : fluent :: lint :: improper_ctypes_opaque , help : None }
1126
1125
}
1127
1126
1128
1127
// `extern "C" fn` functions can have type parameters, which may or may not be FFI-safe,
@@ -1148,8 +1147,8 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
1148
1147
& mut self ,
1149
1148
ty : Ty < ' tcx > ,
1150
1149
sp : Span ,
1151
- note : & str ,
1152
- help : Option < & str > ,
1150
+ note : DiagnosticMessage ,
1151
+ help : Option < DiagnosticMessage > ,
1153
1152
) {
1154
1153
let lint = match self . mode {
1155
1154
CItemKind :: Declaration => IMPROPER_CTYPES ,
@@ -1161,18 +1160,17 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
1161
1160
CItemKind :: Declaration => "block" ,
1162
1161
CItemKind :: Definition => "fn" ,
1163
1162
} ;
1164
- let mut diag = lint. build ( & format ! (
1165
- "`extern` {} uses type `{}`, which is not FFI-safe" ,
1166
- item_description, ty
1167
- ) ) ;
1168
- diag. span_label ( sp, "not FFI-safe" ) ;
1163
+ let mut diag = lint. build ( fluent:: lint:: improper_ctypes) ;
1164
+ diag. set_arg ( "ty" , ty) ;
1165
+ diag. set_arg ( "desc" , item_description) ;
1166
+ diag. span_label ( sp, fluent:: lint:: label) ;
1169
1167
if let Some ( help) = help {
1170
1168
diag. help ( help) ;
1171
1169
}
1172
1170
diag. note ( note) ;
1173
1171
if let ty:: Adt ( def, _) = ty. kind ( ) {
1174
1172
if let Some ( sp) = self . cx . tcx . hir ( ) . span_if_local ( def. did ( ) ) {
1175
- diag. span_note ( sp, "the type is defined here" ) ;
1173
+ diag. span_note ( sp, fluent :: lint :: note ) ;
1176
1174
}
1177
1175
}
1178
1176
diag. emit ( ) ;
@@ -1209,7 +1207,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
1209
1207
}
1210
1208
1211
1209
if let Some ( ty) = ty. visit_with ( & mut ProhibitOpaqueTypes { cx : self . cx } ) . break_value ( ) {
1212
- self . emit_ffi_unsafe_type_lint ( ty, sp, "opaque types have no C equivalent" , None ) ;
1210
+ self . emit_ffi_unsafe_type_lint ( ty, sp, fluent :: lint :: improper_ctypes_opaque , None ) ;
1213
1211
true
1214
1212
} else {
1215
1213
false
@@ -1251,13 +1249,18 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
1251
1249
match self . check_type_for_ffi ( & mut FxHashSet :: default ( ) , ty) {
1252
1250
FfiResult :: FfiSafe => { }
1253
1251
FfiResult :: FfiPhantom ( ty) => {
1254
- self . emit_ffi_unsafe_type_lint ( ty, sp, "composed only of `PhantomData`" , None ) ;
1252
+ self . emit_ffi_unsafe_type_lint (
1253
+ ty,
1254
+ sp,
1255
+ fluent:: lint:: improper_ctypes_only_phantomdata,
1256
+ None ,
1257
+ ) ;
1255
1258
}
1256
1259
// If `ty` is a `repr(transparent)` newtype, and the non-zero-sized type is a generic
1257
1260
// argument, which after substitution, is `()`, then this branch can be hit.
1258
1261
FfiResult :: FfiUnsafe { ty, .. } if is_return_type && ty. is_unit ( ) => { }
1259
1262
FfiResult :: FfiUnsafe { ty, reason, help } => {
1260
- self . emit_ffi_unsafe_type_lint ( ty, sp, & reason, help. as_deref ( ) ) ;
1263
+ self . emit_ffi_unsafe_type_lint ( ty, sp, reason, help) ;
1261
1264
}
1262
1265
}
1263
1266
}
0 commit comments