Skip to content

Commit a941112

Browse files
committed
ImproperCTypes: change handling of indirections
- Uniformise how indirections (references, Boxes, raw pointers) are handled. (more specific indirection types with specific guarantees are not handled yet) - Indirections that are compiled to a "thick pointer" (indirections to slices, dyn objects, *not* foreign !Sized types) have better messaging around them. - Now, the pointee of a FFI-safe indirection is always considered safe. This might be a regression, if we consider that an extern function's API should describe how the function can be used by the non-defining side of the FFI boundary. However, enforcing this everywhere would force the user to perform an unreasonable amount of typecasts to/from opaque pointers. There is something better to do here, but it will be left to another PR.
1 parent b80c5ae commit a941112

File tree

10 files changed

+326
-215
lines changed

10 files changed

+326
-215
lines changed

compiler/rustc_lint/messages.ftl

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -357,7 +357,6 @@ lint_improper_ctypes = {$desc} uses type `{$ty}`, which is not FFI-safe
357357
lint_improper_ctypes_array_help = consider passing a pointer to the array
358358
359359
lint_improper_ctypes_array_reason = passing raw arrays by value is not FFI-safe
360-
lint_improper_ctypes_box = box cannot be represented as a single pointer
361360
362361
lint_improper_ctypes_char_help = consider using `u32` or `libc::wchar_t` instead
363362

compiler/rustc_lint/src/types/improper_ctypes.rs

Lines changed: 176 additions & 57 deletions
Large diffs are not rendered by default.

tests/ui/lint/extern-C-fnptr-lints-slices.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
// It's an improper ctype (a slice) arg in an extern "C" fnptr.
44

55
pub type F = extern "C" fn(&[u8]);
6-
//~^ ERROR: `extern` callback uses type `[u8]`, which is not FFI-safe
6+
//~^ ERROR: `extern` callback uses type `&[u8]`, which is not FFI-safe
77

88

99
fn main() {}

tests/ui/lint/extern-C-fnptr-lints-slices.stderr

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
1-
error: `extern` callback uses type `[u8]`, which is not FFI-safe
1+
error: `extern` callback uses type `&[u8]`, which is not FFI-safe
22
--> $DIR/extern-C-fnptr-lints-slices.rs:5:14
33
|
44
LL | pub type F = extern "C" fn(&[u8]);
55
| ^^^^^^^^^^^^^^^^^^^^ not FFI-safe
66
|
7-
= help: consider using a raw pointer instead
8-
= note: slices have no C equivalent
7+
= note: the function pointer to `for<'a> extern "C" fn(&'a [u8])` is FFI-unsafe due to `&[u8]`
8+
= help: consider using a raw pointer to the slice's first element (and a length) instead
9+
= note: this reference to an unsized type contains metadata, which makes it incompatible with a C pointer
910
note: the lint level is defined here
1011
--> $DIR/extern-C-fnptr-lints-slices.rs:1:8
1112
|

tests/ui/lint/improper_ctypes/lint-73249-2.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
//@ check-pass // possible FIXME: see below
2+
13
#![feature(type_alias_impl_trait)]
24
#![deny(improper_ctypes)]
35

@@ -24,7 +26,8 @@ struct A<T: Foo> {
2426
}
2527

2628
extern "C" {
27-
fn lint_me() -> A<()>; //~ ERROR: uses type `Qux`
29+
// possible FIXME(ctypes): the unsafety of Qux is unseen, as it is behing a FFI-safe indirection
30+
fn lint_me() -> A<()>;
2831
}
2932

3033
fn main() {}

tests/ui/lint/improper_ctypes/lint-73249-2.stderr

Lines changed: 0 additions & 15 deletions
This file was deleted.

tests/ui/lint/improper_ctypes/lint-ctypes.rs

Lines changed: 36 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,16 @@
11
#![feature(rustc_private)]
2+
#![feature(extern_types)]
23

34
#![allow(private_interfaces)]
4-
#![deny(improper_ctypes)]
5+
#![deny(improper_ctypes, improper_c_callbacks)]
6+
#![deny(improper_c_fn_definitions)]
57

68
use std::cell::UnsafeCell;
79
use std::marker::PhantomData;
810
use std::ffi::{c_int, c_uint};
11+
use std::fmt::Debug;
912

