@@ -11,8 +11,8 @@ use rustc_hir::intravisit::VisitorExt;
11
11
use rustc_hir:: { self as hir, AmbigArg } ;
12
12
use rustc_middle:: bug;
13
13
use rustc_middle:: ty:: {
14
- self , Adt , AdtDef , AdtKind , GenericArgsRef , Ty , TyCtxt , TypeSuperVisitable , TypeVisitable ,
15
- TypeVisitableExt ,
14
+ self , Adt , AdtDef , AdtKind , Binder , FnSig , GenericArgsRef , Ty , TyCtxt , TypeSuperVisitable ,
15
+ TypeVisitable , TypeVisitableExt ,
16
16
} ;
17
17
use rustc_session:: { declare_lint, declare_lint_pass} ;
18
18
use rustc_span:: def_id:: LocalDefId ;
@@ -23,6 +23,8 @@ use super::repr_nullable_ptr;
23
23
use crate :: lints:: { ImproperCTypes , ImproperCTypesLayer , UsesPowerAlignment } ;
24
24
use crate :: { LateContext , LateLintPass , LintContext , fluent_generated as fluent} ;
25
25
26
+ type Sig < ' tcx > = Binder < ' tcx , FnSig < ' tcx > > ;
27
+
26
28
/// Getting the (normalized) type out of a field (for, e.g., an enum variant or a tuple).
27
29
#[ inline]
28
30
fn get_type_from_field < ' tcx > (
@@ -156,7 +158,6 @@ impl<'tcx> FfiResult<'tcx> {
156
158
}
157
159
/// If the FfiPhantom variant, turns it into a FfiUnsafe version.
158
160
/// Otherwise, keep unchanged.
159
- #[ expect( unused) ]
160
161
fn forbid_phantom ( self ) -> Self {
161
162
match self {
162
163
Self :: FfiPhantom ( ty) => {
@@ -528,6 +529,41 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
528
529
}
529
530
}
530
531
532
+ /// Checks whether an `extern "ABI" fn` function pointer is indeed FFI-safe to call.
533
+ fn visit_fnptr (
534
+ & self ,
535
+ _state : VisitorState ,
536
+ _outer_ty : Option < Ty < ' tcx > > ,
537
+ ty : Ty < ' tcx > ,
538
+ sig : Sig < ' tcx > ,
539
+ ) -> FfiResult < ' tcx > {
540
+ use FfiResult :: * ;
541
+ debug_assert ! ( !sig. abi( ) . is_rustic_abi( ) ) ;
542
+
543
+ let sig = self . cx . tcx . instantiate_bound_regions_with_erased ( sig) ;
544
+
545
+ let mut all_ffires = FfiSafe ;
546
+
547
+ for arg in sig. inputs ( ) {
548
+ let ffi_res = self . visit_type ( VisitorState :: ArgumentTyInFnPtr , Some ( ty) , * arg) ;
549
+ all_ffires += ffi_res. forbid_phantom ( ) . wrap_all (
550
+ ty,
551
+ fluent:: lint_improper_ctypes_fnptr_indirect_reason,
552
+ None ,
553
+ ) ;
554
+ }
555
+
556
+ let ret_ty = sig. output ( ) ;
557
+
558
+ let ffi_res = self . visit_type ( VisitorState :: ReturnTyInFnPtr , Some ( ty) , ret_ty) ;
559
+ all_ffires += ffi_res. forbid_phantom ( ) . wrap_all (
560
+ ty,
561
+ fluent:: lint_improper_ctypes_fnptr_indirect_reason,
562
+ None ,
563
+ ) ;
564
+ all_ffires
565
+ }
566
+
531
567
/// Checks if a simple numeric (int, float) type has an actual portable definition
532
568
/// for the compile target.
533
569
fn visit_numeric ( & self , ty : Ty < ' tcx > ) -> FfiResult < ' tcx > {
@@ -955,27 +991,21 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
955
991
}
956
992
}
957
993
994
+ // fnptrs are a special case, they always need to be treated as
995
+ // "the element rendered unsafe" because their unsafety doesn't affect
996
+ // their surroundings, and their type is often declared inline
997
+ // as a result, don't go into them when scanning for the safety of something else
958
998
ty:: FnPtr ( sig_tys, hdr) => {
959
999
let sig = sig_tys. with ( hdr) ;
960
1000
if sig. abi ( ) . is_rustic_abi ( ) {
961
- return FfiResult :: new_with_reason (
1001
+ FfiResult :: new_with_reason (
962
1002
ty,
963
1003
fluent:: lint_improper_ctypes_fnptr_reason,
964
1004
Some ( fluent:: lint_improper_ctypes_fnptr_help) ,
965
- ) ;
966
- }
967
-
968
- let sig = tcx. instantiate_bound_regions_with_erased ( sig) ;
969
- for arg in sig. inputs ( ) {
970
- match self . visit_type ( VisitorState :: ArgumentTyInFnPtr , Some ( ty) , * arg) {
971
- FfiSafe => { }
972
- r => return r,
973
- }
1005
+ )
1006
+ } else {
1007
+ FfiSafe
974
1008
}
975
-
976
- let ret_ty = sig. output ( ) ;
977
-
978
- self . visit_type ( VisitorState :: ReturnTyInFnPtr , Some ( ty) , ret_ty)
979
1009
}
980
1010
981
1011
ty:: Foreign ( ..) => FfiSafe ,
@@ -1046,10 +1076,29 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
1046
1076
return res;
1047
1077
}
1048
1078
}
1049
-
1050
1079
self . visit_type ( state, None , ty)
1051
1080
}
1052
1081
1082
+ fn check_for_fnptr ( & self , ty : Ty < ' tcx > ) -> FfiResult < ' tcx > {
1083
+ let ty = self . cx . tcx . try_normalize_erasing_regions ( self . cx . typing_env ( ) , ty) . unwrap_or ( ty) ;
1084
+
1085
+ match * ty. kind ( ) {
1086
+ ty:: FnPtr ( sig_tys, hdr) => {
1087
+ let sig = sig_tys. with ( hdr) ;
1088
+ if sig. abi ( ) . is_rustic_abi ( ) {
1089
+ bug ! (
1090
+ "expected to inspect the type of an `extern \" ABI\" ` FnPtr, not an internal-ABI one"
1091
+ )
1092
+ } else {
1093
+ self . visit_fnptr ( VisitorState :: None , None , ty, sig)
1094
+ }
1095
+ }
1096
+ r @ _ => {
1097
+ bug ! ( "expected to inspect the type of an `extern \" ABI\" ` FnPtr, not {:?}" , r, )
1098
+ }
1099
+ }
1100
+ }
1101
+
1053
1102
fn check_arg_for_power_alignment ( cx : & LateContext < ' tcx > , ty : Ty < ' tcx > ) -> bool {
1054
1103
let tcx = cx. tcx ;
1055
1104
assert ! ( tcx. sess. target. os == "aix" ) ;
@@ -1117,7 +1166,6 @@ impl<'tcx> ImproperCTypesLint {
1117
1166
fn check_type_for_external_abi_fnptr (
1118
1167
& mut self ,
1119
1168
cx : & LateContext < ' tcx > ,
1120
- state : VisitorState ,
1121
1169
hir_ty : & hir:: Ty < ' tcx > ,
1122
1170
ty : Ty < ' tcx > ,
1123
1171
) {
@@ -1160,8 +1208,7 @@ impl<'tcx> ImproperCTypesLint {
1160
1208
let all_types = iter:: zip ( visitor. tys . drain ( ..) , visitor. spans . drain ( ..) ) ;
1161
1209
all_types. for_each ( |( fn_ptr_ty, span) | {
1162
1210
let visitor = ImproperCTypesVisitor :: new ( cx) ;
1163
- // TODO: make a check_for_fnptr
1164
- let ffi_res = visitor. check_for_type ( state, fn_ptr_ty) ;
1211
+ let ffi_res = visitor. check_for_fnptr ( fn_ptr_ty) ;
1165
1212
1166
1213
self . process_ffi_result ( cx, span, ffi_res, CItemKind :: Callback )
1167
1214
} ) ;
@@ -1172,21 +1219,18 @@ impl<'tcx> ImproperCTypesLint {
1172
1219
fn check_fn_for_external_abi_fnptr (
1173
1220
& mut self ,
1174
1221
cx : & LateContext < ' tcx > ,
1175
- fn_mode : CItemKind ,
1176
1222
def_id : LocalDefId ,
1177
1223
decl : & ' tcx hir:: FnDecl < ' _ > ,
1178
1224
) {
1179
1225
let sig = cx. tcx . fn_sig ( def_id) . instantiate_identity ( ) ;
1180
1226
let sig = cx. tcx . instantiate_bound_regions_with_erased ( sig) ;
1181
1227
1182
1228
for ( input_ty, input_hir) in iter:: zip ( sig. inputs ( ) , decl. inputs ) {
1183
- let state = VisitorState :: argument_from_fnmode ( fn_mode) ;
1184
- self . check_type_for_external_abi_fnptr ( cx, state, input_hir, * input_ty) ;
1229
+ self . check_type_for_external_abi_fnptr ( cx, input_hir, * input_ty) ;
1185
1230
}
1186
1231
1187
1232
if let hir:: FnRetTy :: Return ( ret_hir) = decl. output {
1188
- let state = VisitorState :: return_from_fnmode ( fn_mode) ;
1189
- self . check_type_for_external_abi_fnptr ( cx, state, ret_hir, sig. output ( ) ) ;
1233
+ self . check_type_for_external_abi_fnptr ( cx, ret_hir, sig. output ( ) ) ;
1190
1234
}
1191
1235
}
1192
1236
@@ -1207,6 +1251,7 @@ impl<'tcx> ImproperCTypesLint {
1207
1251
ImproperCTypesVisitor :: check_struct_for_power_alignment ( cx, item, adt_def) ;
1208
1252
}
1209
1253
1254
+ /// Check that an extern "ABI" static variable is of a ffi-safe type.
1210
1255
fn check_foreign_static ( & self , cx : & LateContext < ' tcx > , id : hir:: OwnerId , span : Span ) {
1211
1256
let ty = cx. tcx . type_of ( id) . instantiate_identity ( ) ;
1212
1257
let visitor = ImproperCTypesVisitor :: new ( cx) ;
@@ -1359,20 +1404,14 @@ impl<'tcx> LateLintPass<'tcx> for ImproperCTypesLint {
1359
1404
// fnptrs are a special case, they always need to be treated as
1360
1405
// "the element rendered unsafe" because their unsafety doesn't affect
1361
1406
// their surroundings, and their type is often declared inline
1407
+ self . check_fn_for_external_abi_fnptr ( cx, it. owner_id . def_id , sig. decl ) ;
1362
1408
if !abi. is_rustic_abi ( ) {
1363
1409
self . check_foreign_fn (
1364
1410
cx,
1365
1411
CItemKind :: ImportedExtern ,
1366
1412
it. owner_id . def_id ,
1367
1413
sig. decl ,
1368
1414
) ;
1369
- } else {
1370
- self . check_fn_for_external_abi_fnptr (
1371
- cx,
1372
- CItemKind :: ImportedExtern ,
1373
- it. owner_id . def_id ,
1374
- sig. decl ,
1375
- ) ;
1376
1415
}
1377
1416
}
1378
1417
hir:: ForeignItemKind :: Static ( ty, _, _) if !abi. is_rustic_abi ( ) => {
@@ -1389,7 +1428,6 @@ impl<'tcx> LateLintPass<'tcx> for ImproperCTypesLint {
1389
1428
| hir:: ItemKind :: TyAlias ( _, _, ty) => {
1390
1429
self . check_type_for_external_abi_fnptr (
1391
1430
cx,
1392
- VisitorState :: StaticTy ,
1393
1431
ty,
1394
1432
cx. tcx . type_of ( item. owner_id ) . instantiate_identity ( ) ,
1395
1433
) ;
@@ -1422,7 +1460,6 @@ impl<'tcx> LateLintPass<'tcx> for ImproperCTypesLint {
1422
1460
fn check_field_def ( & mut self , cx : & LateContext < ' tcx > , field : & ' tcx hir:: FieldDef < ' tcx > ) {
1423
1461
self . check_type_for_external_abi_fnptr (
1424
1462
cx,
1425
- VisitorState :: StaticTy ,
1426
1463
field. ty ,
1427
1464
cx. tcx . type_of ( field. def_id ) . instantiate_identity ( ) ,
1428
1465
) ;
@@ -1448,10 +1485,9 @@ impl<'tcx> LateLintPass<'tcx> for ImproperCTypesLint {
1448
1485
// fnptrs are a special case, they always need to be treated as
1449
1486
// "the element rendered unsafe" because their unsafety doesn't affect
1450
1487
// their surroundings, and their type is often declared inline
1488
+ self . check_fn_for_external_abi_fnptr ( cx, id, decl) ;
1451
1489
if !abi. is_rustic_abi ( ) {
1452
1490
self . check_foreign_fn ( cx, CItemKind :: ExportedFunction , id, decl) ;
1453
- } else {
1454
- self . check_fn_for_external_abi_fnptr ( cx, CItemKind :: ExportedFunction , id, decl) ;
1455
1491
}
1456
1492
}
1457
1493
}
0 commit comments