@@ -281,7 +281,6 @@ impl<'tcx> FfiResult<'tcx> {
281281 /// If the FfiUnsafe variant, 'wraps' all reasons,
282282 /// creating new `FfiUnsafeReason`s, putting the originals as their `inner` fields.
283283 /// Otherwise, keep unchanged.
284- #[ expect( unused) ]
285284 fn wrap_all ( self , ty : Ty < ' tcx > , note : DiagMessage , help : Option < DiagMessage > ) -> Self {
286285 match self {
287286 Self :: FfiUnsafe ( this) => {
@@ -534,7 +533,6 @@ struct ImproperCTypesVisitor<'a, 'tcx> {
534533
535534 /// The original type being checked, before we recursed
536535 /// to any other types it contains.
537- base_ty : Ty < ' tcx > ,
538536 base_fn_mode : CItemKind ,
539537}
540538
@@ -551,13 +549,8 @@ impl<'a, 'tcx, 'v> Drop for ImproperCTypesVisitorDepthGuard<'a, 'tcx, 'v> {
551549}
552550
553551impl < ' a , ' tcx > ImproperCTypesVisitor < ' a , ' tcx > {
554- fn new ( cx : & ' a LateContext < ' tcx > , base_ty : Ty < ' tcx > , base_fn_mode : CItemKind ) -> Self {
555- Self {
556- cx,
557- base_ty,
558- base_fn_mode,
559- recursion_limiter : RefCell :: new ( ( FxHashSet :: default ( ) , 0 ) ) ,
560- }
552+ fn new ( cx : & ' a LateContext < ' tcx > , base_fn_mode : CItemKind ) -> Self {
553+ Self { cx, base_fn_mode, recursion_limiter : RefCell :: new ( ( FxHashSet :: default ( ) , 0 ) ) }
561554 }
562555
563556 /// Protect against infinite recursion, for example
@@ -596,6 +589,36 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
596589 }
597590 }
598591
592+ /// Return the right help for Cstring and Cstr-linked unsafety.
593+ fn visit_cstr ( & self , outer_ty : Option < Ty < ' tcx > > , ty : Ty < ' tcx > ) -> FfiResult < ' tcx > {
594+ debug_assert ! ( matches!( ty. kind( ) , ty:: Adt ( def, _)
595+ if matches!(
596+ self . cx. tcx. get_diagnostic_name( def. did( ) ) ,
597+ Some ( sym:: cstring_type | sym:: cstr_type)
598+ )
599+ ) ) ;
600+
601+ let help = if let Some ( outer_ty) = outer_ty {
602+ match outer_ty. kind ( ) {
603+ ty:: Ref ( ..) | ty:: RawPtr ( ..) => {
604+ if outer_ty. is_mutable_ptr ( ) {
605+ fluent:: lint_improper_ctypes_cstr_help_mut
606+ } else {
607+ fluent:: lint_improper_ctypes_cstr_help_const
608+ }
609+ }
610+ ty:: Adt ( ..) if outer_ty. boxed_ty ( ) . is_some ( ) => {
611+ fluent:: lint_improper_ctypes_cstr_help_owned
612+ }
613+ _ => fluent:: lint_improper_ctypes_cstr_help_unknown,
614+ }
615+ } else {
616+ fluent:: lint_improper_ctypes_cstr_help_owned
617+ } ;
618+
619+ FfiResult :: new_with_reason ( ty, fluent:: lint_improper_ctypes_cstr_reason, Some ( help) )
620+ }
621+
599622 /// Checks if the given indirection (box,ref,pointer) is "ffi-safe".
600623 fn visit_indirection (
601624 & self ,
@@ -607,6 +630,35 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
607630 use FfiResult :: * ;
608631 let tcx = self . cx . tcx ;
609632
633+ if let ty:: Adt ( def, _) = inner_ty. kind ( ) {
634+ if let Some ( diag_name @ ( sym:: cstring_type | sym:: cstr_type) ) =
635+ tcx. get_diagnostic_name ( def. did ( ) )
636+ {
637+ // we have better error messages when checking for C-strings directly
638+ let mut cstr_res = self . visit_cstr ( Some ( ty) , inner_ty) ; // always unsafe with one depth-one reason.
639+
640+ // Cstr pointer have metadata, CString is Sized
641+ if diag_name == sym:: cstr_type {
642+ // we need to override the "type" part of `cstr_res`'s only FfiResultReason
643+ // so it says that it's the use of the indirection that is unsafe
644+ match cstr_res {
645+ FfiResult :: FfiUnsafe ( ref mut reasons) => {
646+ reasons. first_mut ( ) . unwrap ( ) . reason . ty = ty;
647+ }
648+ _ => unreachable ! ( ) ,
649+ }
650+ let note = match indirection_type {
651+ IndirectionType :: RawPtr => fluent:: lint_improper_ctypes_unsized_ptr,
652+ IndirectionType :: Ref => fluent:: lint_improper_ctypes_unsized_ref,
653+ IndirectionType :: Box => fluent:: lint_improper_ctypes_unsized_box,
654+ } ;
655+ return cstr_res. wrap_all ( ty, note, None ) ;
656+ } else {
657+ return cstr_res;
658+ }
659+ }
660+ }
661+
610662 match indirection_type {
611663 IndirectionType :: Box => {
612664 // FIXME(ctypes): this logic is broken, but it still fits the current tests
@@ -830,13 +882,8 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
830882 // but function *pointers* don't seem to have the same no-unsized-parameters requirement to compile
831883 if let Some ( sym:: cstring_type | sym:: cstr_type) =
832884 tcx. get_diagnostic_name ( def. did ( ) )
833- && !self . base_ty . is_mutable_ptr ( )
834885 {
835- return FfiResult :: new_with_reason (
836- ty,
837- fluent:: lint_improper_ctypes_cstr_reason,
838- Some ( fluent:: lint_improper_ctypes_cstr_help) ,
839- ) ;
886+ return self . visit_cstr ( outer_ty, ty) ;
840887 }
841888 self . visit_struct_or_union ( state, ty, def, args)
842889 }
@@ -1144,7 +1191,7 @@ impl<'tcx> ImproperCTypesLint {
11441191
11451192 let all_types = iter:: zip ( visitor. tys . drain ( ..) , visitor. spans . drain ( ..) ) ;
11461193 for ( fn_ptr_ty, span) in all_types {
1147- let visitor = ImproperCTypesVisitor :: new ( cx, fn_ptr_ty , fn_mode) ;
1194+ let visitor = ImproperCTypesVisitor :: new ( cx, fn_mode) ;
11481195 // FIXME(ctypes): make a check_for_fnptr
11491196 let ffi_res = visitor. check_type ( state, fn_ptr_ty) ;
11501197
@@ -1194,7 +1241,7 @@ impl<'tcx> ImproperCTypesLint {
11941241
11951242 fn check_foreign_static ( & self , cx : & LateContext < ' tcx > , id : hir:: OwnerId , span : Span ) {
11961243 let ty = cx. tcx . type_of ( id) . instantiate_identity ( ) ;
1197- let visitor = ImproperCTypesVisitor :: new ( cx, ty , CItemKind :: ImportedExtern ) ;
1244+ let visitor = ImproperCTypesVisitor :: new ( cx, CItemKind :: ImportedExtern ) ;
11981245 let ffi_res = visitor. check_type ( VisitorState :: STATIC_TY , ty) ;
11991246 self . process_ffi_result ( cx, span, ffi_res, CItemKind :: ImportedExtern ) ;
12001247 }
@@ -1212,14 +1259,14 @@ impl<'tcx> ImproperCTypesLint {
12121259
12131260 for ( input_ty, input_hir) in iter:: zip ( sig. inputs ( ) , decl. inputs ) {
12141261 let visit_state = VisitorState :: argument_from_fnmode ( fn_mode) ;
1215- let visitor = ImproperCTypesVisitor :: new ( cx, * input_ty , fn_mode) ;
1262+ let visitor = ImproperCTypesVisitor :: new ( cx, fn_mode) ;
12161263 let ffi_res = visitor. check_type ( visit_state, * input_ty) ;
12171264 self . process_ffi_result ( cx, input_hir. span , ffi_res, fn_mode) ;
12181265 }
12191266
12201267 if let hir:: FnRetTy :: Return ( ret_hir) = decl. output {
12211268 let visit_state = VisitorState :: return_from_fnmode ( fn_mode) ;
1222- let visitor = ImproperCTypesVisitor :: new ( cx, sig . output ( ) , fn_mode) ;
1269+ let visitor = ImproperCTypesVisitor :: new ( cx, fn_mode) ;
12231270 let ffi_res = visitor. check_type ( visit_state, sig. output ( ) ) ;
12241271 self . process_ffi_result ( cx, ret_hir. span , ffi_res, fn_mode) ;
12251272 }
0 commit comments