Skip to content

Commit 797f247

Browse files
committed
Mark ZST as FFI-safe if all its fields are PhantomData
Modify the linting behavior and add the corresponding regression test
1 parent 2b8590e commit 797f247

File tree

2 files changed

+45
-23
lines changed

2 files changed

+45
-23
lines changed

compiler/rustc_lint/src/types.rs

+23-23
Original file line numberDiff line numberDiff line change
@@ -878,39 +878,39 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
878878
) -> FfiResult<'tcx> {
879879
use FfiResult::*;
880880

881-
if def.repr().transparent() {
881+
let transparent_safety = def.repr().transparent().then(|| {
882882
// Can assume that at most one field is not a ZST, so only check
883883
// that field's type for FFI-safety.
884884
if let Some(field) = transparent_newtype_field(self.cx.tcx, variant) {
885-
self.check_field_type_for_ffi(cache, field, substs)
885+
return self.check_field_type_for_ffi(cache, field, substs);
886886
} else {
887887
// All fields are ZSTs; this means that the type should behave
888-
// like (), which is FFI-unsafe
888+
// like (), which is FFI-unsafe... except if all fields are PhantomData,
889+
// which is tested for below
889890
FfiUnsafe { ty, reason: fluent::lint_improper_ctypes_struct_zst, help: None }
890891
}
891-
} else {
892-
// We can't completely trust repr(C) markings; make sure the fields are
893-
// actually safe.
894-
let mut all_phantom = !variant.fields.is_empty();
895-
for field in &variant.fields {
896-
match self.check_field_type_for_ffi(cache, &field, substs) {
897-
FfiSafe => {
898-
all_phantom = false;
899-
}
900-
FfiPhantom(..) if def.is_enum() => {
901-
return FfiUnsafe {
902-
ty,
903-
reason: fluent::lint_improper_ctypes_enum_phantomdata,
904-
help: None,
905-
};
906-
}
907-
FfiPhantom(..) => {}
908-
r => return r,
892+
});
893+
// We can't completely trust repr(C) markings; make sure the fields are
894+
// actually safe.
895+
let mut all_phantom = !variant.fields.is_empty();
896+
for field in &variant.fields {
897+
match self.check_field_type_for_ffi(cache, &field, substs) {
898+
FfiSafe => {
899+
all_phantom = false;
909900
}
901+
FfiPhantom(..) if !def.repr().transparent() && def.is_enum() => {
902+
return FfiUnsafe {
903+
ty,
904+
reason: fluent::lint_improper_ctypes_enum_phantomdata,
905+
help: None,
906+
};
907+
}
908+
FfiPhantom(..) => {}
909+
r => return transparent_safety.unwrap_or(r),
910910
}
911-
912-
if all_phantom { FfiPhantom(ty) } else { FfiSafe }
913911
}
912+
913+
if all_phantom { FfiPhantom(ty) } else { transparent_safety.unwrap_or(FfiSafe) }
914914
}
915915

916916
/// Checks if the given type is "ffi-safe" (has a stable, well-defined
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// This is a regression test for issue https://github.com/rust-lang/rust/issues/106629.
2+
// It ensures that transparent types where all fields are PhantomData are marked as
3+
// FFI-safe.
4+
5+
// check-pass
6+
7+
#[repr(transparent)]
8+
#[derive(Copy, Clone)]
9+
struct MyPhantom(core::marker::PhantomData<u8>);
10+
11+
#[repr(C)]
12+
#[derive(Copy, Clone)]
13+
pub struct Bar {
14+
pub x: i32,
15+
_marker: MyPhantom,
16+
}
17+
18+
extern "C" {
19+
pub fn foo(bar: *mut Bar);
20+
}
21+
22+
fn main() {}

0 commit comments

Comments
 (0)