@@ -134,7 +134,6 @@ impl<'tcx> FfiResult<'tcx> {
134
134
/// If the FfiUnsafe variant, 'wraps' all reasons,
135
135
/// creating new `FfiUnsafeReason`s, putting the originals as their `inner` fields.
136
136
/// Otherwise, keep unchanged.
137
- #[ expect( unused) ]
138
137
fn wrap_all ( self , ty : Ty < ' tcx > , note : DiagMessage , help : Option < DiagMessage > ) -> Self {
139
138
match self {
140
139
Self :: FfiUnsafe ( this) => {
@@ -376,7 +375,6 @@ struct ImproperCTypesVisitor<'a, 'tcx> {
376
375
377
376
/// The original type being checked, before we recursed
378
377
/// to any other types it contains.
379
- base_ty : Ty < ' tcx > ,
380
378
base_fn_mode : CItemKind ,
381
379
}
382
380
@@ -393,13 +391,8 @@ impl<'a, 'tcx, 'v> Drop for ImproperCTypesVisitorDepthGuard<'a, 'tcx, 'v> {
393
391
}
394
392
395
393
impl < ' a , ' tcx > ImproperCTypesVisitor < ' a , ' tcx > {
396
- fn new ( cx : & ' a LateContext < ' tcx > , base_ty : Ty < ' tcx > , base_fn_mode : CItemKind ) -> Self {
397
- Self {
398
- cx,
399
- base_ty,
400
- base_fn_mode,
401
- recursion_limiter : RefCell :: new ( ( FxHashSet :: default ( ) , 0 ) ) ,
402
- }
394
+ fn new ( cx : & ' a LateContext < ' tcx > , base_fn_mode : CItemKind ) -> Self {
395
+ Self { cx, base_fn_mode, recursion_limiter : RefCell :: new ( ( FxHashSet :: default ( ) , 0 ) ) }
403
396
}
404
397
405
398
/// Protect against infinite recursion, for example
@@ -438,6 +431,36 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
438
431
}
439
432
}
440
433
434
+ /// Return the right help for Cstring and Cstr-linked unsafety.
435
+ fn visit_cstr ( & self , outer_ty : Option < Ty < ' tcx > > , ty : Ty < ' tcx > ) -> FfiResult < ' tcx > {
436
+ debug_assert ! ( matches!( ty. kind( ) , ty:: Adt ( def, _)
437
+ if matches!(
438
+ self . cx. tcx. get_diagnostic_name( def. did( ) ) ,
439
+ Some ( sym:: cstring_type | sym:: cstr_type)
440
+ )
441
+ ) ) ;
442
+
443
+ let help = if let Some ( outer_ty) = outer_ty {
444
+ match outer_ty. kind ( ) {
445
+ ty:: Ref ( ..) | ty:: RawPtr ( ..) => {
446
+ if outer_ty. is_mutable_ptr ( ) {
447
+ fluent:: lint_improper_ctypes_cstr_help_mut
448
+ } else {
449
+ fluent:: lint_improper_ctypes_cstr_help_const
450
+ }
451
+ }
452
+ ty:: Adt ( ..) if outer_ty. boxed_ty ( ) . is_some ( ) => {
453
+ fluent:: lint_improper_ctypes_cstr_help_owned
454
+ }
455
+ _ => fluent:: lint_improper_ctypes_cstr_help_unknown,
456
+ }
457
+ } else {
458
+ fluent:: lint_improper_ctypes_cstr_help_owned
459
+ } ;
460
+
461
+ FfiResult :: new_with_reason ( ty, fluent:: lint_improper_ctypes_cstr_reason, Some ( help) )
462
+ }
463
+
441
464
/// Checks if the given indirection (box,ref,pointer) is "ffi-safe".
442
465
fn visit_indirection (
443
466
& self ,
@@ -449,6 +472,35 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
449
472
use FfiResult :: * ;
450
473
let tcx = self . cx . tcx ;
451
474
475
+ if let ty:: Adt ( def, _) = inner_ty. kind ( ) {
476
+ if let Some ( diag_name @ ( sym:: cstring_type | sym:: cstr_type) ) =
477
+ tcx. get_diagnostic_name ( def. did ( ) )
478
+ {
479
+ // we have better error messages when checking for C-strings directly
480
+ let mut cstr_res = self . visit_cstr ( Some ( ty) , inner_ty) ; // always unsafe with one depth-one reason.
481
+
482
+ // Cstr pointer have metadata, CString is Sized
483
+ if diag_name == sym:: cstr_type {
484
+ // we need to override the "type" part of `cstr_res`'s only FfiResultReason
485
+ // so it says that it's the use of the indirection that is unsafe
486
+ match cstr_res {
487
+ FfiResult :: FfiUnsafe ( ref mut reasons) => {
488
+ reasons. first_mut ( ) . unwrap ( ) . reason . ty = ty;
489
+ }
490
+ _ => unreachable ! ( ) ,
491
+ }
492
+ let note = match indirection_type {
493
+ IndirectionType :: RawPtr => fluent:: lint_improper_ctypes_unsized_ptr,
494
+ IndirectionType :: Ref => fluent:: lint_improper_ctypes_unsized_ref,
495
+ IndirectionType :: Box => fluent:: lint_improper_ctypes_unsized_box,
496
+ } ;
497
+ return cstr_res. wrap_all ( ty, note, None ) ;
498
+ } else {
499
+ return cstr_res;
500
+ }
501
+ }
502
+ }
503
+
452
504
match indirection_type {
453
505
IndirectionType :: Box => {
454
506
// TODO: this logic is broken, but it still fits the current tests
@@ -679,13 +731,8 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
679
731
// but function *pointers* don't seem to have the same no-unsized-parameters requirement to compile
680
732
if let Some ( sym:: cstring_type | sym:: cstr_type) =
681
733
tcx. get_diagnostic_name ( def. did ( ) )
682
- && !self . base_ty . is_mutable_ptr ( )
683
734
{
684
- return FfiResult :: new_with_reason (
685
- ty,
686
- fluent:: lint_improper_ctypes_cstr_reason,
687
- Some ( fluent:: lint_improper_ctypes_cstr_help) ,
688
- ) ;
735
+ return self . visit_cstr ( outer_ty, ty) ;
689
736
}
690
737
self . visit_struct_or_union ( state, ty, def, args)
691
738
}
@@ -991,7 +1038,7 @@ impl<'tcx> ImproperCTypesLint {
991
1038
992
1039
let all_types = iter:: zip ( visitor. tys . drain ( ..) , visitor. spans . drain ( ..) ) ;
993
1040
all_types. for_each ( |( fn_ptr_ty, span) | {
994
- let visitor = ImproperCTypesVisitor :: new ( cx, fn_ptr_ty , fn_mode) ;
1041
+ let visitor = ImproperCTypesVisitor :: new ( cx, fn_mode) ;
995
1042
// TODO: make a check_for_fnptr
996
1043
let ffi_res = visitor. check_for_type ( state, fn_ptr_ty) ;
997
1044
@@ -1041,7 +1088,7 @@ impl<'tcx> ImproperCTypesLint {
1041
1088
1042
1089
fn check_foreign_static ( & self , cx : & LateContext < ' tcx > , id : hir:: OwnerId , span : Span ) {
1043
1090
let ty = cx. tcx . type_of ( id) . instantiate_identity ( ) ;
1044
- let visitor = ImproperCTypesVisitor :: new ( cx, ty , CItemKind :: ImportedExtern ) ;
1091
+ let visitor = ImproperCTypesVisitor :: new ( cx, CItemKind :: ImportedExtern ) ;
1045
1092
let ffi_res = visitor. check_for_type ( VisitorState :: StaticTy , ty) ;
1046
1093
self . process_ffi_result ( cx, span, ffi_res, CItemKind :: ImportedExtern ) ;
1047
1094
}
@@ -1059,14 +1106,14 @@ impl<'tcx> ImproperCTypesLint {
1059
1106
1060
1107
for ( input_ty, input_hir) in iter:: zip ( sig. inputs ( ) , decl. inputs ) {
1061
1108
let visit_state = VisitorState :: argument_from_fnmode ( fn_mode) ;
1062
- let visitor = ImproperCTypesVisitor :: new ( cx, * input_ty , fn_mode) ;
1109
+ let visitor = ImproperCTypesVisitor :: new ( cx, fn_mode) ;
1063
1110
let ffi_res = visitor. check_for_type ( visit_state, * input_ty) ;
1064
1111
self . process_ffi_result ( cx, input_hir. span , ffi_res, fn_mode) ;
1065
1112
}
1066
1113
1067
1114
if let hir:: FnRetTy :: Return ( ret_hir) = decl. output {
1068
1115
let visit_state = VisitorState :: return_from_fnmode ( fn_mode) ;
1069
- let visitor = ImproperCTypesVisitor :: new ( cx, sig . output ( ) , fn_mode) ;
1116
+ let visitor = ImproperCTypesVisitor :: new ( cx, fn_mode) ;
1070
1117
let ffi_res = visitor. check_for_type ( visit_state, sig. output ( ) ) ;
1071
1118
self . process_ffi_result ( cx, ret_hir. span , ffi_res, fn_mode) ;
1072
1119
}
0 commit comments