lint/ctypes: allow ()
within types
Consider `()` within types to be FFI-safe, and `()` to be FFI-safe as a return type (incl. when in a transparent newtype). Signed-off-by: David Wood <david@davidtw.co>
This commit is contained in:
parent
99b1897cf6
commit
24f90fdd26
7 changed files with 87 additions and 83 deletions
|
@ -943,30 +943,6 @@ pub(crate) fn repr_nullable_ptr<'tcx>(
|
|||
}
|
||||
|
||||
impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
|
||||
// Returns `true` if `ty` is a `()`, or a `repr(transparent)` type whose only non-ZST field
|
||||
// is a generic substituted for `()` - in either case, the type is FFI-safe when used as a
|
||||
// return type.
|
||||
pub fn is_unit_or_equivalent(&self, ty: Ty<'tcx>) -> bool {
|
||||
if ty.is_unit() {
|
||||
return true;
|
||||
}
|
||||
|
||||
if let ty::Adt(def, substs) = ty.kind() && def.repr().transparent() {
|
||||
return def.variants()
|
||||
.iter()
|
||||
.filter_map(|variant| transparent_newtype_field(self.cx.tcx, variant))
|
||||
.all(|field| {
|
||||
let field_ty = field.ty(self.cx.tcx, substs);
|
||||
!field_ty.has_opaque_types() && {
|
||||
let field_ty = self.cx.tcx.normalize_erasing_regions(self.cx.param_env, field_ty);
|
||||
self.is_unit_or_equivalent(field_ty)
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
/// Check if the type is array and emit an unsafe type lint.
|
||||
fn check_for_array_ty(&mut self, sp: Span, ty: Ty<'tcx>) -> bool {
|
||||
if let ty::Array(..) = ty.kind() {
|
||||
|
@ -1010,14 +986,19 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
|
|||
use FfiResult::*;
|
||||
|
||||
let transparent_with_all_zst_fields = if def.repr().transparent() {
|
||||
// Transparent newtypes have at most one non-ZST field which needs to be checked..
|
||||
if let Some(field) = transparent_newtype_field(self.cx.tcx, variant) {
|
||||
return self.check_field_type_for_ffi(cache, field, args);
|
||||
}
|
||||
// Transparent newtypes have at most one non-ZST field which needs to be checked..
|
||||
match self.check_field_type_for_ffi(cache, field, args) {
|
||||
FfiUnsafe { ty, .. } if ty.is_unit() => (),
|
||||
r => return r,
|
||||
}
|
||||
|
||||
// ..or have only ZST fields, which is FFI-unsafe (unless those fields are all
|
||||
// `PhantomData`).
|
||||
true
|
||||
false
|
||||
} else {
|
||||
// ..or have only ZST fields, which is FFI-unsafe (unless those fields are all
|
||||
// `PhantomData`).
|
||||
true
|
||||
}
|
||||
} else {
|
||||
false
|
||||
};
|
||||
|
@ -1027,6 +1008,8 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
|
|||
for field in &variant.fields {
|
||||
all_phantom &= match self.check_field_type_for_ffi(cache, &field, args) {
|
||||
FfiSafe => false,
|
||||
// `()` fields are FFI-safe!
|
||||
FfiUnsafe { ty, .. } if ty.is_unit() => false,
|
||||
FfiPhantom(..) => true,
|
||||
r @ FfiUnsafe { .. } => return r,
|
||||
}
|
||||
|
@ -1249,7 +1232,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
|
|||
}
|
||||
|
||||
let ret_ty = sig.output();
|
||||
if self.is_unit_or_equivalent(ret_ty) {
|
||||
if ret_ty.is_unit() {
|
||||
return FfiSafe;
|
||||
}
|
||||
|
||||
|
@ -1374,7 +1357,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
|
|||
// Don't report FFI errors for unit return types. This check exists here, and not in
|
||||
// the caller (where it would make more sense) so that normalization has definitely
|
||||
// happened.
|
||||
if is_return_type && self.is_unit_or_equivalent(ty) {
|
||||
if is_return_type && ty.is_unit() {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue