@@ -134,7 +134,6 @@ impl<'tcx> FfiResult<'tcx> {
134134 /// If the FfiUnsafe variant, 'wraps' all reasons,
135135 /// creating new `FfiUnsafeReason`s, putting the originals as their `inner` fields.
136136 /// Otherwise, keep unchanged.
137- #[ expect( unused) ]
138137 fn wrap_all ( self , ty : Ty < ' tcx > , note : DiagMessage , help : Option < DiagMessage > ) -> Self {
139138 match self {
140139 Self :: FfiUnsafe ( this) => {
@@ -376,7 +375,6 @@ struct ImproperCTypesVisitor<'a, 'tcx> {
376375
377376 /// The original type being checked, before we recursed
378377 /// to any other types it contains.
379- base_ty : Ty < ' tcx > ,
380378 base_fn_mode : CItemKind ,
381379}
382380
@@ -393,13 +391,8 @@ impl<'a, 'tcx, 'v> Drop for ImproperCTypesVisitorDepthGuard<'a, 'tcx, 'v> {
393391}
394392
395393impl < ' 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 ) ) }
403396 }
404397
405398 /// Protect against infinite recursion, for example
@@ -438,6 +431,36 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
438431 }
439432 }
440433
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+
441464 /// Checks if the given indirection (box,ref,pointer) is "ffi-safe".
442465 fn visit_indirection (
443466 & self ,
@@ -449,6 +472,35 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
449472 use FfiResult :: * ;
450473 let tcx = self . cx . tcx ;
451474
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+
452504 match indirection_type {
453505 IndirectionType :: Box => {
454506 // TODO: this logic is broken, but it still fits the current tests
@@ -679,13 +731,8 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
679731 // but function *pointers* don't seem to have the same no-unsized-parameters requirement to compile
680732 if let Some ( sym:: cstring_type | sym:: cstr_type) =
681733 tcx. get_diagnostic_name ( def. did ( ) )
682- && !self . base_ty . is_mutable_ptr ( )
683734 {
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) ;
689736 }
690737 self . visit_struct_or_union ( state, ty, def, args)
691738 }
@@ -991,7 +1038,7 @@ impl<'tcx> ImproperCTypesLint {
9911038
9921039 let all_types = iter:: zip ( visitor. tys . drain ( ..) , visitor. spans . drain ( ..) ) ;
9931040 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) ;
9951042 // TODO: make a check_for_fnptr
9961043 let ffi_res = visitor. check_for_type ( state, fn_ptr_ty) ;
9971044
@@ -1041,7 +1088,7 @@ impl<'tcx> ImproperCTypesLint {
10411088
10421089 fn check_foreign_static ( & self , cx : & LateContext < ' tcx > , id : hir:: OwnerId , span : Span ) {
10431090 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 ) ;
10451092 let ffi_res = visitor. check_for_type ( VisitorState :: StaticTy , ty) ;
10461093 self . process_ffi_result ( cx, span, ffi_res, CItemKind :: ImportedExtern ) ;
10471094 }
@@ -1059,14 +1106,14 @@ impl<'tcx> ImproperCTypesLint {
10591106
10601107 for ( input_ty, input_hir) in iter:: zip ( sig. inputs ( ) , decl. inputs ) {
10611108 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) ;
10631110 let ffi_res = visitor. check_for_type ( visit_state, * input_ty) ;
10641111 self . process_ffi_result ( cx, input_hir. span , ffi_res, fn_mode) ;
10651112 }
10661113
10671114 if let hir:: FnRetTy :: Return ( ret_hir) = decl. output {
10681115 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) ;
10701117 let ffi_res = visitor. check_for_type ( visit_state, sig. output ( ) ) ;
10711118 self . process_ffi_result ( cx, ret_hir. span , ffi_res, fn_mode) ;
10721119 }
0 commit comments