@@ -25,12 +25,14 @@ use crate::{LateContext, LateLintPass, LintContext, fluent_generated as fluent};
2525declare_lint ! {
2626 /// The `improper_ctypes` lint detects incorrect use of types in foreign
2727 /// modules.
28+ /// (In other words, declarations of items defined in foreign code.)
2829 ///
2930 /// ### Example
3031 ///
3132 /// ```rust
3233 /// unsafe extern "C" {
3334 /// static STATIC: String;
35+ /// fn some_func(a:String);
3436 /// }
3537 /// ```
3638 ///
@@ -44,14 +46,15 @@ declare_lint! {
4446 /// detects a probable mistake in a definition. The lint usually should
4547 /// provide a description of the issue, along with possibly a hint on how
4648 /// to resolve it.
47- IMPROPER_CTYPES ,
49+ pub ( crate ) IMPROPER_CTYPES ,
4850 Warn ,
4951 "proper use of libc types in foreign modules"
5052}
5153
5254declare_lint ! {
53- /// The `improper_ctypes_definitions ` lint detects incorrect use of
55+ /// The `improper_c_fn_definitions ` lint detects incorrect use of
5456 /// [`extern` function] definitions.
57+ /// (In other words, functions to be used by foreign code.)
5558 ///
5659 /// [`extern` function]: https://doc.rust-lang.org/reference/items/functions.html#extern-function-qualifier
5760 ///
@@ -71,11 +74,39 @@ declare_lint! {
7174 /// lint is an alert that these types should not be used. The lint usually
7275 /// should provide a description of the issue, along with possibly a hint
7376 /// on how to resolve it.
74- IMPROPER_CTYPES_DEFINITIONS ,
77+ pub ( crate ) IMPROPER_C_FN_DEFINITIONS ,
7578 Warn ,
7679 "proper use of libc types in foreign item definitions"
7780}
7881
82+ declare_lint ! {
83+ /// The `improper_c_callbacks` lint detects incorrect use of
84+ /// [`extern` function] pointers.
85+ /// (In other words, function signatures for callbacks.)
86+ ///
87+ /// [`extern` function]: https://doc.rust-lang.org/reference/items/functions.html#extern-function-qualifier
88+ ///
89+ /// ### Example
90+ ///
91+ /// ```rust
92+ /// # #![allow(unused)]
93+ /// pub fn str_emmiter(call_me_back: extern "C" fn(&str)) { }
94+ /// ```
95+ ///
96+ /// {{produces}}
97+ ///
98+ /// ### Explanation
99+ ///
100+ /// There are many parameter and return types that may be specified in an
101+ /// `extern` function that are not compatible with the given ABI. This
102+ /// lint is an alert that these types should not be used. The lint usually
103+ /// should provide a description of the issue, along with possibly a hint
104+ /// on how to resolve it.
105+ pub ( crate ) IMPROPER_C_CALLBACKS ,
106+ Warn ,
107+ "proper use of libc types in foreign-code-compatible callbacks"
108+ }
109+
79110declare_lint ! {
80111 /// The `uses_power_alignment` lint detects specific `repr(C)`
81112 /// aggregates on AIX.
@@ -133,8 +164,9 @@ declare_lint! {
133164
134165declare_lint_pass ! ( ImproperCTypesLint => [
135166 IMPROPER_CTYPES ,
136- IMPROPER_CTYPES_DEFINITIONS ,
137- USES_POWER_ALIGNMENT
167+ IMPROPER_C_FN_DEFINITIONS ,
168+ IMPROPER_C_CALLBACKS ,
169+ USES_POWER_ALIGNMENT ,
138170] ) ;
139171
140172/// Getting the (normalized) type out of a field (for, e.g., an enum variant or a tuple).
@@ -254,10 +286,17 @@ fn check_struct_for_power_alignment<'tcx>(
254286 }
255287}
256288
257- #[ derive( Clone , Copy ) ]
289+ /// A way to keep track of what we want to lint for FFI-safety.
290+ /// In other words, the nature of the "original item" being checked, and its relation
291+ /// to FFI boundaries.
292+ #[ derive( Clone , Copy , Debug ) ]
258293enum CItemKind {
259- Declaration ,
260- Definition ,
294+ /// Imported items in an `extern "C"` block (function declarations, static variables) -> IMPROPER_CTYPES
295+ ImportedExtern ,
296+ /// `extern "C"` function definitions, to be used elsewhere -> IMPROPER_C_FN_DEFINITIONS,
297+ ExportedFunction ,
298+ /// `extern "C"` function pointers -> IMPROPER_C_CALLBACKS,
299+ Callback ,
261300}
262301
263302#[ derive( Clone , Debug ) ]
@@ -472,7 +511,9 @@ bitflags! {
472511 /// (struct/enum/union definitions, FnPtrs).
473512 const THEORETICAL = 0b010000 ;
474513 }
514+ }
475515
516+ bitflags ! {
476517 /// "Ephemeral state" flags for VisitorState (lost when visiting new mir::Ty,
477518 /// mostly contain info about the Ty immediately containing the current one).
478519 #[ derive( Clone , Copy , Debug , PartialEq , Eq ) ]
@@ -583,17 +624,23 @@ impl VisitorState {
583624 /// Get the proper visitor state for a given function's arguments.
584625 fn argument_from_fnmode ( fn_mode : CItemKind ) -> Self {
585626 let p_flags = match fn_mode {
586- CItemKind :: Definition => PersistentStateFlags :: ARGUMENT_TY_IN_DEFINITION ,
587- CItemKind :: Declaration => PersistentStateFlags :: ARGUMENT_TY_IN_DECLARATION ,
627+ CItemKind :: ExportedFunction => PersistentStateFlags :: ARGUMENT_TY_IN_DEFINITION ,
628+ CItemKind :: ImportedExtern => PersistentStateFlags :: ARGUMENT_TY_IN_DECLARATION ,
629+ // we could also deal with CItemKind::Callback,
630+ // but we bake an assumption from this function's call sites here.
631+ _ => bug ! ( "cannot be called with CItemKind::{:?}" , fn_mode) ,
588632 } ;
589633 Self :: entry_point ( p_flags)
590634 }
591635
592636 /// Get the proper visitor state for a given function's return type.
593637 fn return_from_fnmode ( fn_mode : CItemKind ) -> Self {
594638 let p_flags = match fn_mode {
595- CItemKind :: Definition => PersistentStateFlags :: RETURN_TY_IN_DEFINITION ,
596- CItemKind :: Declaration => PersistentStateFlags :: RETURN_TY_IN_DECLARATION ,
639+ CItemKind :: ExportedFunction => PersistentStateFlags :: RETURN_TY_IN_DEFINITION ,
640+ CItemKind :: ImportedExtern => PersistentStateFlags :: RETURN_TY_IN_DECLARATION ,
641+ // we could also deal with CItemKind::Callback,
642+ // but we bake an assumption from this function's call sites here.
643+ _ => bug ! ( "cannot be called with CItemKind::{:?}" , fn_mode) ,
597644 } ;
598645 Self :: entry_point ( p_flags)
599646 }
@@ -699,7 +746,8 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
699746 // - otherwise, treat the box itself correctly, and follow pointee safety logic
700747 // as described in the other `indirection_type` match branch.
701748 if state. is_in_defined_function ( )
702- || ( state. is_in_fnptr ( ) && matches ! ( self . base_fn_mode, CItemKind :: Definition ) )
749+ || ( state. is_in_fnptr ( )
750+ && matches ! ( self . base_fn_mode, CItemKind :: ExportedFunction ) )
703751 {
704752 if inner_ty. is_sized ( tcx, self . cx . typing_env ( ) ) {
705753 return FfiSafe ;
@@ -1189,7 +1237,7 @@ impl<'tcx> ImproperCTypesLint {
11891237 // FIXME(ctypes): make a check_for_fnptr
11901238 let ffi_res = visitor. check_type ( bridge_state, fn_ptr_ty) ;
11911239
1192- self . process_ffi_result ( cx, span, ffi_res, fn_mode ) ;
1240+ self . process_ffi_result ( cx, span, ffi_res, CItemKind :: Callback ) ;
11931241 }
11941242 }
11951243
@@ -1235,9 +1283,9 @@ impl<'tcx> ImproperCTypesLint {
12351283
12361284 fn check_foreign_static ( & mut self , cx : & LateContext < ' tcx > , id : hir:: OwnerId , span : Span ) {
12371285 let ty = cx. tcx . type_of ( id) . instantiate_identity ( ) ;
1238- let mut visitor = ImproperCTypesVisitor :: new ( cx, ty, CItemKind :: Declaration ) ;
1286+ let mut visitor = ImproperCTypesVisitor :: new ( cx, ty, CItemKind :: ImportedExtern ) ;
12391287 let ffi_res = visitor. check_type ( VisitorState :: static_var ( ) , ty) ;
1240- self . process_ffi_result ( cx, span, ffi_res, CItemKind :: Declaration ) ;
1288+ self . process_ffi_result ( cx, span, ffi_res, CItemKind :: ImportedExtern ) ;
12411289 }
12421290
12431291 /// Check if a function's argument types and result type are "ffi-safe".
@@ -1252,16 +1300,16 @@ impl<'tcx> ImproperCTypesLint {
12521300 let sig = cx. tcx . instantiate_bound_regions_with_erased ( sig) ;
12531301
12541302 for ( input_ty, input_hir) in iter:: zip ( sig. inputs ( ) , decl. inputs ) {
1255- let state = VisitorState :: argument_from_fnmode ( fn_mode) ;
1303+ let visit_state = VisitorState :: argument_from_fnmode ( fn_mode) ;
12561304 let mut visitor = ImproperCTypesVisitor :: new ( cx, * input_ty, fn_mode) ;
1257- let ffi_res = visitor. check_type ( state , * input_ty) ;
1305+ let ffi_res = visitor. check_type ( visit_state , * input_ty) ;
12581306 self . process_ffi_result ( cx, input_hir. span , ffi_res, fn_mode) ;
12591307 }
12601308
12611309 if let hir:: FnRetTy :: Return ( ret_hir) = decl. output {
1262- let state = VisitorState :: return_from_fnmode ( fn_mode) ;
1310+ let visit_state = VisitorState :: return_from_fnmode ( fn_mode) ;
12631311 let mut visitor = ImproperCTypesVisitor :: new ( cx, sig. output ( ) , fn_mode) ;
1264- let ffi_res = visitor. check_type ( state , sig. output ( ) ) ;
1312+ let ffi_res = visitor. check_type ( visit_state , sig. output ( ) ) ;
12651313 self . process_ffi_result ( cx, ret_hir. span , ffi_res, fn_mode) ;
12661314 }
12671315 }
@@ -1338,12 +1386,14 @@ impl<'tcx> ImproperCTypesLint {
13381386 fn_mode : CItemKind ,
13391387 ) {
13401388 let lint = match fn_mode {
1341- CItemKind :: Declaration => IMPROPER_CTYPES ,
1342- CItemKind :: Definition => IMPROPER_CTYPES_DEFINITIONS ,
1389+ CItemKind :: ImportedExtern => IMPROPER_CTYPES ,
1390+ CItemKind :: ExportedFunction => IMPROPER_C_FN_DEFINITIONS ,
1391+ CItemKind :: Callback => IMPROPER_C_CALLBACKS ,
13431392 } ;
13441393 let desc = match fn_mode {
1345- CItemKind :: Declaration => "block" ,
1346- CItemKind :: Definition => "fn" ,
1394+ CItemKind :: ImportedExtern => "`extern` block" ,
1395+ CItemKind :: ExportedFunction => "`extern` fn" ,
1396+ CItemKind :: Callback => "`extern` callback" ,
13471397 } ;
13481398 for reason in reasons. iter_mut ( ) {
13491399 reason. span_note = if let ty:: Adt ( def, _) = reason. ty . kind ( )
@@ -1359,13 +1409,21 @@ impl<'tcx> ImproperCTypesLint {
13591409 }
13601410}
13611411
1362- /// `ImproperCTypesDefinitions` checks items outside of foreign items (e.g. stuff that isn't in
1363- /// `extern "C" { }` blocks):
1412+ /// IMPROPER_CTYPES checks items that are part of a header to a non-rust library
1413+ /// Namely, functions and static variables in `extern "<abi>" { }`,
1414+ /// if `<abi>` is external (e.g. "C").
1415+ ///
1416+ /// `IMPROPER_C_CALLBACKS` checks for function pointers marked with an external ABI.
1417+ /// (fields of type `extern "<abi>" fn`, where e.g. `<abi>` is `C`)
1418+ /// These pointers are searched in all other items which contain types
1419+ /// (e.g.functions, struct definitions, etc)
1420+ ///
1421+ /// `IMPROPER_C_FN_DEFINITIONS` checks rust-defined functions that are marked
1422+ /// to be used from the other side of a FFI boundary.
1423+ /// In other words, `extern "<abi>" fn` definitions and trait-method declarations.
1424+ /// This only matters if `<abi>` is external (e.g. `C`).
13641425///
1365- /// - `extern "<abi>" fn` definitions are checked in the same way as the
1366- /// `ImproperCtypesDeclarations` visitor checks functions if `<abi>` is external (e.g. "C").
1367- /// - All other items which contain types (e.g. other functions, struct definitions, etc) are
1368- /// checked for extern fn-ptrs with external ABIs.
1426+ /// and now combinatorics for pointees
13691427impl < ' tcx > LateLintPass < ' tcx > for ImproperCTypesLint {
13701428 fn check_foreign_item ( & mut self , cx : & LateContext < ' tcx > , it : & hir:: ForeignItem < ' tcx > ) {
13711429 let abi = cx. tcx . hir_get_foreign_abi ( it. hir_id ( ) ) ;
@@ -1376,11 +1434,16 @@ impl<'tcx> LateLintPass<'tcx> for ImproperCTypesLint {
13761434 // "the element rendered unsafe" because their unsafety doesn't affect
13771435 // their surroundings, and their type is often declared inline
13781436 if !abi. is_rustic_abi ( ) {
1379- self . check_foreign_fn ( cx, CItemKind :: Declaration , it. owner_id . def_id , sig. decl ) ;
1437+ self . check_foreign_fn (
1438+ cx,
1439+ CItemKind :: ImportedExtern ,
1440+ it. owner_id . def_id ,
1441+ sig. decl ,
1442+ ) ;
13801443 } else {
13811444 self . check_fn_for_external_abi_fnptr (
13821445 cx,
1383- CItemKind :: Declaration ,
1446+ CItemKind :: ImportedExtern ,
13841447 it. owner_id . def_id ,
13851448 sig. decl ,
13861449 ) ;
@@ -1403,7 +1466,7 @@ impl<'tcx> LateLintPass<'tcx> for ImproperCTypesLint {
14031466 VisitorState :: static_var ( ) ,
14041467 ty,
14051468 cx. tcx . type_of ( item. owner_id ) . instantiate_identity ( ) ,
1406- CItemKind :: Definition ,
1469+ CItemKind :: ExportedFunction , // TODO: for some reason, this is the value that reproduces old behaviour
14071470 ) ;
14081471 }
14091472 // See `check_fn` for declarations, `check_foreign_items` for definitions in extern blocks
@@ -1437,7 +1500,7 @@ impl<'tcx> LateLintPass<'tcx> for ImproperCTypesLint {
14371500 VisitorState :: static_var ( ) ,
14381501 field. ty ,
14391502 cx. tcx . type_of ( field. def_id ) . instantiate_identity ( ) ,
1440- CItemKind :: Definition ,
1503+ CItemKind :: ImportedExtern ,
14411504 ) ;
14421505 }
14431506
@@ -1462,9 +1525,9 @@ impl<'tcx> LateLintPass<'tcx> for ImproperCTypesLint {
14621525 // "the element rendered unsafe" because their unsafety doesn't affect
14631526 // their surroundings, and their type is often declared inline
14641527 if !abi. is_rustic_abi ( ) {
1465- self . check_foreign_fn ( cx, CItemKind :: Definition , id, decl) ;
1528+ self . check_foreign_fn ( cx, CItemKind :: ExportedFunction , id, decl) ;
14661529 } else {
1467- self . check_fn_for_external_abi_fnptr ( cx, CItemKind :: Definition , id, decl) ;
1530+ self . check_fn_for_external_abi_fnptr ( cx, CItemKind :: ExportedFunction , id, decl) ;
14681531 }
14691532 }
14701533}
0 commit comments