@@ -70,10 +70,17 @@ fn variant_has_complex_ctor(variant: &ty::VariantDef) -> bool {
70
70
!matches ! ( variant. ctor_kind( ) , Some ( CtorKind :: Const ) )
71
71
}
72
72
73
- #[ derive( Clone , Copy ) ]
73
+ /// A way to keep track of what we want to lint for FFI-safety.
74
+ /// In other words, the nature of the "original item" being checked, and its relation
75
+ /// to FFI boundaries.
76
+ #[ derive( Clone , Copy , Debug ) ]
74
77
enum CItemKind {
75
- Declaration ,
76
- Definition ,
78
+ /// Imported items in an `extern "C"` block (function declarations, static variables) -> IMPROPER_CTYPES
79
+ ImportedExtern ,
80
+ /// `extern "C"` function definitions, to be used elsewhere -> IMPROPER_C_FN_DEFINITIONS,
81
+ ExportedFunction ,
82
+ /// `extern "C"` function pointers -> IMPROPER_C_CALLBACKS,
83
+ Callback ,
77
84
}
78
85
79
86
#[ derive( Clone , Debug ) ]
@@ -301,16 +308,22 @@ impl VisitorState {
301
308
/// Get the proper visitor state for a given function's arguments.
302
309
fn argument_from_fnmode ( fn_mode : CItemKind ) -> Self {
303
310
match fn_mode {
304
- CItemKind :: Definition => VisitorState :: ArgumentTyInDefinition ,
305
- CItemKind :: Declaration => VisitorState :: ArgumentTyInDeclaration ,
311
+ CItemKind :: ExportedFunction => VisitorState :: ArgumentTyInDefinition ,
312
+ CItemKind :: ImportedExtern => VisitorState :: ArgumentTyInDeclaration ,
313
+ // we could also deal with CItemKind::Callback,
314
+ // but we bake an assumption from this function's call sites here.
315
+ _ => bug ! ( "cannot be called with CItemKind::{:?}" , fn_mode) ,
306
316
}
307
317
}
308
318
309
319
/// Get the proper visitor state for a given function's return type.
310
320
fn return_from_fnmode ( fn_mode : CItemKind ) -> Self {
311
321
match fn_mode {
312
- CItemKind :: Definition => VisitorState :: ReturnTyInDefinition ,
313
- CItemKind :: Declaration => VisitorState :: ReturnTyInDeclaration ,
322
+ CItemKind :: ExportedFunction => VisitorState :: ReturnTyInDefinition ,
323
+ CItemKind :: ImportedExtern => VisitorState :: ReturnTyInDeclaration ,
324
+ // we could also deal with CItemKind::Callback,
325
+ // but we bake an assumption from this function's call sites here.
326
+ _ => bug ! ( "cannot be called with CItemKind::{:?}" , fn_mode) ,
314
327
}
315
328
}
316
329
@@ -440,7 +453,8 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
440
453
IndirectionType :: Box => {
441
454
// TODO: this logic is broken, but it still fits the current tests
442
455
if state. is_in_defined_function ( )
443
- || ( state. is_in_fnptr ( ) && matches ! ( self . base_fn_mode, CItemKind :: Definition ) )
456
+ || ( state. is_in_fnptr ( )
457
+ && matches ! ( self . base_fn_mode, CItemKind :: ExportedFunction ) )
444
458
{
445
459
if inner_ty. is_sized ( tcx, self . cx . typing_env ( ) ) {
446
460
return FfiSafe ;
@@ -981,7 +995,7 @@ impl<'tcx> ImproperCTypesLint {
981
995
// TODO: make a check_for_fnptr
982
996
let ffi_res = visitor. check_for_type ( state, fn_ptr_ty) ;
983
997
984
- self . process_ffi_result ( cx, span, ffi_res, fn_mode )
998
+ self . process_ffi_result ( cx, span, ffi_res, CItemKind :: Callback )
985
999
} ) ;
986
1000
}
987
1001
@@ -1027,9 +1041,9 @@ impl<'tcx> ImproperCTypesLint {
1027
1041
1028
1042
fn check_foreign_static ( & self , cx : & LateContext < ' tcx > , id : hir:: OwnerId , span : Span ) {
1029
1043
let ty = cx. tcx . type_of ( id) . instantiate_identity ( ) ;
1030
- let visitor = ImproperCTypesVisitor :: new ( cx, ty, CItemKind :: Declaration ) ;
1044
+ let visitor = ImproperCTypesVisitor :: new ( cx, ty, CItemKind :: ImportedExtern ) ;
1031
1045
let ffi_res = visitor. check_for_type ( VisitorState :: StaticTy , ty) ;
1032
- self . process_ffi_result ( cx, span, ffi_res, CItemKind :: Declaration ) ;
1046
+ self . process_ffi_result ( cx, span, ffi_res, CItemKind :: ImportedExtern ) ;
1033
1047
}
1034
1048
1035
1049
/// Check if a function's argument types and result type are "ffi-safe".
@@ -1044,16 +1058,16 @@ impl<'tcx> ImproperCTypesLint {
1044
1058
let sig = cx. tcx . instantiate_bound_regions_with_erased ( sig) ;
1045
1059
1046
1060
for ( input_ty, input_hir) in iter:: zip ( sig. inputs ( ) , decl. inputs ) {
1047
- let state = VisitorState :: argument_from_fnmode ( fn_mode) ;
1061
+ let visit_state = VisitorState :: argument_from_fnmode ( fn_mode) ;
1048
1062
let visitor = ImproperCTypesVisitor :: new ( cx, * input_ty, fn_mode) ;
1049
- let ffi_res = visitor. check_for_type ( state , * input_ty) ;
1063
+ let ffi_res = visitor. check_for_type ( visit_state , * input_ty) ;
1050
1064
self . process_ffi_result ( cx, input_hir. span , ffi_res, fn_mode) ;
1051
1065
}
1052
1066
1053
1067
if let hir:: FnRetTy :: Return ( ret_hir) = decl. output {
1054
- let state = VisitorState :: return_from_fnmode ( fn_mode) ;
1068
+ let visit_state = VisitorState :: return_from_fnmode ( fn_mode) ;
1055
1069
let visitor = ImproperCTypesVisitor :: new ( cx, sig. output ( ) , fn_mode) ;
1056
- let ffi_res = visitor. check_for_type ( state , sig. output ( ) ) ;
1070
+ let ffi_res = visitor. check_for_type ( visit_state , sig. output ( ) ) ;
1057
1071
self . process_ffi_result ( cx, ret_hir. span , ffi_res, fn_mode) ;
1058
1072
}
1059
1073
}
@@ -1130,12 +1144,14 @@ impl<'tcx> ImproperCTypesLint {
1130
1144
fn_mode : CItemKind ,
1131
1145
) {
1132
1146
let lint = match fn_mode {
1133
- CItemKind :: Declaration => IMPROPER_CTYPES ,
1134
- CItemKind :: Definition => IMPROPER_CTYPES_DEFINITIONS ,
1147
+ CItemKind :: ImportedExtern => IMPROPER_CTYPES ,
1148
+ CItemKind :: ExportedFunction => IMPROPER_C_FN_DEFINITIONS ,
1149
+ CItemKind :: Callback => IMPROPER_C_CALLBACKS ,
1135
1150
} ;
1136
1151
let desc = match fn_mode {
1137
- CItemKind :: Declaration => "block" ,
1138
- CItemKind :: Definition => "fn" ,
1152
+ CItemKind :: ImportedExtern => "`extern` block" ,
1153
+ CItemKind :: ExportedFunction => "`extern` fn" ,
1154
+ CItemKind :: Callback => "`extern` callback" ,
1139
1155
} ;
1140
1156
for reason in reasons. iter_mut ( ) {
1141
1157
reason. span_note = if let ty:: Adt ( def, _) = reason. ty . kind ( )
@@ -1151,13 +1167,21 @@ impl<'tcx> ImproperCTypesLint {
1151
1167
}
1152
1168
}
1153
1169
1154
- /// `ImproperCTypesDefinitions` checks items outside of foreign items (e.g. stuff that isn't in
1155
- /// `extern "C" { }` blocks):
1170
+ /// IMPROPER_CTYPES checks items that are part of a header to a non-rust library
1171
+ /// Namely, functions and static variables in `extern "<abi>" { }`,
1172
+ /// if `<abi>` is external (e.g. "C").
1173
+ ///
1174
+ /// `IMPROPER_C_CALLBACKS` checks for function pointers marked with an external ABI.
1175
+ /// (fields of type `extern "<abi>" fn`, where e.g. `<abi>` is `C`)
1176
+ /// These pointers are searched in all other items which contain types
1177
+ /// (e.g.functions, struct definitions, etc)
1178
+ ///
1179
+ /// `IMPROPER_C_FN_DEFINITIONS` checks rust-defined functions that are marked
1180
+ /// to be used from the other side of a FFI boundary.
1181
+ /// In other words, `extern "<abi>" fn` definitions and trait-method declarations.
1182
+ /// This only matters if `<abi>` is external (e.g. `C`).
1156
1183
///
1157
- /// - `extern "<abi>" fn` definitions are checked in the same way as the
1158
- /// `ImproperCtypesDeclarations` visitor checks functions if `<abi>` is external (e.g. "C").
1159
- /// - All other items which contain types (e.g. other functions, struct definitions, etc) are
1160
- /// checked for extern fn-ptrs with external ABIs.
1184
+ /// and now combinatorics for pointees
1161
1185
impl < ' tcx > LateLintPass < ' tcx > for ImproperCTypesLint {
1162
1186
fn check_foreign_item ( & mut self , cx : & LateContext < ' tcx > , it : & hir:: ForeignItem < ' tcx > ) {
1163
1187
let abi = cx. tcx . hir_get_foreign_abi ( it. hir_id ( ) ) ;
@@ -1168,11 +1192,16 @@ impl<'tcx> LateLintPass<'tcx> for ImproperCTypesLint {
1168
1192
// "the element rendered unsafe" because their unsafety doesn't affect
1169
1193
// their surroundings, and their type is often declared inline
1170
1194
if !abi. is_rustic_abi ( ) {
1171
- self . check_foreign_fn ( cx, CItemKind :: Declaration , it. owner_id . def_id , sig. decl ) ;
1195
+ self . check_foreign_fn (
1196
+ cx,
1197
+ CItemKind :: ImportedExtern ,
1198
+ it. owner_id . def_id ,
1199
+ sig. decl ,
1200
+ ) ;
1172
1201
} else {
1173
1202
self . check_fn_for_external_abi_fnptr (
1174
1203
cx,
1175
- CItemKind :: Declaration ,
1204
+ CItemKind :: ImportedExtern ,
1176
1205
it. owner_id . def_id ,
1177
1206
sig. decl ,
1178
1207
) ;
@@ -1195,7 +1224,7 @@ impl<'tcx> LateLintPass<'tcx> for ImproperCTypesLint {
1195
1224
VisitorState :: StaticTy ,
1196
1225
ty,
1197
1226
cx. tcx . type_of ( item. owner_id ) . instantiate_identity ( ) ,
1198
- CItemKind :: Definition ,
1227
+ CItemKind :: ExportedFunction , // TODO: for some reason, this is the value that reproduces old behaviour
1199
1228
) ;
1200
1229
}
1201
1230
// See `check_fn` for declarations, `check_foreign_items` for definitions in extern blocks
@@ -1229,7 +1258,7 @@ impl<'tcx> LateLintPass<'tcx> for ImproperCTypesLint {
1229
1258
VisitorState :: StaticTy ,
1230
1259
field. ty ,
1231
1260
cx. tcx . type_of ( field. def_id ) . instantiate_identity ( ) ,
1232
- CItemKind :: Definition ,
1261
+ CItemKind :: ImportedExtern ,
1233
1262
) ;
1234
1263
}
1235
1264
@@ -1254,22 +1283,24 @@ impl<'tcx> LateLintPass<'tcx> for ImproperCTypesLint {
1254
1283
// "the element rendered unsafe" because their unsafety doesn't affect
1255
1284
// their surroundings, and their type is often declared inline
1256
1285
if !abi. is_rustic_abi ( ) {
1257
- self . check_foreign_fn ( cx, CItemKind :: Definition , id, decl) ;
1286
+ self . check_foreign_fn ( cx, CItemKind :: ExportedFunction , id, decl) ;
1258
1287
} else {
1259
- self . check_fn_for_external_abi_fnptr ( cx, CItemKind :: Definition , id, decl) ;
1288
+ self . check_fn_for_external_abi_fnptr ( cx, CItemKind :: ExportedFunction , id, decl) ;
1260
1289
}
1261
1290
}
1262
1291
}
1263
1292
1264
1293
declare_lint ! {
1265
1294
/// The `improper_ctypes` lint detects incorrect use of types in foreign
1266
1295
/// modules.
1296
+ /// (In other words, declarations of items defined in foreign code.)
1267
1297
///
1268
1298
/// ### Example
1269
1299
///
1270
1300
/// ```rust
1271
1301
/// unsafe extern "C" {
1272
1302
/// static STATIC: String;
1303
+ /// fn some_func(a:String);
1273
1304
/// }
1274
1305
/// ```
1275
1306
///
@@ -1283,14 +1314,15 @@ declare_lint! {
1283
1314
/// detects a probable mistake in a definition. The lint usually should
1284
1315
/// provide a description of the issue, along with possibly a hint on how
1285
1316
/// to resolve it.
1286
- IMPROPER_CTYPES ,
1317
+ pub ( crate ) IMPROPER_CTYPES ,
1287
1318
Warn ,
1288
1319
"proper use of libc types in foreign modules"
1289
1320
}
1290
1321
1291
1322
declare_lint ! {
1292
- /// The `improper_ctypes_definitions ` lint detects incorrect use of
1323
+ /// The `improper_c_fn_definitions ` lint detects incorrect use of
1293
1324
/// [`extern` function] definitions.
1325
+ /// (In other words, functions to be used by foreign code.)
1294
1326
///
1295
1327
/// [`extern` function]: https://doc.rust-lang.org/reference/items/functions.html#extern-function-qualifier
1296
1328
///
@@ -1310,11 +1342,39 @@ declare_lint! {
1310
1342
/// lint is an alert that these types should not be used. The lint usually
1311
1343
/// should provide a description of the issue, along with possibly a hint
1312
1344
/// on how to resolve it.
1313
- IMPROPER_CTYPES_DEFINITIONS ,
1345
+ pub ( crate ) IMPROPER_C_FN_DEFINITIONS ,
1314
1346
Warn ,
1315
1347
"proper use of libc types in foreign item definitions"
1316
1348
}
1317
1349
1350
+ declare_lint ! {
1351
+ /// The `improper_c_callbacks` lint detects incorrect use of
1352
+ /// [`extern` function] pointers.
1353
+ /// (In other words, function signatures for callbacks.)
1354
+ ///
1355
+ /// [`extern` function]: https://doc.rust-lang.org/reference/items/functions.html#extern-function-qualifier
1356
+ ///
1357
+ /// ### Example
1358
+ ///
1359
+ /// ```rust
1360
+ /// # #![allow(unused)]
1361
+ /// pub fn str_emmiter(call_me_back: extern "C" fn(&str)) { }
1362
+ /// ```
1363
+ ///
1364
+ /// {{produces}}
1365
+ ///
1366
+ /// ### Explanation
1367
+ ///
1368
+ /// There are many parameter and return types that may be specified in an
1369
+ /// `extern` function that are not compatible with the given ABI. This
1370
+ /// lint is an alert that these types should not be used. The lint usually
1371
+ /// should provide a description of the issue, along with possibly a hint
1372
+ /// on how to resolve it.
1373
+ pub ( crate ) IMPROPER_C_CALLBACKS ,
1374
+ Warn ,
1375
+ "proper use of libc types in foreign-code-compatible callbacks"
1376
+ }
1377
+
1318
1378
declare_lint ! {
1319
1379
/// The `uses_power_alignment` lint detects specific `repr(C)`
1320
1380
/// aggregates on AIX.
@@ -1372,6 +1432,7 @@ declare_lint! {
1372
1432
1373
1433
declare_lint_pass ! ( ImproperCTypesLint => [
1374
1434
IMPROPER_CTYPES ,
1375
- IMPROPER_CTYPES_DEFINITIONS ,
1376
- USES_POWER_ALIGNMENT
1435
+ IMPROPER_C_FN_DEFINITIONS ,
1436
+ IMPROPER_C_CALLBACKS ,
1437
+ USES_POWER_ALIGNMENT ,
1377
1438
] ) ;
0 commit comments