@@ -26,12 +26,14 @@ use crate::{LateContext, LateLintPass, LintContext, fluent_generated as fluent};
2626declare_lint ! {
2727 /// The `improper_ctypes` lint detects incorrect use of types in foreign
2828 /// modules.
29+ /// (In other words, declarations of items defined in foreign code.)
2930 ///
3031 /// ### Example
3132 ///
3233 /// ```rust
3334 /// unsafe extern "C" {
3435 /// static STATIC: String;
36+ /// fn some_func(a:String);
3537 /// }
3638 /// ```
3739 ///
@@ -45,14 +47,15 @@ declare_lint! {
4547 /// detects a probable mistake in a definition. The lint usually should
4648 /// provide a description of the issue, along with possibly a hint on how
4749 /// to resolve it.
48- IMPROPER_CTYPES ,
50+ pub ( crate ) IMPROPER_CTYPES ,
4951 Warn ,
5052 "proper use of libc types in foreign modules"
5153}
5254
5355declare_lint ! {
54- /// The `improper_ctypes_definitions ` lint detects incorrect use of
56+ /// The `improper_c_fn_definitions ` lint detects incorrect use of
5557 /// [`extern` function] definitions.
58+ /// (In other words, functions to be used by foreign code.)
5659 ///
5760 /// [`extern` function]: https://doc.rust-lang.org/reference/items/functions.html#extern-function-qualifier
5861 ///
@@ -72,11 +75,39 @@ declare_lint! {
7275 /// lint is an alert that these types should not be used. The lint usually
7376 /// should provide a description of the issue, along with possibly a hint
7477 /// on how to resolve it.
75- IMPROPER_CTYPES_DEFINITIONS ,
78+ pub ( crate ) IMPROPER_C_FN_DEFINITIONS ,
7679 Warn ,
7780 "proper use of libc types in foreign item definitions"
7881}
7982
83+ declare_lint ! {
84+ /// The `improper_c_callbacks` lint detects incorrect use of
85+ /// [`extern` function] pointers.
86+ /// (In other words, function signatures for callbacks.)
87+ ///
88+ /// [`extern` function]: https://doc.rust-lang.org/reference/items/functions.html#extern-function-qualifier
89+ ///
90+ /// ### Example
91+ ///
92+ /// ```rust
93+ /// # #![allow(unused)]
94+ /// pub fn str_emmiter(call_me_back: extern "C" fn(&str)) { }
95+ /// ```
96+ ///
97+ /// {{produces}}
98+ ///
99+ /// ### Explanation
100+ ///
101+ /// There are many parameter and return types that may be specified in an
102+ /// `extern` function that are not compatible with the given ABI. This
103+ /// lint is an alert that these types should not be used. The lint usually
104+ /// should provide a description of the issue, along with possibly a hint
105+ /// on how to resolve it.
106+ pub ( crate ) IMPROPER_C_CALLBACKS ,
107+ Warn ,
108+ "proper use of libc types in foreign-code-compatible callbacks"
109+ }
110+
80111declare_lint ! {
81112 /// The `uses_power_alignment` lint detects specific `repr(C)`
82113 /// aggregates on AIX.
@@ -134,8 +165,9 @@ declare_lint! {
134165
135166declare_lint_pass ! ( ImproperCTypesLint => [
136167 IMPROPER_CTYPES ,
137- IMPROPER_CTYPES_DEFINITIONS ,
138- USES_POWER_ALIGNMENT
168+ IMPROPER_C_FN_DEFINITIONS ,
169+ IMPROPER_C_CALLBACKS ,
170+ USES_POWER_ALIGNMENT ,
139171] ) ;
140172
141173/// Getting the (normalized) type out of a field (for, e.g., an enum variant or a tuple).
@@ -185,10 +217,17 @@ fn variant_has_complex_ctor(variant: &ty::VariantDef) -> bool {
185217 !matches ! ( variant. ctor_kind( ) , Some ( CtorKind :: Const ) )
186218}
187219
188- #[ derive( Clone , Copy ) ]
220+ /// A way to keep track of what we want to lint for FFI-safety.
221+ /// In other words, the nature of the "original item" being checked, and its relation
222+ /// to FFI boundaries.
223+ #[ derive( Clone , Copy , Debug ) ]
189224enum CItemKind {
190- Declaration ,
191- Definition ,
225+ /// Imported items in an `extern "C"` block (function declarations, static variables) -> IMPROPER_CTYPES
226+ ImportedExtern ,
227+ /// `extern "C"` function definitions, to be used elsewhere -> IMPROPER_C_FN_DEFINITIONS,
228+ ExportedFunction ,
229+ /// `extern "C"` function pointers -> IMPROPER_C_CALLBACKS,
230+ Callback ,
192231}
193232
194233#[ derive( Clone , Debug ) ]
@@ -428,16 +467,22 @@ impl VisitorState {
428467 /// Get the proper visitor state for a given function's arguments.
429468 fn argument_from_fnmode ( fn_mode : CItemKind ) -> Self {
430469 match fn_mode {
431- CItemKind :: Definition => VisitorState :: ARGUMENT_TY_IN_DEFINITION ,
432- CItemKind :: Declaration => VisitorState :: ARGUMENT_TY_IN_DECLARATION ,
470+ CItemKind :: ExportedFunction => VisitorState :: ARGUMENT_TY_IN_DEFINITION ,
471+ CItemKind :: ImportedExtern => VisitorState :: ARGUMENT_TY_IN_DECLARATION ,
472+ // we could also deal with CItemKind::Callback,
473+ // but we bake an assumption from this function's call sites here.
474+ _ => bug ! ( "cannot be called with CItemKind::{:?}" , fn_mode) ,
433475 }
434476 }
435477
436478 /// Get the proper visitor state for a given function's return type.
437479 fn return_from_fnmode ( fn_mode : CItemKind ) -> Self {
438480 match fn_mode {
439- CItemKind :: Definition => VisitorState :: RETURN_TY_IN_DEFINITION ,
440- CItemKind :: Declaration => VisitorState :: RETURN_TY_IN_DECLARATION ,
481+ CItemKind :: ExportedFunction => VisitorState :: RETURN_TY_IN_DEFINITION ,
482+ CItemKind :: ImportedExtern => VisitorState :: RETURN_TY_IN_DECLARATION ,
483+ // we could also deal with CItemKind::Callback,
484+ // but we bake an assumption from this function's call sites here.
485+ _ => bug ! ( "cannot be called with CItemKind::{:?}" , fn_mode) ,
441486 }
442487 }
443488
@@ -566,7 +611,8 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
566611 IndirectionType :: Box => {
567612 // FIXME(ctypes): this logic is broken, but it still fits the current tests
568613 if state. is_in_defined_function ( )
569- || ( state. is_in_fnptr ( ) && matches ! ( self . base_fn_mode, CItemKind :: Definition ) )
614+ || ( state. is_in_fnptr ( )
615+ && matches ! ( self . base_fn_mode, CItemKind :: ExportedFunction ) )
570616 {
571617 if inner_ty. is_sized ( tcx, self . cx . typing_env ( ) ) {
572618 return FfiSafe ;
@@ -1102,7 +1148,7 @@ impl<'tcx> ImproperCTypesLint {
11021148 // FIXME(ctypes): make a check_for_fnptr
11031149 let ffi_res = visitor. check_type ( state, fn_ptr_ty) ;
11041150
1105- self . process_ffi_result ( cx, span, ffi_res, fn_mode ) ;
1151+ self . process_ffi_result ( cx, span, ffi_res, CItemKind :: Callback ) ;
11061152 }
11071153 }
11081154
@@ -1148,9 +1194,9 @@ impl<'tcx> ImproperCTypesLint {
11481194
11491195 fn check_foreign_static ( & self , cx : & LateContext < ' tcx > , id : hir:: OwnerId , span : Span ) {
11501196 let ty = cx. tcx . type_of ( id) . instantiate_identity ( ) ;
1151- let visitor = ImproperCTypesVisitor :: new ( cx, ty, CItemKind :: Declaration ) ;
1197+ let visitor = ImproperCTypesVisitor :: new ( cx, ty, CItemKind :: ImportedExtern ) ;
11521198 let ffi_res = visitor. check_type ( VisitorState :: STATIC_TY , ty) ;
1153- self . process_ffi_result ( cx, span, ffi_res, CItemKind :: Declaration ) ;
1199+ self . process_ffi_result ( cx, span, ffi_res, CItemKind :: ImportedExtern ) ;
11541200 }
11551201
11561202 /// Check if a function's argument types and result type are "ffi-safe".
@@ -1165,16 +1211,16 @@ impl<'tcx> ImproperCTypesLint {
11651211 let sig = cx. tcx . instantiate_bound_regions_with_erased ( sig) ;
11661212
11671213 for ( input_ty, input_hir) in iter:: zip ( sig. inputs ( ) , decl. inputs ) {
1168- let state = VisitorState :: argument_from_fnmode ( fn_mode) ;
1214+ let visit_state = VisitorState :: argument_from_fnmode ( fn_mode) ;
11691215 let visitor = ImproperCTypesVisitor :: new ( cx, * input_ty, fn_mode) ;
1170- let ffi_res = visitor. check_type ( state , * input_ty) ;
1216+ let ffi_res = visitor. check_type ( visit_state , * input_ty) ;
11711217 self . process_ffi_result ( cx, input_hir. span , ffi_res, fn_mode) ;
11721218 }
11731219
11741220 if let hir:: FnRetTy :: Return ( ret_hir) = decl. output {
1175- let state = VisitorState :: return_from_fnmode ( fn_mode) ;
1221+ let visit_state = VisitorState :: return_from_fnmode ( fn_mode) ;
11761222 let visitor = ImproperCTypesVisitor :: new ( cx, sig. output ( ) , fn_mode) ;
1177- let ffi_res = visitor. check_type ( state , sig. output ( ) ) ;
1223+ let ffi_res = visitor. check_type ( visit_state , sig. output ( ) ) ;
11781224 self . process_ffi_result ( cx, ret_hir. span , ffi_res, fn_mode) ;
11791225 }
11801226 }
@@ -1251,12 +1297,14 @@ impl<'tcx> ImproperCTypesLint {
12511297 fn_mode : CItemKind ,
12521298 ) {
12531299 let lint = match fn_mode {
1254- CItemKind :: Declaration => IMPROPER_CTYPES ,
1255- CItemKind :: Definition => IMPROPER_CTYPES_DEFINITIONS ,
1300+ CItemKind :: ImportedExtern => IMPROPER_CTYPES ,
1301+ CItemKind :: ExportedFunction => IMPROPER_C_FN_DEFINITIONS ,
1302+ CItemKind :: Callback => IMPROPER_C_CALLBACKS ,
12561303 } ;
12571304 let desc = match fn_mode {
1258- CItemKind :: Declaration => "block" ,
1259- CItemKind :: Definition => "fn" ,
1305+ CItemKind :: ImportedExtern => "`extern` block" ,
1306+ CItemKind :: ExportedFunction => "`extern` fn" ,
1307+ CItemKind :: Callback => "`extern` callback" ,
12601308 } ;
12611309 for reason in reasons. iter_mut ( ) {
12621310 reason. span_note = if let ty:: Adt ( def, _) = reason. ty . kind ( )
@@ -1272,13 +1320,21 @@ impl<'tcx> ImproperCTypesLint {
12721320 }
12731321}
12741322
1275- /// `ImproperCTypesDefinitions` checks items outside of foreign items (e.g. stuff that isn't in
1276- /// `extern "C" { }` blocks):
1323+ /// IMPROPER_CTYPES checks items that are part of a header to a non-rust library
1324+ /// Namely, functions and static variables in `extern "<abi>" { }`,
1325+ /// if `<abi>` is external (e.g. "C").
1326+ ///
1327+ /// `IMPROPER_C_CALLBACKS` checks for function pointers marked with an external ABI.
1328+ /// (fields of type `extern "<abi>" fn`, where e.g. `<abi>` is `C`)
1329+ /// These pointers are searched in all other items which contain types
1330+ /// (e.g.functions, struct definitions, etc)
1331+ ///
1332+ /// `IMPROPER_C_FN_DEFINITIONS` checks rust-defined functions that are marked
1333+ /// to be used from the other side of a FFI boundary.
1334+ /// In other words, `extern "<abi>" fn` definitions and trait-method declarations.
1335+ /// This only matters if `<abi>` is external (e.g. `C`).
12771336///
1278- /// - `extern "<abi>" fn` definitions are checked in the same way as the
1279- /// `ImproperCtypesDeclarations` visitor checks functions if `<abi>` is external (e.g. "C").
1280- /// - All other items which contain types (e.g. other functions, struct definitions, etc) are
1281- /// checked for extern fn-ptrs with external ABIs.
1337+ /// and now combinatorics for pointees
12821338impl < ' tcx > LateLintPass < ' tcx > for ImproperCTypesLint {
12831339 fn check_foreign_item ( & mut self , cx : & LateContext < ' tcx > , it : & hir:: ForeignItem < ' tcx > ) {
12841340 let abi = cx. tcx . hir_get_foreign_abi ( it. hir_id ( ) ) ;
@@ -1289,11 +1345,16 @@ impl<'tcx> LateLintPass<'tcx> for ImproperCTypesLint {
12891345 // "the element rendered unsafe" because their unsafety doesn't affect
12901346 // their surroundings, and their type is often declared inline
12911347 if !abi. is_rustic_abi ( ) {
1292- self . check_foreign_fn ( cx, CItemKind :: Declaration , it. owner_id . def_id , sig. decl ) ;
1348+ self . check_foreign_fn (
1349+ cx,
1350+ CItemKind :: ImportedExtern ,
1351+ it. owner_id . def_id ,
1352+ sig. decl ,
1353+ ) ;
12931354 } else {
12941355 self . check_fn_for_external_abi_fnptr (
12951356 cx,
1296- CItemKind :: Declaration ,
1357+ CItemKind :: ImportedExtern ,
12971358 it. owner_id . def_id ,
12981359 sig. decl ,
12991360 ) ;
@@ -1316,7 +1377,7 @@ impl<'tcx> LateLintPass<'tcx> for ImproperCTypesLint {
13161377 VisitorState :: STATIC_TY ,
13171378 ty,
13181379 cx. tcx . type_of ( item. owner_id ) . instantiate_identity ( ) ,
1319- CItemKind :: Definition ,
1380+ CItemKind :: ExportedFunction , // TODO: for some reason, this is the value that reproduces old behaviour
13201381 ) ;
13211382 }
13221383 // See `check_fn` for declarations, `check_foreign_items` for definitions in extern blocks
@@ -1350,7 +1411,7 @@ impl<'tcx> LateLintPass<'tcx> for ImproperCTypesLint {
13501411 VisitorState :: STATIC_TY ,
13511412 field. ty ,
13521413 cx. tcx . type_of ( field. def_id ) . instantiate_identity ( ) ,
1353- CItemKind :: Definition ,
1414+ CItemKind :: ImportedExtern ,
13541415 ) ;
13551416 }
13561417
@@ -1375,9 +1436,9 @@ impl<'tcx> LateLintPass<'tcx> for ImproperCTypesLint {
13751436 // "the element rendered unsafe" because their unsafety doesn't affect
13761437 // their surroundings, and their type is often declared inline
13771438 if !abi. is_rustic_abi ( ) {
1378- self . check_foreign_fn ( cx, CItemKind :: Definition , id, decl) ;
1439+ self . check_foreign_fn ( cx, CItemKind :: ExportedFunction , id, decl) ;
13791440 } else {
1380- self . check_fn_for_external_abi_fnptr ( cx, CItemKind :: Definition , id, decl) ;
1441+ self . check_fn_for_external_abi_fnptr ( cx, CItemKind :: ExportedFunction , id, decl) ;
13811442 }
13821443 }
13831444}
0 commit comments