Mark ZST as FFI-safe if all its fields are PhantomData
Modify the linting behavior and add the corresponding regression test
This commit is contained in:
parent
2b8590ef3b
commit
797f247997
2 changed files with 45 additions and 23 deletions
|
@ -878,17 +878,18 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
|
||||||
) -> FfiResult<'tcx> {
|
) -> FfiResult<'tcx> {
|
||||||
use FfiResult::*;
|
use FfiResult::*;
|
||||||
|
|
||||||
if def.repr().transparent() {
|
let transparent_safety = def.repr().transparent().then(|| {
|
||||||
// Can assume that at most one field is not a ZST, so only check
|
// Can assume that at most one field is not a ZST, so only check
|
||||||
// that field's type for FFI-safety.
|
// that field's type for FFI-safety.
|
||||||
if let Some(field) = transparent_newtype_field(self.cx.tcx, variant) {
|
if let Some(field) = transparent_newtype_field(self.cx.tcx, variant) {
|
||||||
self.check_field_type_for_ffi(cache, field, substs)
|
return self.check_field_type_for_ffi(cache, field, substs);
|
||||||
} else {
|
} else {
|
||||||
// All fields are ZSTs; this means that the type should behave
|
// All fields are ZSTs; this means that the type should behave
|
||||||
// like (), which is FFI-unsafe
|
// like (), which is FFI-unsafe... except if all fields are PhantomData,
|
||||||
|
// which is tested for below
|
||||||
FfiUnsafe { ty, reason: fluent::lint_improper_ctypes_struct_zst, help: None }
|
FfiUnsafe { ty, reason: fluent::lint_improper_ctypes_struct_zst, help: None }
|
||||||
}
|
}
|
||||||
} else {
|
});
|
||||||
// We can't completely trust repr(C) markings; make sure the fields are
|
// We can't completely trust repr(C) markings; make sure the fields are
|
||||||
// actually safe.
|
// actually safe.
|
||||||
let mut all_phantom = !variant.fields.is_empty();
|
let mut all_phantom = !variant.fields.is_empty();
|
||||||
|
@ -897,7 +898,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
|
||||||
FfiSafe => {
|
FfiSafe => {
|
||||||
all_phantom = false;
|
all_phantom = false;
|
||||||
}
|
}
|
||||||
FfiPhantom(..) if def.is_enum() => {
|
FfiPhantom(..) if !def.repr().transparent() && def.is_enum() => {
|
||||||
return FfiUnsafe {
|
return FfiUnsafe {
|
||||||
ty,
|
ty,
|
||||||
reason: fluent::lint_improper_ctypes_enum_phantomdata,
|
reason: fluent::lint_improper_ctypes_enum_phantomdata,
|
||||||
|
@ -905,12 +906,11 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
FfiPhantom(..) => {}
|
FfiPhantom(..) => {}
|
||||||
r => return r,
|
r => return transparent_safety.unwrap_or(r),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if all_phantom { FfiPhantom(ty) } else { FfiSafe }
|
if all_phantom { FfiPhantom(ty) } else { transparent_safety.unwrap_or(FfiSafe) }
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Checks if the given type is "ffi-safe" (has a stable, well-defined
|
/// Checks if the given type is "ffi-safe" (has a stable, well-defined
|
||||||
|
|
22
tests/ui/lint/lint-ffi-safety-all-phantom.rs
Normal file
22
tests/ui/lint/lint-ffi-safety-all-phantom.rs
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
// This is a regression test for issue https://github.com/rust-lang/rust/issues/106629.
|
||||||
|
// It ensures that transparent types where all fields are PhantomData are marked as
|
||||||
|
// FFI-safe.
|
||||||
|
|
||||||
|
// check-pass
|
||||||
|
|
||||||
|
#[repr(transparent)]
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
|
struct MyPhantom(core::marker::PhantomData<u8>);
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
|
pub struct Bar {
|
||||||
|
pub x: i32,
|
||||||
|
_marker: MyPhantom,
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
pub fn foo(bar: *mut Bar);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
Loading…
Add table
Add a link
Reference in a new issue