13+
unsafe extern "C" {type UnsizedOpaque;}
1014
trait Bar { }
1115
trait Mirror { type It: ?Sized; }
1216
impl<T: ?Sized> Mirror for T { type It = Self; }
@@ -20,15 +24,15 @@ pub type I32Pair = (i32, i32);
2024
#[repr(C)]
2125
pub struct ZeroSize;
2226
pub type RustFn = fn();
23-
pub type RustBadRet = extern "C" fn() -> Box<u32>;
27+
pub type RustBoxRet = extern "C" fn() -> Box<u32>;
2428
pub type CVoidRet = ();
2529
pub struct Foo;
2630
#[repr(transparent)]
2731
pub struct TransparentI128(i128);
2832
#[repr(transparent)]
2933
pub struct TransparentStr(&'static str);
3034
#[repr(transparent)]
31-
pub struct TransparentBadFn(RustBadRet);
35+
pub struct TransparentBoxFn(RustBoxRet);
3236
#[repr(transparent)]
3337
pub struct TransparentInt(u32);
3438
#[repr(transparent)]
@@ -39,21 +43,37 @@ pub struct TransparentLifetime<'a>(*const u8, PhantomData<&'a ()>);
3943
pub struct TransparentUnit<U>(f32, PhantomData<U>);
4044
#[repr(transparent)]
4145
pub struct TransparentCustomZst(i32, ZeroSize);
46+
#[repr(C)]
47+
pub struct UnsizedStructBecauseForeign {
48+
sized: u32,
49+
unszd: UnsizedOpaque,
50+
}
51+
#[repr(C)]
52+
pub struct UnsizedStructBecauseDyn {
53+
sized: u32,
54+
unszd: dyn Debug,
55+
}
56+
57+
#[repr(C)]
58+
pub struct TwoBadTypes<'a> {
59+
non_c_type: char,
60+
ref_with_mdata: &'a [u8],
61+
}
4262

4363
#[repr(C)]
4464
pub struct ZeroSizeWithPhantomData(::std::marker::PhantomData<i32>);
4565

4666
extern "C" {
47-
pub fn ptr_type1(size: *const Foo); //~ ERROR: uses type `Foo`
48-
pub fn ptr_type2(size: *const Foo); //~ ERROR: uses type `Foo`
67+
pub fn ptr_type1(size: *const Foo);
68+
pub fn ptr_type2(size: *const Foo);
4969
pub fn ptr_unit(p: *const ());
50-
pub fn ptr_tuple(p: *const ((),)); //~ ERROR: uses type `((),)`
51-
pub fn slice_type(p: &[u32]); //~ ERROR: uses type `[u32]`
52-
pub fn str_type(p: &str); //~ ERROR: uses type `str`
53-
pub fn box_type(p: Box<u32>); //~ ERROR uses type `Box<u32>`
70+
pub fn ptr_tuple(p: *const ((),));
71+
pub fn slice_type(p: &[u32]); //~ ERROR: uses type `&[u32]`
72+
pub fn str_type(p: &str); //~ ERROR: uses type `&str`
73+
pub fn box_type(p: Box<u32>);
5474
pub fn opt_box_type(p: Option<Box<u32>>);
5575
pub fn char_type(p: char); //~ ERROR uses type `char`
56-
pub fn trait_type(p: &dyn Bar); //~ ERROR uses type `dyn Bar`
76+
pub fn trait_type(p: &dyn Bar); //~ ERROR uses type `&dyn Bar`
5777
pub fn tuple_type(p: (i32, i32)); //~ ERROR uses type `(i32, i32)`
5878
pub fn tuple_type2(p: I32Pair); //~ ERROR uses type `(i32, i32)`
5979
pub fn zero_size(p: ZeroSize); //~ ERROR uses type `ZeroSize`
@@ -63,11 +83,14 @@ extern "C" {
6383
-> ::std::marker::PhantomData<bool>; //~ ERROR uses type `PhantomData<bool>`
6484
pub fn fn_type(p: RustFn); //~ ERROR uses type `fn()`
6585
pub fn fn_type2(p: fn()); //~ ERROR uses type `fn()`
66-
pub fn fn_contained(p: RustBadRet); //~ ERROR: uses type `Box<u32>`
67-
pub fn transparent_str(p: TransparentStr); //~ ERROR: uses type `str`
68-
pub fn transparent_fn(p: TransparentBadFn); //~ ERROR: uses type `Box<u32>`
86+
pub fn fn_contained(p: RustBoxRet);
87+
pub fn transparent_str(p: TransparentStr); //~ ERROR: uses type `&str`
88+
pub fn transparent_fn(p: TransparentBoxFn);
6989
pub fn raw_array(arr: [u8; 8]); //~ ERROR: uses type `[u8; 8]`
7090

91+
pub fn struct_unsized_ptr_no_metadata(p: &UnsizedStructBecauseForeign);
92+
pub fn struct_unsized_ptr_has_metadata(p: &UnsizedStructBecauseDyn); //~ ERROR uses type `&UnsizedStructBecauseDyn`
93+
7194
pub fn no_niche_a(a: Option<UnsafeCell<extern "C" fn()>>);
7295
//~^ ERROR: uses type `Option<UnsafeCell<extern "C" fn()>>`
7396
pub fn no_niche_b(b: Option<UnsafeCell<&i32>>);

0 commit comments

Comments
 (0)