@@ -25,13 +25,19 @@ 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.)
29+ /// This also includes all [`extern` function] pointers.
30+ ///
31+ /// [`extern` function]: https://doc.rust-lang.org/reference/items/functions.html#extern-function-qualifier
2832 ///
2933 /// ### Example
3034 ///
3135 /// ```rust
3236 /// unsafe extern "C" {
3337 /// static STATIC: String;
38+ /// fn some_func(a:String);
3439 /// }
40+ /// extern "C" fn register_callback(a: i32, call: extern "C" fn(char)) { /* ... */ }
3541 /// ```
3642 ///
3743 /// {{produces}}
@@ -44,14 +50,15 @@ declare_lint! {
4450 /// detects a probable mistake in a definition. The lint usually should
4551 /// provide a description of the issue, along with possibly a hint on how
4652 /// to resolve it.
47- IMPROPER_CTYPES ,
53+ pub ( crate ) IMPROPER_CTYPES ,
4854 Warn ,
4955 "proper use of libc types in foreign modules"
5056}
5157
5258declare_lint ! {
5359 /// The `improper_ctypes_definitions` lint detects incorrect use of
5460 /// [`extern` function] definitions.
61+ /// (In other words, functions to be used by foreign code.)
5562 ///
5663 /// [`extern` function]: https://doc.rust-lang.org/reference/items/functions.html#extern-function-qualifier
5764 ///
@@ -71,7 +78,7 @@ declare_lint! {
7178 /// lint is an alert that these types should not be used. The lint usually
7279 /// should provide a description of the issue, along with possibly a hint
7380 /// on how to resolve it.
74- IMPROPER_CTYPES_DEFINITIONS ,
81+ pub ( crate ) IMPROPER_CTYPES_DEFINITIONS ,
7582 Warn ,
7683 "proper use of libc types in foreign item definitions"
7784}
@@ -134,7 +141,7 @@ declare_lint! {
134141declare_lint_pass ! ( ImproperCTypesLint => [
135142 IMPROPER_CTYPES ,
136143 IMPROPER_CTYPES_DEFINITIONS ,
137- USES_POWER_ALIGNMENT
144+ USES_POWER_ALIGNMENT ,
138145] ) ;
139146
140147/// Getting the (normalized) type out of a field (for, e.g., an enum variant or a tuple).
@@ -254,13 +261,19 @@ fn check_struct_for_power_alignment<'tcx>(
254261 }
255262}
256263
257- /// Annotates whether we are in the context of an item *defined* in rust
258- /// and exposed to an FFI boundary,
259- /// or the context of an item from elsewhere, whose interface is re-*declared* in rust.
260- #[ derive( Clone , Copy ) ]
264+ /// Annotates the nature of the "original item" being checked, and its relation
265+ /// to FFI boundaries.
266+ /// Mainly, whether is is something defined in rust and exported through the FFI boundary,
267+ /// or something rust imports through the same boundary.
268+ /// Callbacks are ultimately treated as imported items, in terms of denying/warning/ignoring FFI-unsafety
269+ #[ derive( Clone , Copy , Debug ) ]
261270enum CItemKind {
262- Declaration ,
263- Definition ,
271+ /// Imported items in an `extern "C"` block (function declarations, static variables) -> IMPROPER_CTYPES
272+ ImportedExtern ,
273+ /// `extern "C"` function definitions, to be used elsewhere -> IMPROPER_CTYPES_DEFINITIONS,
274+ ExportedFunction ,
275+ /// `extern "C"` function pointers -> also IMPROPER_CTYPES,
276+ Callback ,
264277}
265278
266279/// Annotates whether we are in the context of a function's argument types or return type.
@@ -582,10 +595,13 @@ impl VisitorState {
582595 /// Get the proper visitor state for a given function's arguments or return type.
583596 fn entry_point_from_fnmode ( fn_mode : CItemKind , fn_pos : FnPos ) -> Self {
584597 let p_flags = match ( fn_mode, fn_pos) {
585- ( CItemKind :: Definition , FnPos :: Ret ) => RootUseFlags :: RETURN_TY_IN_DEFINITION ,
586- ( CItemKind :: Declaration , FnPos :: Ret ) => RootUseFlags :: RETURN_TY_IN_DECLARATION ,
587- ( CItemKind :: Definition , FnPos :: Arg ) => RootUseFlags :: ARGUMENT_TY_IN_DEFINITION ,
588- ( CItemKind :: Declaration , FnPos :: Arg ) => RootUseFlags :: ARGUMENT_TY_IN_DECLARATION ,
598+ ( CItemKind :: ExportedFunction , FnPos :: Ret ) => RootUseFlags :: RETURN_TY_IN_DEFINITION ,
599+ ( CItemKind :: ImportedExtern , FnPos :: Ret ) => RootUseFlags :: RETURN_TY_IN_DECLARATION ,
600+ ( CItemKind :: ExportedFunction , FnPos :: Arg ) => RootUseFlags :: ARGUMENT_TY_IN_DEFINITION ,
601+ ( CItemKind :: ImportedExtern , FnPos :: Arg ) => RootUseFlags :: ARGUMENT_TY_IN_DECLARATION ,
602+ // we could also deal with CItemKind::Callback,
603+ // but we bake an assumption from this function's call sites here.
604+ _ => bug ! ( "cannot be called with CItemKind::{:?}" , fn_mode) ,
589605 } ;
590606 Self :: entry_point ( p_flags)
591607 }
@@ -689,7 +705,8 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
689705 // - otherwise, treat the box itself correctly, and follow pointee safety logic
690706 // as described in the other `indirection_type` match branch.
691707 if state. is_in_defined_function ( )
692- || ( state. is_in_fnptr ( ) && matches ! ( self . base_fn_mode, CItemKind :: Definition ) )
708+ || ( state. is_in_fnptr ( )
709+ && matches ! ( self . base_fn_mode, CItemKind :: ExportedFunction ) )
693710 {
694711 if inner_ty. is_sized ( tcx, self . cx . typing_env ( ) ) {
695712 return FfiSafe ;
@@ -1177,7 +1194,7 @@ impl<'tcx> ImproperCTypesLint {
11771194 // FIXME(ctypes): make a check_for_fnptr
11781195 let ffi_res = visitor. check_type ( bridge_state, fn_ptr_ty) ;
11791196
1180- self . process_ffi_result ( cx, span, ffi_res, fn_mode ) ;
1197+ self . process_ffi_result ( cx, span, ffi_res, CItemKind :: Callback ) ;
11811198 }
11821199 }
11831200
@@ -1223,9 +1240,9 @@ impl<'tcx> ImproperCTypesLint {
12231240
12241241 fn check_foreign_static ( & mut self , cx : & LateContext < ' tcx > , id : hir:: OwnerId , span : Span ) {
12251242 let ty = cx. tcx . type_of ( id) . instantiate_identity ( ) ;
1226- let mut visitor = ImproperCTypesVisitor :: new ( cx, ty, CItemKind :: Declaration ) ;
1243+ let mut visitor = ImproperCTypesVisitor :: new ( cx, ty, CItemKind :: ImportedExtern ) ;
12271244 let ffi_res = visitor. check_type ( VisitorState :: static_var ( ) , ty) ;
1228- self . process_ffi_result ( cx, span, ffi_res, CItemKind :: Declaration ) ;
1245+ self . process_ffi_result ( cx, span, ffi_res, CItemKind :: ImportedExtern ) ;
12291246 }
12301247
12311248 /// Check if a function's argument types and result type are "ffi-safe".
@@ -1326,12 +1343,16 @@ impl<'tcx> ImproperCTypesLint {
13261343 fn_mode : CItemKind ,
13271344 ) {
13281345 let lint = match fn_mode {
1329- CItemKind :: Declaration => IMPROPER_CTYPES ,
1330- CItemKind :: Definition => IMPROPER_CTYPES_DEFINITIONS ,
1346+ CItemKind :: ImportedExtern => IMPROPER_CTYPES ,
1347+ CItemKind :: ExportedFunction => IMPROPER_CTYPES_DEFINITIONS ,
1348+ // Internally, we treat this differently, but at the end of the day
1349+ // their linting needs to be enabled/disabled alongside that of "FFI-imported" items.
1350+ CItemKind :: Callback => IMPROPER_CTYPES ,
13311351 } ;
13321352 let desc = match fn_mode {
1333- CItemKind :: Declaration => "block" ,
1334- CItemKind :: Definition => "fn" ,
1353+ CItemKind :: ImportedExtern => "`extern` block" ,
1354+ CItemKind :: ExportedFunction => "`extern` fn" ,
1355+ CItemKind :: Callback => "`extern` callback" ,
13351356 } ;
13361357 for reason in reasons. iter_mut ( ) {
13371358 reason. span_note = if let ty:: Adt ( def, _) = reason. ty . kind ( )
@@ -1347,13 +1368,20 @@ impl<'tcx> ImproperCTypesLint {
13471368 }
13481369}
13491370
1350- /// `ImproperCTypesDefinitions` checks items outside of foreign items (e.g. stuff that isn't in
1351- /// `extern "C" { }` blocks):
1371+ /// IMPROPER_CTYPES checks items that are part of a header to a non-rust library
1372+ /// Namely, functions and static variables in `extern "<abi>" { }`,
1373+ /// if `<abi>` is external (e.g. "C").
1374+ /// it also checks for function pointers marked with an external ABI.
1375+ /// (fields of type `extern "<abi>" fn`, where e.g. `<abi>` is `C`)
1376+ /// These pointers are searched in all other items which contain types
1377+ /// (e.g.functions, struct definitions, etc)
13521378///
1353- /// - `extern "<abi>" fn` definitions are checked in the same way as the
1354- /// `ImproperCtypesDeclarations` visitor checks functions if `<abi>` is external (e.g. "C").
1355- /// - All other items which contain types (e.g. other functions, struct definitions, etc) are
1356- /// checked for extern fn-ptrs with external ABIs.
1379+ /// `IMPROPER_CTYPES_DEFINITIONS` checks rust-defined functions that are marked
1380+ /// to be used from the other side of a FFI boundary.
1381+ /// In other words, `extern "<abi>" fn` definitions and trait-method declarations.
1382+ /// This only matters if `<abi>` is external (e.g. `C`).
1383+ ///
1384+ /// maybe later: specialised lints for pointees
13571385impl < ' tcx > LateLintPass < ' tcx > for ImproperCTypesLint {
13581386 fn check_foreign_item ( & mut self , cx : & LateContext < ' tcx > , it : & hir:: ForeignItem < ' tcx > ) {
13591387 let abi = cx. tcx . hir_get_foreign_abi ( it. hir_id ( ) ) ;
@@ -1364,11 +1392,16 @@ impl<'tcx> LateLintPass<'tcx> for ImproperCTypesLint {
13641392 // "the element rendered unsafe" because their unsafety doesn't affect
13651393 // their surroundings, and their type is often declared inline
13661394 if !abi. is_rustic_abi ( ) {
1367- self . check_foreign_fn ( cx, CItemKind :: Declaration , it. owner_id . def_id , sig. decl ) ;
1395+ self . check_foreign_fn (
1396+ cx,
1397+ CItemKind :: ImportedExtern ,
1398+ it. owner_id . def_id ,
1399+ sig. decl ,
1400+ ) ;
13681401 } else {
13691402 self . check_fn_for_external_abi_fnptr (
13701403 cx,
1371- CItemKind :: Declaration ,
1404+ CItemKind :: ImportedExtern ,
13721405 it. owner_id . def_id ,
13731406 sig. decl ,
13741407 ) ;
@@ -1391,7 +1424,7 @@ impl<'tcx> LateLintPass<'tcx> for ImproperCTypesLint {
13911424 VisitorState :: static_var ( ) ,
13921425 ty,
13931426 cx. tcx . type_of ( item. owner_id ) . instantiate_identity ( ) ,
1394- CItemKind :: Definition ,
1427+ CItemKind :: ExportedFunction , // TODO: for some reason, this is the value that reproduces old behaviour
13951428 ) ;
13961429 }
13971430 // See `check_fn` for declarations, `check_foreign_items` for definitions in extern blocks
@@ -1425,7 +1458,7 @@ impl<'tcx> LateLintPass<'tcx> for ImproperCTypesLint {
14251458 VisitorState :: static_var ( ) ,
14261459 field. ty ,
14271460 cx. tcx . type_of ( field. def_id ) . instantiate_identity ( ) ,
1428- CItemKind :: Definition ,
1461+ CItemKind :: ImportedExtern ,
14291462 ) ;
14301463 }
14311464
@@ -1450,9 +1483,9 @@ impl<'tcx> LateLintPass<'tcx> for ImproperCTypesLint {
14501483 // "the element rendered unsafe" because their unsafety doesn't affect
14511484 // their surroundings, and their type is often declared inline
14521485 if !abi. is_rustic_abi ( ) {
1453- self . check_foreign_fn ( cx, CItemKind :: Definition , id, decl) ;
1486+ self . check_foreign_fn ( cx, CItemKind :: ExportedFunction , id, decl) ;
14541487 } else {
1455- self . check_fn_for_external_abi_fnptr ( cx, CItemKind :: Definition , id, decl) ;
1488+ self . check_fn_for_external_abi_fnptr ( cx, CItemKind :: ExportedFunction , id, decl) ;
14561489 }
14571490 }
14581491}
0 commit comments