Skip to content

Commit 335c960

Browse files
committed
Provide C FFI types via core::ffi, not just in std
The ability to interoperate with C code via FFI is not limited to crates using std; this allows using these types without std. The existing types in `std::os::raw` become type aliases for the ones in `core::ffi`. This uses type aliases rather than re-exports, to allow the std types to remain stable while the core types are unstable. This also moves the currently unstable `NonZero_` variants and `c_size_t`/`c_ssize_t`/`c_ptrdiff_t` types to `core::ffi`, while leaving them unstable.
1 parent 0f505c6 commit 335c960

22 files changed

+189
-166
lines changed
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.

library/core/src/ffi/c_void.md

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
Equivalent to C's `void` type when used as a [pointer].
2+
3+
In essence, `*const c_void` is equivalent to C's `const void*`
4+
and `*mut c_void` is equivalent to C's `void*`. That said, this is
5+
*not* the same as C's `void` return type, which is Rust's `()` type.
6+
7+
To model pointers to opaque types in FFI, until `extern type` is
8+
stabilized, it is recommended to use a newtype wrapper around an empty
9+
byte array. See the [Nomicon] for details.
10+
11+
One could use `std::os::raw::c_void` if they want to support old Rust
12+
compiler down to 1.1.0. After Rust 1.30.0, it was re-exported by
13+
this definition. For more information, please read [RFC 2521].
14+
15+
[Nomicon]: https://doc.rust-lang.org/nomicon/ffi.html#representing-opaque-structs
16+
[RFC 2521]: https://github.com/rust-lang/rfcs/blob/master/text/2521-c_void-reunification.md

library/core/src/ffi.rs renamed to library/core/src/ffi/mod.rs

+145-15
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,157 @@
1+
//! Platform-specific types, as defined by C.
2+
//!
3+
//! Code that interacts via FFI will almost certainly be using the
4+
//! base types provided by C, which aren't nearly as nicely defined
5+
//! as Rust's primitive types. This module provides types which will
6+
//! match those defined by C, so that code that interacts with C will
7+
//! refer to the correct types.
8+
19
#![stable(feature = "", since = "1.30.0")]
210
#![allow(non_camel_case_types)]
311

4-
//! Utilities related to foreign function interface (FFI) bindings.
5-
612
use crate::fmt;
713
use crate::marker::PhantomData;
14+
use crate::num::*;
815
use crate::ops::{Deref, DerefMut};
916

