@@ -70,10 +70,17 @@ fn variant_has_complex_ctor(variant: &ty::VariantDef) -> bool {
7070 !matches ! ( variant. ctor_kind( ) , Some ( CtorKind :: Const ) )
7171}
7272
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 ) ]
7477enum 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 ,
7784}
7885
7986#[ derive( Clone , Debug ) ]
@@ -301,16 +308,22 @@ impl VisitorState {
301308 /// Get the proper visitor state for a given function's arguments.
302309 fn argument_from_fnmode ( fn_mode : CItemKind ) -> Self {
303310 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) ,
306316 }
307317 }
308318
309319 /// Get the proper visitor state for a given function's return type.
310320 fn return_from_fnmode ( fn_mode : CItemKind ) -> Self {
311321 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) ,
314327 }
315328 }
316329
@@ -440,7 +453,8 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
440453 IndirectionType :: Box => {
441454 // TODO: this logic is broken, but it still fits the current tests
442455 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 ) )
444458 {
445459 if inner_ty. is_sized ( tcx, self . cx . typing_env ( ) ) {
446460 return FfiSafe ;
@@ -981,7 +995,7 @@ impl<'tcx> ImproperCTypesLint {
981995 // TODO: make a check_for_fnptr
982996 let ffi_res = visitor. check_for_type ( state, fn_ptr_ty) ;
983997
984- self . process_ffi_result ( cx, span, ffi_res, fn_mode )
998+ self . process_ffi_result ( cx, span, ffi_res, CItemKind :: Callback )
985999 } ) ;
9861000 }
9871001
@@ -1027,9 +1041,9 @@ impl<'tcx> ImproperCTypesLint {
10271041
10281042 fn check_foreign_static ( & self , cx : & LateContext < ' tcx > , id : hir:: OwnerId , span : Span ) {
10291043 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 ) ;
10311045 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 ) ;
10331047 }
10341048
10351049 /// Check if a function's argument types and result type are "ffi-safe".
@@ -1044,16 +1058,16 @@ impl<'tcx> ImproperCTypesLint {
10441058 let sig = cx. tcx . instantiate_bound_regions_with_erased ( sig) ;
10451059
10461060 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) ;
10481062 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) ;
10501064 self . process_ffi_result ( cx, input_hir. span , ffi_res, fn_mode) ;
10511065 }
10521066
10531067 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) ;
10551069 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 ( ) ) ;
10571071 self . process_ffi_result ( cx, ret_hir. span , ffi_res, fn_mode) ;
10581072 }
10591073 }
@@ -1130,12 +1144,14 @@ impl<'tcx> ImproperCTypesLint {
11301144 fn_mode : CItemKind ,
11311145 ) {
11321146 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 ,
11351150 } ;
11361151 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" ,
11391155 } ;
11401156 for reason in reasons. iter_mut ( ) {
11411157 reason. span_note = if let ty:: Adt ( def, _) = reason. ty . kind ( )
@@ -1151,13 +1167,21 @@ impl<'tcx> ImproperCTypesLint {
11511167 }
11521168}
11531169
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`).
11561183///
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
11611185impl < ' tcx > LateLintPass < ' tcx > for ImproperCTypesLint {
11621186 fn check_foreign_item ( & mut self , cx : & LateContext < ' tcx > , it : & hir:: ForeignItem < ' tcx > ) {
11631187 let abi = cx. tcx . hir_get_foreign_abi ( it. hir_id ( ) ) ;
@@ -1168,11 +1192,16 @@ impl<'tcx> LateLintPass<'tcx> for ImproperCTypesLint {
11681192 // "the element rendered unsafe" because their unsafety doesn't affect
11691193 // their surroundings, and their type is often declared inline
11701194 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+ ) ;
11721201 } else {
11731202 self . check_fn_for_external_abi_fnptr (
11741203 cx,
1175- CItemKind :: Declaration ,
1204+ CItemKind :: ImportedExtern ,
11761205 it. owner_id . def_id ,
11771206 sig. decl ,
11781207 ) ;
@@ -1195,7 +1224,7 @@ impl<'tcx> LateLintPass<'tcx> for ImproperCTypesLint {
11951224 VisitorState :: StaticTy ,
11961225 ty,
11971226 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
11991228 ) ;
12001229 }
12011230 // See `check_fn` for declarations, `check_foreign_items` for definitions in extern blocks
@@ -1229,7 +1258,7 @@ impl<'tcx> LateLintPass<'tcx> for ImproperCTypesLint {
12291258 VisitorState :: StaticTy ,
12301259 field. ty ,
12311260 cx. tcx . type_of ( field. def_id ) . instantiate_identity ( ) ,
1232- CItemKind :: Definition ,
1261+ CItemKind :: ImportedExtern ,
12331262 ) ;
12341263 }
12351264
@@ -1254,22 +1283,24 @@ impl<'tcx> LateLintPass<'tcx> for ImproperCTypesLint {
12541283 // "the element rendered unsafe" because their unsafety doesn't affect
12551284 // their surroundings, and their type is often declared inline
12561285 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) ;
12581287 } 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) ;
12601289 }
12611290 }
12621291}
12631292
12641293declare_lint ! {
12651294 /// The `improper_ctypes` lint detects incorrect use of types in foreign
12661295 /// modules.
1296+ /// (In other words, declarations of items defined in foreign code.)
12671297 ///
12681298 /// ### Example
12691299 ///
12701300 /// ```rust
12711301 /// unsafe extern "C" {
12721302 /// static STATIC: String;
1303+ /// fn some_func(a:String);
12731304 /// }
12741305 /// ```
12751306 ///
@@ -1283,14 +1314,15 @@ declare_lint! {
12831314 /// detects a probable mistake in a definition. The lint usually should
12841315 /// provide a description of the issue, along with possibly a hint on how
12851316 /// to resolve it.
1286- IMPROPER_CTYPES ,
1317+ pub ( crate ) IMPROPER_CTYPES ,
12871318 Warn ,
12881319 "proper use of libc types in foreign modules"
12891320}
12901321
12911322declare_lint ! {
1292- /// The `improper_ctypes_definitions ` lint detects incorrect use of
1323+ /// The `improper_c_fn_definitions ` lint detects incorrect use of
12931324 /// [`extern` function] definitions.
1325+ /// (In other words, functions to be used by foreign code.)
12941326 ///
12951327 /// [`extern` function]: https://doc.rust-lang.org/reference/items/functions.html#extern-function-qualifier
12961328 ///
@@ -1310,11 +1342,39 @@ declare_lint! {
13101342 /// lint is an alert that these types should not be used. The lint usually
13111343 /// should provide a description of the issue, along with possibly a hint
13121344 /// on how to resolve it.
1313- IMPROPER_CTYPES_DEFINITIONS ,
1345+ pub ( crate ) IMPROPER_C_FN_DEFINITIONS ,
13141346 Warn ,
13151347 "proper use of libc types in foreign item definitions"
13161348}
13171349
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+
13181378declare_lint ! {
13191379 /// The `uses_power_alignment` lint detects specific `repr(C)`
13201380 /// aggregates on AIX.
@@ -1372,6 +1432,7 @@ declare_lint! {
13721432
13731433declare_lint_pass ! ( ImproperCTypesLint => [
13741434 IMPROPER_CTYPES ,
1375- IMPROPER_CTYPES_DEFINITIONS ,
1376- USES_POWER_ALIGNMENT
1435+ IMPROPER_C_FN_DEFINITIONS ,
1436+ IMPROPER_C_CALLBACKS ,
1437+ USES_POWER_ALIGNMENT ,
13771438] ) ;
0 commit comments