@@ -341,6 +341,7 @@ struct ImproperCTypesVisitor<'a, 'tcx: 'a> {
341341
342342enum FfiResult {
343343 FfiSafe ,
344+ FfiPhantom ,
344345 FfiUnsafe ( & ' static str ) ,
345346 FfiBadStruct ( DefId , & ' static str ) ,
346347 FfiBadUnion ( DefId , & ' static str ) ,
@@ -385,8 +386,11 @@ fn is_repr_nullable_ptr<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
385386impl < ' a , ' tcx > ImproperCTypesVisitor < ' a , ' tcx > {
386387 /// Check if the given type is "ffi-safe" (has a stable, well-defined
387388 /// 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 {
389392 use self :: FfiResult :: * ;
393+
390394 let cx = self . cx . tcx ;
391395
392396 // Protect against infinite recursion, for example
@@ -399,6 +403,9 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
399403
400404 match ty. sty {
401405 ty:: TyAdt ( def, substs) => {
406+ if def. is_phantom_data ( ) {
407+ return FfiPhantom ;
408+ }
402409 match def. adt_kind ( ) {
403410 AdtKind :: Struct => {
404411 if !cx. lookup_repr_hints ( def. did ) . contains ( & attr:: ReprExtern ) {
@@ -407,18 +414,22 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
407414 consider adding a #[repr(C)] attribute to the type") ;
408415 }
409416
410- // We can't completely trust repr(C) markings; make sure the
411- // fields are actually safe.
412417 if def. struct_variant ( ) . fields . is_empty ( ) {
413418 return FfiUnsafe ( "found zero-size struct in foreign module, consider \
414419 adding a member to this struct") ;
415420 }
416421
422+ // We can't completely trust repr(C) markings; make sure the
423+ // fields are actually safe.
424+ let mut all_phantom = true ;
417425 for field in & def. struct_variant ( ) . fields {
418426 let field_ty = cx. normalize_associated_type ( & field. ty ( cx, substs) ) ;
419427 let r = self . check_type_for_ffi ( cache, field_ty) ;
420428 match r {
421- FfiSafe => { }
429+ FfiSafe => {
430+ all_phantom = false ;
431+ }
432+ FfiPhantom => { }
422433 FfiBadStruct ( ..) | FfiBadUnion ( ..) | FfiBadEnum ( ..) => {
423434 return r;
424435 }
@@ -427,7 +438,8 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
427438 }
428439 }
429440 }
430- FfiSafe
441+
442+ if all_phantom { FfiPhantom } else { FfiSafe }
431443 }
432444 AdtKind :: Union => {
433445 if !cx. lookup_repr_hints ( def. did ) . contains ( & attr:: ReprExtern ) {
@@ -436,11 +448,20 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
436448 consider adding a #[repr(C)] attribute to the type") ;
437449 }
438450
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 ;
439457 for field in & def. struct_variant ( ) . fields {
440458 let field_ty = cx. normalize_associated_type ( & field. ty ( cx, substs) ) ;
441459 let r = self . check_type_for_ffi ( cache, field_ty) ;
442460 match r {
443- FfiSafe => { }
461+ FfiSafe => {
462+ all_phantom = false ;
463+ }
464+ FfiPhantom => { }
444465 FfiBadStruct ( ..) | FfiBadUnion ( ..) | FfiBadEnum ( ..) => {
445466 return r;
446467 }
@@ -449,7 +470,8 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
449470 }
450471 }
451472 }
452- FfiSafe
473+
474+ if all_phantom { FfiPhantom } else { FfiSafe }
453475 }
454476 AdtKind :: Enum => {
455477 if def. variants . is_empty ( ) {
@@ -500,6 +522,10 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
500522 FfiBadStruct ( ..) | FfiBadUnion ( ..) | FfiBadEnum ( ..) => {
501523 return r;
502524 }
525+ FfiPhantom => {
526+ return FfiBadEnum ( def. did ,
527+ "Found phantom data in enum variant" ) ;
528+ }
503529 FfiUnsafe ( s) => {
504530 return FfiBadEnum ( def. did , s) ;
505531 }
@@ -593,6 +619,12 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
593619
594620 match self . check_type_for_ffi ( & mut FxHashSet ( ) , ty) {
595621 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+ }
596628 FfiResult :: FfiUnsafe ( s) => {
597629 self . cx . span_lint ( IMPROPER_CTYPES , sp, s) ;
598630 }
0 commit comments