10-
/// Equivalent to C's `void` type when used as a [pointer].
11-
///
12-
/// In essence, `*const c_void` is equivalent to C's `const void*`
13-
/// and `*mut c_void` is equivalent to C's `void*`. That said, this is
14-
/// *not* the same as C's `void` return type, which is Rust's `()` type.
17+
macro_rules! type_alias_no_nz {
18+
{
19+
$Docfile:tt, $Alias:ident = $Real:ty;
20+
$( $Cfg:tt )*
21+
} => {
22+
#[doc = include_str!($Docfile)]
23+
$( $Cfg )*
24+
#[unstable(feature = "core_ffi_c", issue = "94501")]
25+
pub type $Alias = $Real;
26+
}
27+
}
28+
29+
// To verify that the NonZero types in this file's macro invocations correspond
30+
//
31+
// perl -n < library/std/src/os/raw/mod.rs -e 'next unless m/type_alias\!/; die "$_ ?" unless m/, (c_\w+) = (\w+), NonZero_(\w+) = NonZero(\w+)/; die "$_ ?" unless $3 eq $1 and $4 eq ucfirst $2'
32+
//
33+
// NB this does not check that the main c_* types are right.
34+
35+
macro_rules! type_alias {
36+
{
37+
$Docfile:tt, $Alias:ident = $Real:ty, $NZAlias:ident = $NZReal:ty;
38+
$( $Cfg:tt )*
39+
} => {
40+
type_alias_no_nz! { $Docfile, $Alias = $Real; $( $Cfg )* }
41+
42+
#[doc = concat!("Type alias for `NonZero` version of [`", stringify!($Alias), "`]")]
43+
#[unstable(feature = "raw_os_nonzero", issue = "82363")]
44+
$( $Cfg )*
45+
pub type $NZAlias = $NZReal;
46+
}
47+
}
48+
49+
type_alias! { "c_char.md", c_char = c_char_definition::c_char, NonZero_c_char = c_char_definition::NonZero_c_char;
50+
// Make this type alias appear cfg-dependent so that Clippy does not suggest
51+
// replacing `0 as c_char` with `0_i8`/`0_u8`. This #[cfg(all())] can be removed
52+
// after the false positive in https://github.com/rust-lang/rust-clippy/issues/8093
53+
// is fixed.
54+
#[cfg(all())]
55+
#[doc(cfg(all()))] }
56+
type_alias! { "c_schar.md", c_schar = i8, NonZero_c_schar = NonZeroI8; }
57+
type_alias! { "c_uchar.md", c_uchar = u8, NonZero_c_uchar = NonZeroU8; }
58+
type_alias! { "c_short.md", c_short = i16, NonZero_c_short = NonZeroI16; }
59+
type_alias! { "c_ushort.md", c_ushort = u16, NonZero_c_ushort = NonZeroU16; }
60+
type_alias! { "c_int.md", c_int = i32, NonZero_c_int = NonZeroI32; }
61+
type_alias! { "c_uint.md", c_uint = u32, NonZero_c_uint = NonZeroU32; }
62+
type_alias! { "c_long.md", c_long = i32, NonZero_c_long = NonZeroI32;
63+
#[doc(cfg(all()))]
64+
#[cfg(any(target_pointer_width = "32", windows))] }
65+
type_alias! { "c_ulong.md", c_ulong = u32, NonZero_c_ulong = NonZeroU32;
66+
#[doc(cfg(all()))]
67+
#[cfg(any(target_pointer_width = "32", windows))] }
68+
type_alias! { "c_long.md", c_long = i64, NonZero_c_long = NonZeroI64;
69+
#[doc(cfg(all()))]
70+
#[cfg(all(target_pointer_width = "64", not(windows)))] }
71+
type_alias! { "c_ulong.md", c_ulong = u64, NonZero_c_ulong = NonZeroU64;
72+
#[doc(cfg(all()))]
73+
#[cfg(all(target_pointer_width = "64", not(windows)))] }
74+
type_alias! { "c_longlong.md", c_longlong = i64, NonZero_c_longlong = NonZeroI64; }
75+
type_alias! { "c_ulonglong.md", c_ulonglong = u64, NonZero_c_ulonglong = NonZeroU64; }
76+
type_alias_no_nz! { "c_float.md", c_float = f32; }
77+
type_alias_no_nz! { "c_double.md", c_double = f64; }
78+
79+
/// Equivalent to C's `size_t` type, from `stddef.h` (or `cstddef` for C++).
1580
///
16-
/// To model pointers to opaque types in FFI, until `extern type` is
17-
/// stabilized, it is recommended to use a newtype wrapper around an empty
18-
/// byte array. See the [Nomicon] for details.
81+
/// This type is currently always [`usize`], however in the future there may be
82+
/// platforms where this is not the case.
83+
#[unstable(feature = "c_size_t", issue = "88345")]
84+
pub type c_size_t = usize;
85+
86+
/// Equivalent to C's `ptrdiff_t` type, from `stddef.h` (or `cstddef` for C++).
1987
///
20-
/// One could use `std::os::raw::c_void` if they want to support old Rust
21-
/// compiler down to 1.1.0. After Rust 1.30.0, it was re-exported by
22-
/// this definition. For more information, please read [RFC 2521].
88+
/// This type is currently always [`isize`], however in the future there may be
89+
/// platforms where this is not the case.
90+
#[unstable(feature = "c_size_t", issue = "88345")]
91+
pub type c_ptrdiff_t = isize;
92+
93+
/// Equivalent to C's `ssize_t` (on POSIX) or `SSIZE_T` (on Windows) type.
2394
///
24-
/// [Nomicon]: https://doc.rust-lang.org/nomicon/ffi.html#representing-opaque-structs
25-
/// [RFC 2521]: https://github.com/rust-lang/rfcs/blob/master/text/2521-c_void-reunification.md
95+
/// This type is currently always [`isize`], however in the future there may be
96+
/// platforms where this is not the case.
97+
#[unstable(feature = "c_size_t", issue = "88345")]
98+
pub type c_ssize_t = isize;
99+
100+
mod c_char_definition {
101+
cfg_if! {
102+
// These are the targets on which c_char is unsigned.
103+
if #[cfg(any(
104+
all(
105+
target_os = "linux",
106+
any(
107+
target_arch = "aarch64",
108+
target_arch = "arm",
109+
target_arch = "hexagon",
110+
target_arch = "powerpc",
111+
target_arch = "powerpc64",
112+
target_arch = "s390x",
113+
target_arch = "riscv64",
114+
target_arch = "riscv32"
115+
)
116+
),
117+
all(target_os = "android", any(target_arch = "aarch64", target_arch = "arm")),
118+
all(target_os = "l4re", target_arch = "x86_64"),
119+
all(
120+
target_os = "freebsd",
121+
any(
122+
target_arch = "aarch64",
123+
target_arch = "arm",
124+
target_arch = "powerpc",
125+
target_arch = "powerpc64",
126+
target_arch = "riscv64"
127+
)
128+
),
129+
all(
130+
target_os = "netbsd",
131+
any(target_arch = "aarch64", target_arch = "arm", target_arch = "powerpc")
132+
),
133+
all(target_os = "openbsd", target_arch = "aarch64"),
134+
all(
135+
target_os = "vxworks",
136+
any(
137+
target_arch = "aarch64",
138+
target_arch = "arm",
139+
target_arch = "powerpc64",
140+
target_arch = "powerpc"
141+
)
142+
),
143+
all(target_os = "fuchsia", target_arch = "aarch64")
144+
))] {
145+
pub type c_char = u8;
146+
pub type NonZero_c_char = crate::num::NonZeroU8;
147+
} else {
148+
// On every other target, c_char is signed.
149+
pub type c_char = i8;
150+
pub type NonZero_c_char = crate::num::NonZeroI8;
151+
}
152+
}
153+
}
154+
26155
// N.B., for LLVM to recognize the void pointer type and by extension
27156
// functions like malloc(), we need to have it represented as i8* in
28157
// LLVM bitcode. The enum used here ensures this and prevents misuse
@@ -31,6 +160,7 @@ use crate::ops::{Deref, DerefMut};
31160
// otherwise and we need at least one variant as otherwise the enum
32161
// would be uninhabited and at least dereferencing such pointers would
33162
// be UB.
163+
#[doc = include_str!("c_void.md")]
34164
#[repr(u8)]
35165
#[stable(feature = "core_c_void", since = "1.30.0")]
36166
pub enum c_void {

library/std/src/lib.rs

+2
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,7 @@
261261
#![feature(const_socketaddr)]
262262
#![feature(const_trait_impl)]
263263
#![feature(container_error_extra)]
264+
#![feature(core_ffi_c)]
264265
#![feature(core_intrinsics)]
265266
#![feature(core_panic)]
266267
#![feature(custom_test_frameworks)]
@@ -315,6 +316,7 @@
315316
#![feature(prelude_import)]
316317
#![feature(ptr_as_uninit)]
317318
#![feature(ptr_internals)]
319+
#![feature(raw_os_nonzero)]
318320
#![feature(rustc_attrs)]
319321
#![feature(rustc_private)]
320322
#![feature(saturating_int_impl)]

library/std/src/os/raw/mod.rs

+21-146
Original file line numberDiff line numberDiff line change
@@ -1,156 +1,31 @@
1-
//! Platform-specific types, as defined by C.
2-
//!
3-
//! Code that interacts via FFI will almost certainly be using the
4-
//! base types provided by C, which aren't nearly as nicely defined
5-
//! as Rust's primitive types. This module provides types which will
6-
//! match those defined by C, so that code that interacts with C will
7-
//! refer to the correct types.
1+
//! Compatibility module for C platform-specific types. Use [`core::ffi`] instead.
82
93
#![stable(feature = "raw_os", since = "1.1.0")]
104

115
#[cfg(test)]
126
mod tests;
137

14-
use core::num::*;
15-
16-
macro_rules! type_alias_no_nz {
17-
{
18-
$Docfile:tt, $Alias:ident = $Real:ty;
19-
$( $Cfg:tt )*
20-
} => {
21-
#[doc = include_str!($Docfile)]
22-
$( $Cfg )*
8+
macro_rules! alias_core_ffi {
9+
($($t:ident)*) => {$(
2310
#[stable(feature = "raw_os", since = "1.1.0")]
24-
pub type $Alias = $Real;
25-
}
26-
}
27-
28-
// To verify that the NonZero types in this file's macro invocations correspond
29-
//
30-
// perl -n < library/std/src/os/raw/mod.rs -e 'next unless m/type_alias\!/; die "$_ ?" unless m/, (c_\w+) = (\w+), NonZero_(\w+) = NonZero(\w+)/; die "$_ ?" unless $3 eq $1 and $4 eq ucfirst $2'
31-
//
32-
// NB this does not check that the main c_* types are right.
33-
34-
macro_rules! type_alias {
35-
{
36-
$Docfile:tt, $Alias:ident = $Real:ty, $NZAlias:ident = $NZReal:ty;
37-
$( $Cfg:tt )*
38-
} => {
39-
type_alias_no_nz! { $Docfile, $Alias = $Real; $( $Cfg )* }
40-
41-
#[doc = concat!("Type alias for `NonZero` version of [`", stringify!($Alias), "`]")]
42-
#[unstable(feature = "raw_os_nonzero", issue = "82363")]
43-
$( $Cfg )*
44-
pub type $NZAlias = $NZReal;
45-
}
11+
#[doc = include_str!(concat!("../../../../core/src/ffi/", stringify!($t), ".md"))]
12+
// Make this type alias appear cfg-dependent so that Clippy does not suggest
13+
// replacing expressions like `0 as c_char` with `0_i8`/`0_u8`. This #[cfg(all())] can be
14+
// removed after the false positive in https://github.com/rust-lang/rust-clippy/issues/8093
15+
// is fixed.
16+
#[cfg(all())]
17+
#[doc(cfg(all()))]
18+
pub type $t = core::ffi::$t;
19+
)*}
4620
}
4721

48-
type_alias! { "char.md", c_char = c_char_definition::c_char, NonZero_c_char = c_char_definition::NonZero_c_char;
49-
// Make this type alias appear cfg-dependent so that Clippy does not suggest
50-
// replacing `0 as c_char` with `0_i8`/`0_u8`. This #[cfg(all())] can be removed
51-
// after the false positive in https://github.com/rust-lang/rust-clippy/issues/8093
52-
// is fixed.
53-
#[cfg(all())]
54-
#[doc(cfg(all()))] }
55-
type_alias! { "schar.md", c_schar = i8, NonZero_c_schar = NonZeroI8; }
56-
type_alias! { "uchar.md", c_uchar = u8, NonZero_c_uchar = NonZeroU8; }
57-
type_alias! { "short.md", c_short = i16, NonZero_c_short = NonZeroI16; }
58-
type_alias! { "ushort.md", c_ushort = u16, NonZero_c_ushort = NonZeroU16; }
59-
type_alias! { "int.md", c_int = i32, NonZero_c_int = NonZeroI32; }
60-
type_alias! { "uint.md", c_uint = u32, NonZero_c_uint = NonZeroU32; }
61-
type_alias! { "long.md", c_long = i32, NonZero_c_long = NonZeroI32;
62-
#[doc(cfg(all()))]
63-
#[cfg(any(target_pointer_width = "32", windows))] }
64-
type_alias! { "ulong.md", c_ulong = u32, NonZero_c_ulong = NonZeroU32;
65-
#[doc(cfg(all()))]
66-
#[cfg(any(target_pointer_width = "32", windows))] }
67-
type_alias! { "long.md", c_long = i64, NonZero_c_long = NonZeroI64;
68-
#[doc(cfg(all()))]
69-
#[cfg(all(target_pointer_width = "64", not(windows)))] }
70-
type_alias! { "ulong.md", c_ulong = u64, NonZero_c_ulong = NonZeroU64;
71-
#[doc(cfg(all()))]
72-
#[cfg(all(target_pointer_width = "64", not(windows)))] }
73-
type_alias! { "longlong.md", c_longlong = i64, NonZero_c_longlong = NonZeroI64; }
74-
type_alias! { "ulonglong.md", c_ulonglong = u64, NonZero_c_ulonglong = NonZeroU64; }
75-
type_alias_no_nz! { "float.md", c_float = f32; }
76-
type_alias_no_nz! { "double.md", c_double = f64; }
77-
78-
#[stable(feature = "raw_os", since = "1.1.0")]
79-
#[doc(no_inline)]
80-
pub use core::ffi::c_void;
81-
82-
/// Equivalent to C's `size_t` type, from `stddef.h` (or `cstddef` for C++).
83-
///
84-
/// This type is currently always [`usize`], however in the future there may be
85-
/// platforms where this is not the case.
86-
#[unstable(feature = "c_size_t", issue = "88345")]
87-
pub type c_size_t = usize;
88-
89-
/// Equivalent to C's `ptrdiff_t` type, from `stddef.h` (or `cstddef` for C++).
90-
///
91-
/// This type is currently always [`isize`], however in the future there may be
92-
/// platforms where this is not the case.
93-
#[unstable(feature = "c_size_t", issue = "88345")]
94-
pub type c_ptrdiff_t = isize;
95-
96-
/// Equivalent to C's `ssize_t` (on POSIX) or `SSIZE_T` (on Windows) type.
97-
///
98-
/// This type is currently always [`isize`], however in the future there may be
99-
/// platforms where this is not the case.
100-
#[unstable(feature = "c_size_t", issue = "88345")]
101-
pub type c_ssize_t = isize;
102-
103-
mod c_char_definition {
104-
cfg_if::cfg_if! {
105-
// These are the targets on which c_char is unsigned.
106-
if #[cfg(any(
107-
all(
108-
target_os = "linux",
109-
any(
110-
target_arch = "aarch64",
111-
target_arch = "arm",
112-
target_arch = "hexagon",
113-
target_arch = "powerpc",
114-
target_arch = "powerpc64",
115-
target_arch = "s390x",
116-
target_arch = "riscv64",
117-
target_arch = "riscv32"
118-
)
119-
),
120-
all(target_os = "android", any(target_arch = "aarch64", target_arch = "arm")),
121-
all(target_os = "l4re", target_arch = "x86_64"),
122-
all(
123-
target_os = "freebsd",
124-
any(
125-
target_arch = "aarch64",
126-
target_arch = "arm",
127-
target_arch = "powerpc",
128-
target_arch = "powerpc64",
129-
target_arch = "riscv64"
130-
)
131-
),
132-
all(
133-
target_os = "netbsd",
134-
any(target_arch = "aarch64", target_arch = "arm", target_arch = "powerpc")
135-
),
136-
all(target_os = "openbsd", target_arch = "aarch64"),
137-
all(
138-
target_os = "vxworks",
139-
any(
140-
target_arch = "aarch64",
141-
target_arch = "arm",
142-
target_arch = "powerpc64",
143-
target_arch = "powerpc"
144-
)
145-
),
146-
all(target_os = "fuchsia", target_arch = "aarch64")
147-
))] {
148-
pub type c_char = u8;
149-
pub type NonZero_c_char = core::num::NonZeroU8;
150-
} else {
151-
// On every other target, c_char is signed.
152-
pub type c_char = i8;
153-
pub type NonZero_c_char = core::num::NonZeroI8;
154-
}
155-
}
22+
alias_core_ffi! {
23+
c_char c_schar c_uchar
24+
c_short c_ushort
25+
c_int c_uint
26+
c_long c_ulong
27+
c_longlong c_ulonglong
28+
c_float
29+
c_double
30+
c_void
15631
}

0 commit comments

Comments
 (0)