@@ -341,6 +341,7 @@ struct ImproperCTypesVisitor<'a, 'tcx: 'a> {
341
341
342
342
enum FfiResult {
343
343
FfiSafe ,
344
+ FfiPhantom ,
344
345
FfiUnsafe ( & ' static str ) ,
345
346
FfiBadStruct ( DefId , & ' static str ) ,
346
347
FfiBadUnion ( DefId , & ' static str ) ,
@@ -385,8 +386,11 @@ fn is_repr_nullable_ptr<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
385
386
impl < ' a , ' tcx > ImproperCTypesVisitor < ' a , ' tcx > {
386
387
/// Check if the given type is "ffi-safe" (has a stable, well-defined
387
388
/// representation which can be exported to C code).
388
- fn check_type_for_ffi ( & self , cache : & mut FxHashSet < Ty < ' tcx > > , ty : Ty < ' tcx > ) -> FfiResult {
389
+ fn check_type_for_ffi ( & self ,
390
+ cache : & mut FxHashSet < Ty < ' tcx > > ,
391
+ ty : Ty < ' tcx > ) -> FfiResult {
389
392
use self :: FfiResult :: * ;
393
+
390
394
let cx = self . cx . tcx ;
391
395
392
396
// Protect against infinite recursion, for example
@@ -399,6 +403,9 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
399
403
400
404
match ty. sty {
401
405
ty:: TyAdt ( def, substs) => {
406
+ if def. is_phantom_data ( ) {
407
+ return FfiPhantom ;
408
+ }
402
409
match def. adt_kind ( ) {
403
410
AdtKind :: Struct => {
404
411
if !cx. lookup_repr_hints ( def. did ) . contains ( & attr:: ReprExtern ) {
@@ -407,18 +414,22 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
407
414
consider adding a #[repr(C)] attribute to the type") ;
408
415
}
409
416
410
- // We can't completely trust repr(C) markings; make sure the
411
- // fields are actually safe.
412
417
if def. struct_variant ( ) . fields . is_empty ( ) {
413
418
return FfiUnsafe ( "found zero-size struct in foreign module, consider \
414
419
adding a member to this struct") ;
415
420
}
416
421
422
+ // We can't completely trust repr(C) markings; make sure the
423
+ // fields are actually safe.
424
+ let mut all_phantom = true ;
417
425
for field in & def. struct_variant ( ) . fields {
418
426
let field_ty = cx. normalize_associated_type ( & field. ty ( cx, substs) ) ;
419
427
let r = self . check_type_for_ffi ( cache, field_ty) ;
420
428
match r {
421
- FfiSafe => { }
429
+ FfiSafe => {
430
+ all_phantom = false ;
431
+ }
432
+ FfiPhantom => { }
422
433
FfiBadStruct ( ..) | FfiBadUnion ( ..) | FfiBadEnum ( ..) => {
423
434
return r;
424
435
}
@@ -427,7 +438,8 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
427
438
}
428
439
}
429
440
}
430
- FfiSafe
441
+
442
+ if all_phantom { FfiPhantom } else { FfiSafe }
431
443
}
432
444
AdtKind :: Union => {
433
445
if !cx. lookup_repr_hints ( def. did ) . contains ( & attr:: ReprExtern ) {
@@ -436,11 +448,20 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
436
448
consider adding a #[repr(C)] attribute to the type") ;
437
449
}
438
450
451
+ if def. struct_variant ( ) . fields . is_empty ( ) {
452
+ return FfiUnsafe ( "found zero-size union in foreign module, consider \
453
+ adding a member to this union") ;
454
+ }
455
+
456
+ let mut all_phantom = true ;
439
457
for field in & def. struct_variant ( ) . fields {
440
458
let field_ty = cx. normalize_associated_type ( & field. ty ( cx, substs) ) ;
441
459
let r = self . check_type_for_ffi ( cache, field_ty) ;
442
460
match r {
443
- FfiSafe => { }
461
+ FfiSafe => {
462
+ all_phantom = false ;
463
+ }
464
+ FfiPhantom => { }
444
465
FfiBadStruct ( ..) | FfiBadUnion ( ..) | FfiBadEnum ( ..) => {
445
466
return r;
446
467
}
@@ -449,7 +470,8 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
449
470
}
450
471
}
451
472
}
452
- FfiSafe
473
+
474
+ if all_phantom { FfiPhantom } else { FfiSafe }
453
475
}
454
476
AdtKind :: Enum => {
455
477
if def. variants . is_empty ( ) {
@@ -500,6 +522,10 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
500
522
FfiBadStruct ( ..) | FfiBadUnion ( ..) | FfiBadEnum ( ..) => {
501
523
return r;
502
524
}
525
+ FfiPhantom => {
526
+ return FfiBadEnum ( def. did ,
527
+ "Found phantom data in enum variant" ) ;
528
+ }
503
529
FfiUnsafe ( s) => {
504
530
return FfiBadEnum ( def. did , s) ;
505
531
}
@@ -593,6 +619,12 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
593
619
594
620
match self . check_type_for_ffi ( & mut FxHashSet ( ) , ty) {
595
621
FfiResult :: FfiSafe => { }
622
+ FfiResult :: FfiPhantom => {
623
+ self . cx . span_lint ( IMPROPER_CTYPES ,
624
+ sp,
625
+ & format ! ( "found zero-sized type composed only \
626
+ of phantom-data in a foreign-function.") ) ;
627
+ }
596
628
FfiResult :: FfiUnsafe ( s) => {
597
629
self . cx . span_lint ( IMPROPER_CTYPES , sp, s) ;
598
630
}
0 commit comments