@@ -732,8 +732,6 @@ enum FfiResult<'tcx> {
732
732
reason : DiagMessage ,
733
733
help : Option < DiagMessage > ,
734
734
} ,
735
- // NOTE: this `allow` is only here for one retroactively-added commit
736
- #[ allow( dead_code) ]
737
735
FfiUnsafeWrapper {
738
736
ty : Ty < ' tcx > ,
739
737
reason : DiagMessage ,
@@ -1044,16 +1042,47 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
1044
1042
1045
1043
match * ty. kind ( ) {
1046
1044
ty:: Adt ( def, args) => {
1047
- if let Some ( boxed) = ty. boxed_ty ( )
1048
- && matches ! ( self . mode, CItemKind :: Definition )
1049
- {
1050
- if boxed. is_sized ( tcx, self . cx . typing_env ( ) ) {
1051
- return FfiSafe ;
1045
+ if let Some ( inner_ty) = ty. boxed_ty ( ) {
1046
+ if inner_ty. is_sized ( tcx, self . cx . typing_env ( ) )
1047
+ || matches ! ( inner_ty. kind( ) , ty:: Foreign ( ..) )
1048
+ {
1049
+ // discussion on declaration vs definition:
1050
+ // see the `ty::RawPtr(inner_ty, _) | ty::Ref(_, inner_ty, _)` arm
1051
+ // of this `match *ty.kind()` block
1052
+ if matches ! ( self . mode, CItemKind :: Definition ) {
1053
+ return FfiSafe ;
1054
+ } else {
1055
+ let inner_res = self . check_type_for_ffi ( acc, inner_ty) ;
1056
+ return match inner_res {
1057
+ FfiUnsafe { .. } | FfiUnsafeWrapper { .. } => FfiUnsafeWrapper {
1058
+ ty,
1059
+ reason : fluent:: lint_improper_ctypes_sized_ptr_to_unsafe_type,
1060
+ wrapped : Box :: new ( inner_res) ,
1061
+ help : None ,
1062
+ } ,
1063
+ _ => inner_res,
1064
+ } ;
1065
+ }
1052
1066
} else {
1067
+ let help = match inner_ty. kind ( ) {
1068
+ ty:: Str => Some ( fluent:: lint_improper_ctypes_str_help) ,
1069
+ ty:: Slice ( _) => Some ( fluent:: lint_improper_ctypes_slice_help) ,
1070
+ ty:: Adt ( def, _)
1071
+ if matches ! ( def. adt_kind( ) , AdtKind :: Struct | AdtKind :: Union )
1072
+ && matches ! (
1073
+ tcx. get_diagnostic_name( def. did( ) ) ,
1074
+ Some ( sym:: cstring_type | sym:: cstr_type)
1075
+ )
1076
+ && !acc. base_ty . is_mutable_ptr ( ) =>
1077
+ {
1078
+ Some ( fluent:: lint_improper_ctypes_cstr_help)
1079
+ }
1080
+ _ => None ,
1081
+ } ;
1053
1082
return FfiUnsafe {
1054
1083
ty,
1055
- reason : fluent:: lint_improper_ctypes_box ,
1056
- help : None ,
1084
+ reason : fluent:: lint_improper_ctypes_unsized_box ,
1085
+ help,
1057
1086
} ;
1058
1087
}
1059
1088
}
@@ -1209,15 +1238,6 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
1209
1238
help : Some ( fluent:: lint_improper_ctypes_tuple_help) ,
1210
1239
} ,
1211
1240
1212
- ty:: RawPtr ( ty, _) | ty:: Ref ( _, ty, _)
1213
- if {
1214
- matches ! ( self . mode, CItemKind :: Definition )
1215
- && ty. is_sized ( self . cx . tcx , self . cx . typing_env ( ) )
1216
- } =>
1217
- {
1218
- FfiSafe
1219
- }
1220
-
1221
1241
ty:: RawPtr ( ty, _)
1222
1242
if match ty. kind ( ) {
1223
1243
ty:: Tuple ( tuple) => tuple. is_empty ( ) ,
@@ -1227,7 +1247,66 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
1227
1247
FfiSafe
1228
1248
}
1229
1249
1230
- ty:: RawPtr ( ty, _) | ty:: Ref ( _, ty, _) => self . check_type_for_ffi ( acc, ty) ,
1250
+ ty:: RawPtr ( inner_ty, _) | ty:: Ref ( _, inner_ty, _) => {
1251
+ if inner_ty. is_sized ( tcx, self . cx . typing_env ( ) )
1252
+ || matches ! ( inner_ty. kind( ) , ty:: Foreign ( ..) )
1253
+ {
1254
+ // there's a nuance on what this lint should do for function definitions
1255
+ // (touched upon in https://github.com/rust-lang/rust/issues/66220 and https://github.com/rust-lang/rust/pull/72700)
1256
+ //
1257
+ // (`extern "C" fn fn_name(...) {...}`) versus declarations (`extern "C" {fn fn_name(...);}`).
1258
+ // The big question is: what does "ABI safety" mean? if you have something translated to a C pointer
1259
+ // (which has a stable layout) but points to FFI-unsafe type, is it safe?
1260
+ // on one hand, the function's ABI will match that of a similar C-declared function API,
1261
+ // on the other, dereferencing the pointer in not-rust will be painful.
1262
+ // In this code, the opinion is split between function declarations and function definitions.
1263
+ // For declarations, we see this as unsafe, but for definitions, we see this as safe.
1264
+ // This is mostly because, for extern function declarations, the actual definition of the function is written somewhere else,
1265
+ // so the fact that a pointer's pointee should be treated as opaque to one side or the other can be explicitely written out.
1266
+ // For extern function definitions, however, both callee and some callers can be written in rust,
1267
+ // so developers need to keep as much typing information as possible.
1268
+ if matches ! ( self . mode, CItemKind :: Definition ) {
1269
+ return FfiSafe ;
1270
+ } else if matches ! ( ty. kind( ) , ty:: RawPtr ( ..) )
1271
+ && matches ! ( inner_ty. kind( ) , ty:: Tuple ( tuple) if tuple. is_empty( ) )
1272
+ {
1273
+ FfiSafe
1274
+ } else {
1275
+ let inner_res = self . check_type_for_ffi ( acc, inner_ty) ;
1276
+ return match inner_res {
1277
+ FfiSafe => inner_res,
1278
+ _ => FfiUnsafeWrapper {
1279
+ ty,
1280
+ reason : fluent:: lint_improper_ctypes_sized_ptr_to_unsafe_type,
1281
+ wrapped : Box :: new ( inner_res) ,
1282
+ help : None ,
1283
+ } ,
1284
+ } ;
1285
+ }
1286
+ } else {
1287
+ let help = match inner_ty. kind ( ) {
1288
+ ty:: Str => Some ( fluent:: lint_improper_ctypes_str_help) ,
1289
+ ty:: Slice ( _) => Some ( fluent:: lint_improper_ctypes_slice_help) ,
1290
+ ty:: Adt ( def, _)
1291
+ if matches ! ( def. adt_kind( ) , AdtKind :: Struct | AdtKind :: Union )
1292
+ && matches ! (
1293
+ tcx. get_diagnostic_name( def. did( ) ) ,
1294
+ Some ( sym:: cstring_type | sym:: cstr_type)
1295
+ )
1296
+ && !acc. base_ty . is_mutable_ptr ( ) =>
1297
+ {
1298
+ Some ( fluent:: lint_improper_ctypes_cstr_help)
1299
+ }
1300
+ _ => None ,
1301
+ } ;
1302
+ let reason = match ty. kind ( ) {
1303
+ ty:: RawPtr ( ..) => fluent:: lint_improper_ctypes_unsized_ptr,
1304
+ ty:: Ref ( ..) => fluent:: lint_improper_ctypes_unsized_ref,
1305
+ _ => unreachable ! ( ) ,
1306
+ } ;
1307
+ FfiUnsafe { ty, reason, help }
1308
+ }
1309
+ }
1231
1310
1232
1311
ty:: Array ( inner_ty, _) => self . check_type_for_ffi ( acc, inner_ty) ,
1233
1312
@@ -1245,7 +1324,14 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
1245
1324
for arg in sig. inputs ( ) {
1246
1325
match self . check_type_for_ffi ( acc, * arg) {
1247
1326
FfiSafe => { }
1248
- r => return r,
1327
+ r => {
1328
+ return FfiUnsafeWrapper {
1329
+ ty,
1330
+ reason : fluent:: lint_improper_ctypes_fnptr_indirect_reason,
1331
+ help : None ,
1332
+ wrapped : Box :: new ( r) ,
1333
+ } ;
1334
+ }
1249
1335
}
1250
1336
}
1251
1337
@@ -1254,7 +1340,15 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
1254
1340
return FfiSafe ;
1255
1341
}
1256
1342
1257
- self . check_type_for_ffi ( acc, ret_ty)
1343
+ match self . check_type_for_ffi ( acc, ret_ty) {
1344
+ r @ ( FfiSafe | FfiPhantom ( _) ) => r,
1345
+ r => FfiUnsafeWrapper {
1346
+ ty : ty. clone ( ) ,
1347
+ reason : fluent:: lint_improper_ctypes_fnptr_indirect_reason,
1348
+ help : None ,
1349
+ wrapped : Box :: new ( r) ,
1350
+ } ,
1351
+ }
1258
1352
}
1259
1353
1260
1354
ty:: Foreign ( ..) => FfiSafe ,
0 commit comments