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