10
10
11
11
#![ allow( non_snake_case) ]
12
12
13
- use rustc:: hir:: def_id:: DefId ;
14
13
use rustc:: hir:: map as hir_map;
15
14
use rustc:: ty:: subst:: Substs ;
16
15
use rustc:: ty:: { self , AdtKind , Ty , TyCtxt } ;
@@ -352,18 +351,14 @@ struct ImproperCTypesVisitor<'a, 'tcx: 'a> {
352
351
cx : & ' a LateContext < ' a , ' tcx > ,
353
352
}
354
353
355
- struct FfiError {
356
- message : & ' static str ,
357
- help : Option < & ' static str > ,
358
- }
359
-
360
- enum FfiResult {
354
+ enum FfiResult < ' tcx > {
361
355
FfiSafe ,
362
- FfiPhantom ,
363
- FfiUnsafe ( FfiError ) ,
364
- FfiBadStruct ( DefId , FfiError ) ,
365
- FfiBadUnion ( DefId , FfiError ) ,
366
- FfiBadEnum ( DefId , FfiError ) ,
356
+ FfiPhantom ( Ty < ' tcx > ) ,
357
+ FfiUnsafe {
358
+ ty : Ty < ' tcx > ,
359
+ reason : & ' static str ,
360
+ help : Option < & ' static str > ,
361
+ } ,
367
362
}
368
363
369
364
/// Check if this enum can be safely exported based on the
@@ -406,7 +401,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
406
401
/// representation which can be exported to C code).
407
402
fn check_type_for_ffi ( & self ,
408
403
cache : & mut FxHashSet < Ty < ' tcx > > ,
409
- ty : Ty < ' tcx > ) -> FfiResult {
404
+ ty : Ty < ' tcx > ) -> FfiResult < ' tcx > {
410
405
use self :: FfiResult :: * ;
411
406
412
407
let cx = self . cx . tcx ;
@@ -422,23 +417,24 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
422
417
match ty. sty {
423
418
ty:: TyAdt ( def, substs) => {
424
419
if def. is_phantom_data ( ) {
425
- return FfiPhantom ;
420
+ return FfiPhantom ( ty ) ;
426
421
}
427
422
match def. adt_kind ( ) {
428
423
AdtKind :: Struct => {
429
424
if !def. repr . c ( ) && !def. repr . transparent ( ) {
430
- return FfiUnsafe ( FfiError {
431
- message : "found struct without foreign-function-safe \
432
- representation annotation in foreign module ",
433
- help : Some ( "consider adding a #[repr(C)] attribute to the type " ) ,
434
- } ) ;
425
+ return FfiUnsafe {
426
+ ty : ty ,
427
+ reason : "this struct has unspecified layout ",
428
+ help : Some ( "consider adding a #[repr(C)] attribute to this struct " ) ,
429
+ } ;
435
430
}
436
431
437
432
if def. non_enum_variant ( ) . fields . is_empty ( ) {
438
- return FfiUnsafe ( FfiError {
439
- message : "found zero-size struct in foreign module" ,
433
+ return FfiUnsafe {
434
+ ty : ty,
435
+ reason : "this struct has no fields" ,
440
436
help : Some ( "consider adding a member to this struct" ) ,
441
- } ) ;
437
+ } ;
442
438
}
443
439
444
440
// We can't completely trust repr(C) and repr(transparent) markings;
@@ -464,32 +460,30 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
464
460
FfiSafe => {
465
461
all_phantom = false ;
466
462
}
467
- FfiPhantom => { }
468
- FfiBadStruct ( .. ) | FfiBadUnion ( .. ) | FfiBadEnum ( .. ) => {
463
+ FfiPhantom ( .. ) => { }
464
+ FfiUnsafe { .. } => {
469
465
return r;
470
466
}
471
- FfiUnsafe ( err) => {
472
- return FfiBadStruct ( def. did , err) ;
473
- }
474
467
}
475
468
}
476
469
477
- if all_phantom { FfiPhantom } else { FfiSafe }
470
+ if all_phantom { FfiPhantom ( ty ) } else { FfiSafe }
478
471
}
479
472
AdtKind :: Union => {
480
473
if !def. repr . c ( ) {
481
- return FfiUnsafe ( FfiError {
482
- message : "found union without foreign-function-safe \
483
- representation annotation in foreign module ",
484
- help : Some ( "consider adding a #[repr(C)] attribute to the type " ) ,
485
- } ) ;
474
+ return FfiUnsafe {
475
+ ty : ty ,
476
+ reason : "this union has unspecified layout ",
477
+ help : Some ( "consider adding a #[repr(C)] attribute to this union " ) ,
478
+ } ;
486
479
}
487
480
488
481
if def. non_enum_variant ( ) . fields . is_empty ( ) {
489
- return FfiUnsafe ( FfiError {
490
- message : "found zero-size union in foreign module" ,
491
- help : Some ( "consider adding a member to this union" ) ,
492
- } ) ;
482
+ return FfiUnsafe {
483
+ ty : ty,
484
+ reason : "this union has no fields" ,
485
+ help : Some ( "consider adding a field to this union" ) ,
486
+ } ;
493
487
}
494
488
495
489
let mut all_phantom = true ;
@@ -502,17 +496,14 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
502
496
FfiSafe => {
503
497
all_phantom = false ;
504
498
}
505
- FfiPhantom => { }
506
- FfiBadStruct ( .. ) | FfiBadUnion ( .. ) | FfiBadEnum ( .. ) => {
499
+ FfiPhantom ( .. ) => { }
500
+ FfiUnsafe { .. } => {
507
501
return r;
508
502
}
509
- FfiUnsafe ( err) => {
510
- return FfiBadUnion ( def. did , err) ;
511
- }
512
503
}
513
504
}
514
505
515
- if all_phantom { FfiPhantom } else { FfiSafe }
506
+ if all_phantom { FfiPhantom ( ty ) } else { FfiSafe }
516
507
}
517
508
AdtKind :: Enum => {
518
509
if def. variants . is_empty ( ) {
@@ -525,12 +516,12 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
525
516
if !def. repr . c ( ) && def. repr . int . is_none ( ) {
526
517
// Special-case types like `Option<extern fn()>`.
527
518
if !is_repr_nullable_ptr ( cx, def, substs) {
528
- return FfiUnsafe ( FfiError {
529
- message : "found enum without foreign-function-safe \
530
- representation annotation in foreign module ",
519
+ return FfiUnsafe {
520
+ ty : ty ,
521
+ reason : "enum has no representation hint ",
531
522
help : Some ( "consider adding a #[repr(...)] attribute \
532
- to the type ") ,
533
- } ) ;
523
+ to this enum ") ,
524
+ } ;
534
525
}
535
526
}
536
527
@@ -543,17 +534,15 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
543
534
let r = self . check_type_for_ffi ( cache, arg) ;
544
535
match r {
545
536
FfiSafe => { }
546
- FfiBadStruct ( .. ) | FfiBadUnion ( .. ) | FfiBadEnum ( .. ) => {
537
+ FfiUnsafe { .. } => {
547
538
return r;
548
539
}
549
- FfiPhantom => {
550
- return FfiBadEnum ( def. did , FfiError {
551
- message : "Found phantom data in enum variant" ,
540
+ FfiPhantom ( ..) => {
541
+ return FfiUnsafe {
542
+ ty : ty,
543
+ reason : "this enum contains a PhantomData field" ,
552
544
help : None ,
553
- } ) ;
554
- }
555
- FfiUnsafe ( err) => {
556
- return FfiBadEnum ( def. did , err) ;
545
+ } ;
557
546
}
558
547
}
559
548
}
@@ -563,59 +552,44 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
563
552
}
564
553
}
565
554
566
- ty:: TyChar => {
567
- FfiUnsafe ( FfiError {
568
- message : "found Rust type `char` in foreign module" ,
569
- help : Some ( "consider using `u32` or `libc::wchar_t`" ) ,
570
- } )
571
- }
555
+ ty:: TyChar => FfiUnsafe {
556
+ ty : ty,
557
+ reason : "the `char` type has no C equivalent" ,
558
+ help : Some ( "consider using `u32` or `libc::wchar_t` instead" ) ,
559
+ } ,
572
560
573
- ty:: TyInt ( ast:: IntTy :: I128 ) => {
574
- FfiUnsafe ( FfiError {
575
- message : "found Rust type `i128` in foreign module, but 128-bit \
576
- integers don't currently have a known stable ABI",
577
- help : None ,
578
- } )
579
- }
580
-
581
- ty:: TyUint ( ast:: UintTy :: U128 ) => {
582
- FfiUnsafe ( FfiError {
583
- message : "found Rust type `u128` in foreign module, but 128-bit \
584
- integers don't currently have a known stable ABI",
585
- help : None ,
586
- } )
587
- }
561
+ ty:: TyInt ( ast:: IntTy :: I128 ) | ty:: TyUint ( ast:: UintTy :: U128 ) => FfiUnsafe {
562
+ ty : ty,
563
+ reason : "128-bit integers don't currently have a known stable ABI" ,
564
+ help : None ,
565
+ } ,
588
566
589
567
// Primitive types with a stable representation.
590
568
ty:: TyBool | ty:: TyInt ( ..) | ty:: TyUint ( ..) | ty:: TyFloat ( ..) | ty:: TyNever => FfiSafe ,
591
569
592
- ty:: TySlice ( _) => {
593
- FfiUnsafe ( FfiError {
594
- message : "found Rust slice type in foreign module" ,
595
- help : Some ( "consider using a raw pointer instead" ) ,
596
- } )
597
- }
598
-
599
- ty:: TyDynamic ( ..) => {
600
- FfiUnsafe ( FfiError {
601
- message : "found Rust trait type in foreign module" ,
602
- help : Some ( "consider using a raw pointer instead" ) ,
603
- } )
604
- }
605
-
606
- ty:: TyStr => {
607
- FfiUnsafe ( FfiError {
608
- message : "found Rust type `str` in foreign module" ,
609
- help : Some ( "consider using a `*const libc::c_char`" ) ,
610
- } )
611
- }
612
-
613
- ty:: TyTuple ( ..) => {
614
- FfiUnsafe ( FfiError {
615
- message : "found Rust tuple type in foreign module" ,
616
- help : Some ( "consider using a struct instead" ) ,
617
- } )
618
- }
570
+ ty:: TySlice ( _) => FfiUnsafe {
571
+ ty : ty,
572
+ reason : "slices have no C equivalent" ,
573
+ help : Some ( "consider using a raw pointer instead" ) ,
574
+ } ,
575
+
576
+ ty:: TyDynamic ( ..) => FfiUnsafe {
577
+ ty : ty,
578
+ reason : "trait objects have no C equivalent" ,
579
+ help : Some ( "consider using a raw pointer instead" ) ,
580
+ } ,
581
+
582
+ ty:: TyStr => FfiUnsafe {
583
+ ty : ty,
584
+ reason : "string slices have no C equivalent" ,
585
+ help : Some ( "consider using `*const u8` and a length instead" ) ,
586
+ } ,
587
+
588
+ ty:: TyTuple ( ..) => FfiUnsafe {
589
+ ty : ty,
590
+ reason : "tuples have unspecified layout" ,
591
+ help : Some ( "consider using a struct instead" ) ,
592
+ } ,
619
593
620
594
ty:: TyRawPtr ( ref m) |
621
595
ty:: TyRef ( _, ref m) => self . check_type_for_ffi ( cache, m. ty ) ,
@@ -625,11 +599,12 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
625
599
ty:: TyFnPtr ( sig) => {
626
600
match sig. abi ( ) {
627
601
Abi :: Rust | Abi :: RustIntrinsic | Abi :: PlatformIntrinsic | Abi :: RustCall => {
628
- return FfiUnsafe ( FfiError {
629
- message : "found function pointer with Rust calling convention in \
630
- foreign module",
631
- help : Some ( "consider using an `extern` function pointer" ) ,
632
- } )
602
+ return FfiUnsafe {
603
+ ty : ty,
604
+ reason : "this function pointer has Rust-specific calling convention" ,
605
+ help : Some ( "consider using an `fn \" extern\" (...) -> ...` \
606
+ function pointer instead") ,
607
+ }
633
608
}
634
609
_ => { }
635
610
}
@@ -677,48 +652,17 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
677
652
678
653
match self . check_type_for_ffi ( & mut FxHashSet ( ) , ty) {
679
654
FfiResult :: FfiSafe => { }
680
- FfiResult :: FfiPhantom => {
655
+ FfiResult :: FfiPhantom ( ty ) => {
681
656
self . cx . span_lint ( IMPROPER_CTYPES ,
682
657
sp,
683
- & format ! ( "found zero-sized type composed only \
684
- of phantom-data in a foreign-function.") ) ;
685
- }
686
- FfiResult :: FfiUnsafe ( err) => {
687
- let mut diag = self . cx . struct_span_lint ( IMPROPER_CTYPES , sp, err. message ) ;
688
- if let Some ( s) = err. help {
689
- diag. help ( s) ;
690
- }
691
- diag. emit ( ) ;
692
- }
693
- FfiResult :: FfiBadStruct ( _, err) => {
694
- // FIXME: This diagnostic is difficult to read, and doesn't
695
- // point at the relevant field.
696
- let msg = format ! ( "found non-foreign-function-safe member in struct \
697
- marked #[repr(C)]: {}", err. message) ;
698
- let mut diag = self . cx . struct_span_lint ( IMPROPER_CTYPES , sp, & msg) ;
699
- if let Some ( s) = err. help {
700
- diag. help ( s) ;
701
- }
702
- diag. emit ( ) ;
703
- }
704
- FfiResult :: FfiBadUnion ( _, err) => {
705
- // FIXME: This diagnostic is difficult to read, and doesn't
706
- // point at the relevant field.
707
- let msg = format ! ( "found non-foreign-function-safe member in union \
708
- marked #[repr(C)]: {}", err. message) ;
709
- let mut diag = self . cx . struct_span_lint ( IMPROPER_CTYPES , sp, & msg) ;
710
- if let Some ( s) = err. help {
711
- diag. help ( s) ;
712
- }
713
- diag. emit ( ) ;
658
+ & format ! ( "`extern` block uses type `{}` which is not FFI-safe: \
659
+ composed only of PhantomData", ty) ) ;
714
660
}
715
- FfiResult :: FfiBadEnum ( _, err) => {
716
- // FIXME: This diagnostic is difficult to read, and doesn't
717
- // point at the relevant variant.
718
- let msg = format ! ( "found non-foreign-function-safe member in enum: {}" ,
719
- err. message) ;
661
+ FfiResult :: FfiUnsafe { ty : unsafe_ty, reason, help } => {
662
+ let msg = format ! ( "`extern` block uses type `{}` which is not FFI-safe: {}" ,
663
+ unsafe_ty, reason) ;
720
664
let mut diag = self . cx . struct_span_lint ( IMPROPER_CTYPES , sp, & msg) ;
721
- if let Some ( s) = err . help {
665
+ if let Some ( s) = help {
722
666
diag. help ( s) ;
723
667
}
724
668
diag. emit ( ) ;
0 commit comments