Skip to content

Commit a261924

Browse files
authored
Rollup merge of rust-lang#39462 - emilio:improper-ctypes, r=nikomatsakis
lint/ctypes: Don't warn on sized structs with PhantomData. Fixes rust-lang#34798
2 parents 10f6a5c + e866d07 commit a261924

File tree

3 files changed

+79
-7
lines changed

3 files changed

+79
-7
lines changed

src/librustc_lint/types.rs

+39-7
Original file line numberDiff line numberDiff line change
@@ -339,6 +339,7 @@ struct ImproperCTypesVisitor<'a, 'tcx: 'a> {
339339

340340
enum FfiResult {
341341
FfiSafe,
342+
FfiPhantom,
342343
FfiUnsafe(&'static str),
343344
FfiBadStruct(DefId, &'static str),
344345
FfiBadUnion(DefId, &'static str),
@@ -383,8 +384,11 @@ fn is_repr_nullable_ptr<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
383384
impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
384385
/// Check if the given type is "ffi-safe" (has a stable, well-defined
385386
/// 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 {
387390
use self::FfiResult::*;
391+
388392
let cx = self.cx.tcx;
389393

390394
// Protect against infinite recursion, for example
@@ -397,6 +401,9 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
397401

398402
match ty.sty {
399403
ty::TyAdt(def, substs) => {
404+
if def.is_phantom_data() {
405+
return FfiPhantom;
406+
}
400407
match def.adt_kind() {
401408
AdtKind::Struct => {
402409
if !cx.lookup_repr_hints(def.did).contains(&attr::ReprExtern) {
@@ -405,18 +412,22 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
405412
consider adding a #[repr(C)] attribute to the type");
406413
}
407414

408-
// We can't completely trust repr(C) markings; make sure the
409-
// fields are actually safe.
410415
if def.struct_variant().fields.is_empty() {
411416
return FfiUnsafe("found zero-size struct in foreign module, consider \
412417
adding a member to this struct");
413418
}
414419

420+
// We can't completely trust repr(C) markings; make sure the
421+
// fields are actually safe.
422+
let mut all_phantom = true;
415423
for field in &def.struct_variant().fields {
416424
let field_ty = cx.normalize_associated_type(&field.ty(cx, substs));
417425
let r = self.check_type_for_ffi(cache, field_ty);
418426
match r {
419-
FfiSafe => {}
427+
FfiSafe => {
428+
all_phantom = false;
429+
}
430+
FfiPhantom => {}
420431
FfiBadStruct(..) | FfiBadUnion(..) | FfiBadEnum(..) => {
421432
return r;
422433
}
@@ -425,7 +436,8 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
425436
}
426437
}
427438
}
428-
FfiSafe
439+
440+
if all_phantom { FfiPhantom } else { FfiSafe }
429441
}
430442
AdtKind::Union => {
431443
if !cx.lookup_repr_hints(def.did).contains(&attr::ReprExtern) {
@@ -434,11 +446,20 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
434446
consider adding a #[repr(C)] attribute to the type");
435447
}
436448

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;
437455
for field in &def.struct_variant().fields {
438456
let field_ty = cx.normalize_associated_type(&field.ty(cx, substs));
439457
let r = self.check_type_for_ffi(cache, field_ty);
440458
match r {
441-
FfiSafe => {}
459+
FfiSafe => {
460+
all_phantom = false;
461+
}
462+
FfiPhantom => {}
442463
FfiBadStruct(..) | FfiBadUnion(..) | FfiBadEnum(..) => {
443464
return r;
444465
}
@@ -447,7 +468,8 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
447468
}
448469
}
449470
}
450-
FfiSafe
471+
472+
if all_phantom { FfiPhantom } else { FfiSafe }
451473
}
452474
AdtKind::Enum => {
453475
if def.variants.is_empty() {
@@ -498,6 +520,10 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
498520
FfiBadStruct(..) | FfiBadUnion(..) | FfiBadEnum(..) => {
499521
return r;
500522
}
523+
FfiPhantom => {
524+
return FfiBadEnum(def.did,
525+
"Found phantom data in enum variant");
526+
}
501527
FfiUnsafe(s) => {
502528
return FfiBadEnum(def.did, s);
503529
}
@@ -591,6 +617,12 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
591617

592618
match self.check_type_for_ffi(&mut FxHashSet(), ty) {
593619
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+
}
594626
FfiResult::FfiUnsafe(s) => {
595627
self.cx.span_lint(IMPROPER_CTYPES, sp, s);
596628
}

src/test/compile-fail/lint-ctypes.rs

+6
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,9 @@ pub type RustBadRet = extern fn() -> Box<u32>;
2929
pub type CVoidRet = ();
3030
pub struct Foo;
3131

32+
#[repr(C)]
33+
pub struct ZeroSizeWithPhantomData(::std::marker::PhantomData<i32>);
34+
3235
extern {
3336
pub fn ptr_type1(size: *const Foo); //~ ERROR: found struct without
3437
pub fn ptr_type2(size: *const Foo); //~ ERROR: found struct without
@@ -40,6 +43,9 @@ extern {
4043
pub fn tuple_type(p: (i32, i32)); //~ ERROR found Rust tuple type
4144
pub fn tuple_type2(p: I32Pair); //~ ERROR found Rust tuple type
4245
pub fn zero_size(p: ZeroSize); //~ ERROR found zero-size struct
46+
pub fn zero_size_phantom(p: ZeroSizeWithPhantomData); //~ ERROR found zero-sized type
47+
pub fn zero_size_phantom_toplevel()
48+
-> ::std::marker::PhantomData<bool>; //~ ERROR: found zero-sized type
4349
pub fn fn_type(p: RustFn); //~ ERROR found function pointer with Rust
4450
pub fn fn_type2(p: fn()); //~ ERROR found function pointer with Rust
4551
pub fn fn_contained(p: RustBadRet); //~ ERROR: found struct without

src/test/run-pass/issue-34798.rs

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#![forbid(improper_ctypes)]
12+
#![allow(dead_code)]
13+
14+
#[repr(C)]
15+
pub struct Foo {
16+
size: u8,
17+
__value: ::std::marker::PhantomData<i32>,
18+
}
19+
20+
#[repr(C)]
21+
pub struct ZeroSizeWithPhantomData<T>(::std::marker::PhantomData<T>);
22+
23+
#[repr(C)]
24+
pub struct Bar {
25+
size: u8,
26+
baz: ZeroSizeWithPhantomData<i32>,
27+
}
28+
29+
extern "C" {
30+
pub fn bar(_: *mut Foo, _: *mut Bar);
31+
}
32+
33+
fn main() {
34+
}

0 commit comments

Comments
 (0)