lint: fix ImproperCTypes edge case for unsized structs due to foreign types
This commit is contained in:
parent
1d52131043
commit
7962a2de3a
3 changed files with 119 additions and 32 deletions
|
@ -740,6 +740,69 @@ enum FfiResult<'tcx> {
|
|||
},
|
||||
}
|
||||
|
||||
pub(crate) fn is_unsized_because_foreign<'tcx, 'a>(
|
||||
cx: &'a LateContext<'tcx>,
|
||||
ty: Ty<'tcx>,
|
||||
) -> Result<bool, ()> {
|
||||
let tcx = cx.tcx;
|
||||
|
||||
if ty.is_sized(tcx, cx.typing_env()) {
|
||||
Err(())
|
||||
} else {
|
||||
Ok(match ty.kind() {
|
||||
ty::Slice(_) => false,
|
||||
ty::Str => false,
|
||||
ty::Dynamic(..) => false,
|
||||
ty::Foreign(..) => true,
|
||||
ty::Alias(ty::Opaque, ..) => todo!("why"),
|
||||
ty::Adt(def, args) => {
|
||||
// for now assume: boxes and phantoms don't mess with this
|
||||
match def.adt_kind() {
|
||||
AdtKind::Union | AdtKind::Enum => true,
|
||||
AdtKind::Struct => {
|
||||
if let Some(sym::cstring_type | sym::cstr_type) =
|
||||
tcx.get_diagnostic_name(def.did())
|
||||
{
|
||||
return Ok(false);
|
||||
}
|
||||
// FIXME: how do we deal with non-exhaustive unsized structs/unions?
|
||||
|
||||
if def.non_enum_variant().fields.is_empty() {
|
||||
bug!("empty unsized struct/union. what?");
|
||||
}
|
||||
|
||||
let variant = def.non_enum_variant();
|
||||
|
||||
// only the last field may be unsized
|
||||
let n_fields = variant.fields.len();
|
||||
let last_field = &variant.fields[(n_fields - 1).into()];
|
||||
let field_ty = last_field.ty(cx.tcx, args);
|
||||
let field_ty = cx
|
||||
.tcx
|
||||
.try_normalize_erasing_regions(cx.typing_env(), field_ty)
|
||||
.unwrap_or(field_ty);
|
||||
return Ok(is_unsized_because_foreign(cx, field_ty).unwrap());
|
||||
}
|
||||
}
|
||||
}
|
||||
ty::Tuple(tuple) => {
|
||||
// only the last field may be unsized
|
||||
let n_fields = tuple.len();
|
||||
let field_ty: Ty<'tcx> = tuple[n_fields - 1];
|
||||
//let field_ty = last_field.ty(cx.tcx, args);
|
||||
let field_ty = cx
|
||||
.tcx
|
||||
.try_normalize_erasing_regions(cx.typing_env(), field_ty)
|
||||
.unwrap_or(field_ty);
|
||||
is_unsized_because_foreign(cx, field_ty).unwrap()
|
||||
}
|
||||
t => {
|
||||
bug!("we shouldn't be looking if this is unsized for a reason or another: {:?}", t)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn nonnull_optimization_guaranteed<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
def: ty::AdtDef<'tcx>,
|
||||
|
@ -1044,7 +1107,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
|
|||
ty::Adt(def, args) => {
|
||||
if let Some(inner_ty) = ty.boxed_ty() {
|
||||
if inner_ty.is_sized(tcx, self.cx.typing_env())
|
||||
|| matches!(inner_ty.kind(), ty::Foreign(..))
|
||||
|| is_unsized_because_foreign(self.cx, inner_ty).unwrap()
|
||||
{
|
||||
// discussion on declaration vs definition:
|
||||
// see the `ty::RawPtr(inner_ty, _) | ty::Ref(_, inner_ty, _)` arm
|
||||
|
@ -1249,7 +1312,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
|
|||
|
||||
ty::RawPtr(inner_ty, _) | ty::Ref(_, inner_ty, _) => {
|
||||
if inner_ty.is_sized(tcx, self.cx.typing_env())
|
||||
|| matches!(inner_ty.kind(), ty::Foreign(..))
|
||||
|| is_unsized_because_foreign(self.cx, inner_ty).unwrap()
|
||||
{
|
||||
// there's a nuance on what this lint should do for function definitions
|
||||
// (touched upon in https://github.com/rust-lang/rust/issues/66220 and https://github.com/rust-lang/rust/pull/72700)
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#![feature(rustc_private)]
|
||||
#![feature(extern_types)]
|
||||
|
||||
#![allow(private_interfaces)]
|
||||
#![deny(improper_ctypes)]
|
||||
|
@ -6,7 +7,9 @@
|
|||
use std::cell::UnsafeCell;
|
||||
use std::marker::PhantomData;
|
||||
use std::ffi::{c_int, c_uint};
|
||||
use std::fmt::Debug;
|
||||
|
||||
unsafe extern "C" {type UnsizedOpaque;}
|
||||
trait Bar { }
|
||||
trait Mirror { type It: ?Sized; }
|
||||
impl<T: ?Sized> Mirror for T { type It = Self; }
|
||||
|
@ -39,6 +42,16 @@ pub struct TransparentLifetime<'a>(*const u8, PhantomData<&'a ()>);
|
|||
pub struct TransparentUnit<U>(f32, PhantomData<U>);
|
||||
#[repr(transparent)]
|
||||
pub struct TransparentCustomZst(i32, ZeroSize);
|
||||
#[repr(C)]
|
||||
pub struct UnsizedStructBecauseForeign {
|
||||
sized: u32,
|
||||
unszd: UnsizedOpaque,
|
||||
}
|
||||
#[repr(C)]
|
||||
pub struct UnsizedStructBecauseDyn {
|
||||
sized: u32,
|
||||
unszd: dyn Debug,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct ZeroSizeWithPhantomData(::std::marker::PhantomData<i32>);
|
||||
|
@ -72,6 +85,9 @@ extern "C" {
|
|||
pub fn transparent_fn(p: TransparentBadFn); //~ ERROR: uses type `Box<u32>`
|
||||
pub fn raw_array(arr: [u8; 8]); //~ ERROR: uses type `[u8; 8]`
|
||||
|
||||
pub fn struct_unsized_ptr_no_metadata(p: &UnsizedStructBecauseForeign);
|
||||
pub fn struct_unsized_ptr_has_metadata(p: &UnsizedStructBecauseDyn); //~ ERROR uses type `&UnsizedStructBecauseDyn`
|
||||
|
||||
pub fn no_niche_a(a: Option<UnsafeCell<extern fn()>>);
|
||||
//~^ ERROR: uses type `Option<UnsafeCell<extern "C" fn()>>`
|
||||
pub fn no_niche_b(b: Option<UnsafeCell<&i32>>);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
error: `extern` block uses type `Foo`, which is not FFI-safe
|
||||
--> $DIR/lint-ctypes.rs:47:28
|
||||
--> $DIR/lint-ctypes.rs:60:28
|
||||
|
|
||||
LL | pub fn ptr_type1(size: *const Foo);
|
||||
| ^^^^^^^^^^ not FFI-safe
|
||||
|
@ -8,18 +8,18 @@ LL | pub fn ptr_type1(size: *const Foo);
|
|||
= help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
|
||||
= note: this struct has unspecified layout
|
||||
note: the type is defined here
|
||||
--> $DIR/lint-ctypes.rs:25:1
|
||||
--> $DIR/lint-ctypes.rs:28:1
|
||||
|
|
||||
LL | pub struct Foo;
|
||||
| ^^^^^^^^^^^^^^
|
||||
note: the lint level is defined here
|
||||
--> $DIR/lint-ctypes.rs:4:9
|
||||
--> $DIR/lint-ctypes.rs:5:9
|
||||
|
|
||||
LL | #![deny(improper_ctypes)]
|
||||
| ^^^^^^^^^^^^^^^
|
||||
|
||||
error: `extern` block uses type `Foo`, which is not FFI-safe
|
||||
--> $DIR/lint-ctypes.rs:48:28
|
||||
--> $DIR/lint-ctypes.rs:61:28
|
||||
|
|
||||
LL | pub fn ptr_type2(size: *const Foo);
|
||||
| ^^^^^^^^^^ not FFI-safe
|
||||
|
@ -28,13 +28,13 @@ LL | pub fn ptr_type2(size: *const Foo);
|
|||
= help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
|
||||
= note: this struct has unspecified layout
|
||||
note: the type is defined here
|
||||
--> $DIR/lint-ctypes.rs:25:1
|
||||
--> $DIR/lint-ctypes.rs:28:1
|
||||
|
|
||||
LL | pub struct Foo;
|
||||
| ^^^^^^^^^^^^^^
|
||||
|
||||
error: `extern` block uses type `((),)`, which is not FFI-safe
|
||||
--> $DIR/lint-ctypes.rs:50:25
|
||||
--> $DIR/lint-ctypes.rs:63:25
|
||||
|
|
||||
LL | pub fn ptr_tuple(p: *const ((),));
|
||||
| ^^^^^^^^^^^^ not FFI-safe
|
||||
|
@ -44,7 +44,7 @@ LL | pub fn ptr_tuple(p: *const ((),));
|
|||
= note: tuples have unspecified layout
|
||||
|
||||
error: `extern` block uses type `&[u32]`, which is not FFI-safe
|
||||
--> $DIR/lint-ctypes.rs:51:26
|
||||
--> $DIR/lint-ctypes.rs:64:26
|
||||
|
|
||||
LL | pub fn slice_type(p: &[u32]);
|
||||
| ^^^^^^ not FFI-safe
|
||||
|
@ -53,7 +53,7 @@ LL | pub fn slice_type(p: &[u32]);
|
|||
= note: this reference to an unsized rust type contains metadata, which makes it incompatible with a C pointer
|
||||
|
||||
error: `extern` block uses type `&str`, which is not FFI-safe
|
||||
--> $DIR/lint-ctypes.rs:52:24
|
||||
--> $DIR/lint-ctypes.rs:65:24
|
||||
|
|
||||
LL | pub fn str_type(p: &str);
|
||||
| ^^^^ not FFI-safe
|
||||
|
@ -71,7 +71,7 @@ LL | pub fn box_type(p: Box<u32>);
|
|||
= note: this struct has unspecified layout
|
||||
|
||||
error: `extern` block uses type `Option<Box<u32>>`, which is not FFI-safe
|
||||
--> $DIR/lint-ctypes.rs:54:28
|
||||
--> $DIR/lint-ctypes.rs:67:28
|
||||
|
|
||||
LL | pub fn opt_box_type(p: Option<Box<u32>>);
|
||||
| ^^^^^^^^^^^^^^^^ not FFI-safe
|
||||
|
@ -80,7 +80,7 @@ LL | pub fn opt_box_type(p: Option<Box<u32>>);
|
|||
= note: enum has no representation hint
|
||||
|
||||
error: `extern` block uses type `char`, which is not FFI-safe
|
||||
--> $DIR/lint-ctypes.rs:56:25
|
||||
--> $DIR/lint-ctypes.rs:69:25
|
||||
|
|
||||
LL | pub fn char_type(p: char);
|
||||
| ^^^^ not FFI-safe
|
||||
|
@ -89,7 +89,7 @@ LL | pub fn char_type(p: char);
|
|||
= note: the `char` type has no C equivalent
|
||||
|
||||
error: `extern` block uses type `i128`, which is not FFI-safe
|
||||
--> $DIR/lint-ctypes.rs:57:25
|
||||
--> $DIR/lint-ctypes.rs:70:25
|
||||
|
|
||||
LL | pub fn i128_type(p: i128);
|
||||
| ^^^^ not FFI-safe
|
||||
|
@ -97,7 +97,7 @@ LL | pub fn i128_type(p: i128);
|
|||
= note: 128-bit integers don't currently have a known stable ABI
|
||||
|
||||
error: `extern` block uses type `u128`, which is not FFI-safe
|
||||
--> $DIR/lint-ctypes.rs:58:25
|
||||
--> $DIR/lint-ctypes.rs:71:25
|
||||
|
|
||||
LL | pub fn u128_type(p: u128);
|
||||
| ^^^^ not FFI-safe
|
||||
|
@ -105,7 +105,7 @@ LL | pub fn u128_type(p: u128);
|
|||
= note: 128-bit integers don't currently have a known stable ABI
|
||||
|
||||
error: `extern` block uses type `&dyn Bar`, which is not FFI-safe
|
||||
--> $DIR/lint-ctypes.rs:59:26
|
||||
--> $DIR/lint-ctypes.rs:72:26
|
||||
|
|
||||
LL | pub fn trait_type(p: &dyn Bar);
|
||||
| ^^^^^^^^ not FFI-safe
|
||||
|
@ -113,7 +113,7 @@ LL | pub fn trait_type(p: &dyn Bar);
|
|||
= note: this reference to an unsized rust type contains metadata, which makes it incompatible with a C pointer
|
||||
|
||||
error: `extern` block uses type `(i32, i32)`, which is not FFI-safe
|
||||
--> $DIR/lint-ctypes.rs:60:26
|
||||
--> $DIR/lint-ctypes.rs:73:26
|
||||
|
|
||||
LL | pub fn tuple_type(p: (i32, i32));
|
||||
| ^^^^^^^^^^ not FFI-safe
|
||||
|
@ -122,7 +122,7 @@ LL | pub fn tuple_type(p: (i32, i32));
|
|||
= note: tuples have unspecified layout
|
||||
|
||||
error: `extern` block uses type `(i32, i32)`, which is not FFI-safe
|
||||
--> $DIR/lint-ctypes.rs:61:27
|
||||
--> $DIR/lint-ctypes.rs:74:27
|
||||
|
|
||||
LL | pub fn tuple_type2(p: I32Pair);
|
||||
| ^^^^^^^ not FFI-safe
|
||||
|
@ -131,7 +131,7 @@ LL | pub fn tuple_type2(p: I32Pair);
|
|||
= note: tuples have unspecified layout
|
||||
|
||||
error: `extern` block uses type `ZeroSize`, which is not FFI-safe
|
||||
--> $DIR/lint-ctypes.rs:62:25
|
||||
--> $DIR/lint-ctypes.rs:75:25
|
||||
|
|
||||
LL | pub fn zero_size(p: ZeroSize);
|
||||
| ^^^^^^^^ not FFI-safe
|
||||
|
@ -139,26 +139,26 @@ LL | pub fn zero_size(p: ZeroSize);
|
|||
= help: consider adding a member to this struct
|
||||
= note: this struct has no fields
|
||||
note: the type is defined here
|
||||
--> $DIR/lint-ctypes.rs:21:1
|
||||
--> $DIR/lint-ctypes.rs:24:1
|
||||
|
|
||||
LL | pub struct ZeroSize;
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: `extern` block uses type `ZeroSizeWithPhantomData`, which is not FFI-safe
|
||||
--> $DIR/lint-ctypes.rs:63:33
|
||||
--> $DIR/lint-ctypes.rs:76:33
|
||||
|
|
||||
LL | pub fn zero_size_phantom(p: ZeroSizeWithPhantomData);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
|
||||
|
|
||||
= note: composed only of `PhantomData`
|
||||
note: the type is defined here
|
||||
--> $DIR/lint-ctypes.rs:44:1
|
||||
--> $DIR/lint-ctypes.rs:57:1
|
||||
|
|
||||
LL | pub struct ZeroSizeWithPhantomData(::std::marker::PhantomData<i32>);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: `extern` block uses type `PhantomData<bool>`, which is not FFI-safe
|
||||
--> $DIR/lint-ctypes.rs:66:12
|
||||
--> $DIR/lint-ctypes.rs:79:12
|
||||
|
|
||||
LL | -> ::std::marker::PhantomData<bool>;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
|
||||
|
@ -166,7 +166,7 @@ LL | -> ::std::marker::PhantomData<bool>;
|
|||
= note: composed only of `PhantomData`
|
||||
|
||||
error: `extern` block uses type `fn()`, which is not FFI-safe
|
||||
--> $DIR/lint-ctypes.rs:67:23
|
||||
--> $DIR/lint-ctypes.rs:80:23
|
||||
|
|
||||
LL | pub fn fn_type(p: RustFn);
|
||||
| ^^^^^^ not FFI-safe
|
||||
|
@ -175,7 +175,7 @@ LL | pub fn fn_type(p: RustFn);
|
|||
= note: this function pointer has Rust-specific calling convention
|
||||
|
||||
error: `extern` block uses type `fn()`, which is not FFI-safe
|
||||
--> $DIR/lint-ctypes.rs:68:24
|
||||
--> $DIR/lint-ctypes.rs:81:24
|
||||
|
|
||||
LL | pub fn fn_type2(p: fn());
|
||||
| ^^^^ not FFI-safe
|
||||
|
@ -193,7 +193,7 @@ LL | pub fn fn_contained(p: RustBadRet);
|
|||
= note: this struct has unspecified layout
|
||||
|
||||
error: `extern` block uses type `i128`, which is not FFI-safe
|
||||
--> $DIR/lint-ctypes.rs:70:32
|
||||
--> $DIR/lint-ctypes.rs:83:32
|
||||
|
|
||||
LL | pub fn transparent_i128(p: TransparentI128);
|
||||
| ^^^^^^^^^^^^^^^ not FFI-safe
|
||||
|
@ -201,7 +201,7 @@ LL | pub fn transparent_i128(p: TransparentI128);
|
|||
= note: 128-bit integers don't currently have a known stable ABI
|
||||
|
||||
error: `extern` block uses type `&str`, which is not FFI-safe
|
||||
--> $DIR/lint-ctypes.rs:71:31
|
||||
--> $DIR/lint-ctypes.rs:84:31
|
||||
|
|
||||
LL | pub fn transparent_str(p: TransparentStr);
|
||||
| ^^^^^^^^^^^^^^ not FFI-safe
|
||||
|
@ -219,7 +219,7 @@ LL | pub fn transparent_fn(p: TransparentBadFn);
|
|||
= note: this struct has unspecified layout
|
||||
|
||||
error: `extern` block uses type `[u8; 8]`, which is not FFI-safe
|
||||
--> $DIR/lint-ctypes.rs:73:27
|
||||
--> $DIR/lint-ctypes.rs:86:27
|
||||
|
|
||||
LL | pub fn raw_array(arr: [u8; 8]);
|
||||
| ^^^^^^^ not FFI-safe
|
||||
|
@ -227,8 +227,16 @@ LL | pub fn raw_array(arr: [u8; 8]);
|
|||
= help: consider passing a pointer to the array
|
||||
= note: passing raw arrays by value is not FFI-safe
|
||||
|
||||
error: `extern` block uses type `&UnsizedStructBecauseDyn`, which is not FFI-safe
|
||||
--> $DIR/lint-ctypes.rs:89:47
|
||||
|
|
||||
LL | pub fn struct_unsized_ptr_has_metadata(p: &UnsizedStructBecauseDyn);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
|
||||
|
|
||||
= note: this reference to an unsized rust type contains metadata, which makes it incompatible with a C pointer
|
||||
|
||||
error: `extern` block uses type `Option<UnsafeCell<extern "C" fn()>>`, which is not FFI-safe
|
||||
--> $DIR/lint-ctypes.rs:75:26
|
||||
--> $DIR/lint-ctypes.rs:91:26
|
||||
|
|
||||
LL | pub fn no_niche_a(a: Option<UnsafeCell<extern fn()>>);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
|
||||
|
@ -237,7 +245,7 @@ LL | pub fn no_niche_a(a: Option<UnsafeCell<extern fn()>>);
|
|||
= note: enum has no representation hint
|
||||
|
||||
error: `extern` block uses type `Option<UnsafeCell<&i32>>`, which is not FFI-safe
|
||||
--> $DIR/lint-ctypes.rs:77:26
|
||||
--> $DIR/lint-ctypes.rs:93:26
|
||||
|
|
||||
LL | pub fn no_niche_b(b: Option<UnsafeCell<&i32>>);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
|
||||
|
@ -246,7 +254,7 @@ LL | pub fn no_niche_b(b: Option<UnsafeCell<&i32>>);
|
|||
= note: enum has no representation hint
|
||||
|
||||
error: `extern` block uses type `u128`, which is not FFI-safe
|
||||
--> $DIR/lint-ctypes.rs:80:34
|
||||
--> $DIR/lint-ctypes.rs:96:34
|
||||
|
|
||||
LL | pub static static_u128_type: u128;
|
||||
| ^^^^ not FFI-safe
|
||||
|
@ -254,11 +262,11 @@ LL | pub static static_u128_type: u128;
|
|||
= note: 128-bit integers don't currently have a known stable ABI
|
||||
|
||||
error: `extern` block uses type `u128`, which is not FFI-safe
|
||||
--> $DIR/lint-ctypes.rs:81:40
|
||||
--> $DIR/lint-ctypes.rs:97:40
|
||||
|
|
||||
LL | pub static static_u128_array_type: [u128; 16];
|
||||
| ^^^^^^^^^^ not FFI-safe
|
||||
|
|
||||
= note: 128-bit integers don't currently have a known stable ABI
|
||||
|
||||
error: aborting due to 27 previous errors
|
||||
error: aborting due to 29 previous errors
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue