1 #![stable(feature = "", since = "1.30.0")]
2 #![allow(non_camel_case_types)]
4 //! Utilities related to FFI bindings.
7 use crate::marker
::PhantomData
;
8 use crate::ops
::{Deref, DerefMut}
;
10 /// Equivalent to C's `void` type when used as a [pointer].
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.
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.
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].
24 /// [pointer]: ../../std/primitive.pointer.html
25 /// [Nomicon]: https://doc.rust-lang.org/nomicon/ffi.html#representing-opaque-structs
26 /// [RFC 2521]: https://github.com/rust-lang/rfcs/blob/master/text/2521-c_void-reunification.md
27 // N.B., for LLVM to recognize the void pointer type and by extension
28 // functions like malloc(), we need to have it represented as i8* in
29 // LLVM bitcode. The enum used here ensures this and prevents misuse
30 // of the "raw" type by only having private variants. We need two
31 // variants, because the compiler complains about the repr attribute
32 // otherwise and we need at least one variant as otherwise the enum
33 // would be uninhabited and at least dereferencing such pointers would
36 #[stable(feature = "core_c_void", since = "1.30.0")]
39 feature
= "c_void_variant",
40 reason
= "temporary implementation detail",
46 feature
= "c_void_variant",
47 reason
= "temporary implementation detail",
54 #[stable(feature = "std_debug", since = "1.16.0")]
55 impl fmt
::Debug
for c_void
{
56 fn fmt(&self, f
: &mut fmt
::Formatter
<'_
>) -> fmt
::Result
{
61 /// Basic implementation of a `va_list`.
62 // The name is WIP, using `VaListImpl` for now.
64 all(not(target_arch
= "aarch64"), not(target_arch
= "powerpc"), not(target_arch
= "x86_64")),
65 all(target_arch
= "aarch64", target_os
= "ios"),
66 target_arch
= "wasm32",
67 target_arch
= "asmjs",
72 feature
= "c_variadic",
73 reason
= "the `c_variadic` feature has not been properly tested on \
74 all supported platforms",
78 pub struct VaListImpl
<'f
> {
81 // Invariant over `'f`, so each `VaListImpl<'f>` object is tied to
82 // the region of the function it's defined in
83 _marker
: PhantomData
<&'f
mut &'f c_void
>,
87 all(not(target_arch
= "aarch64"), not(target_arch
= "powerpc"), not(target_arch
= "x86_64")),
88 all(target_arch
= "aarch64", target_os
= "ios"),
89 target_arch
= "wasm32",
90 target_arch
= "asmjs",
94 feature
= "c_variadic",
95 reason
= "the `c_variadic` feature has not been properly tested on \
96 all supported platforms",
99 impl<'f
> fmt
::Debug
for VaListImpl
<'f
> {
100 fn fmt(&self, f
: &mut fmt
::Formatter
<'_
>) -> fmt
::Result
{
101 write
!(f
, "va_list* {:p}", self.ptr
)
105 /// AArch64 ABI implementation of a `va_list`. See the
106 /// [AArch64 Procedure Call Standard] for more details.
108 /// [AArch64 Procedure Call Standard]:
109 /// http://infocenter.arm.com/help/topic/com.arm.doc.ihi0055b/IHI0055B_aapcs64.pdf
110 #[cfg(all(target_arch = "aarch64", not(target_os = "ios"), not(windows)))]
114 feature
= "c_variadic",
115 reason
= "the `c_variadic` feature has not been properly tested on \
116 all supported platforms",
120 pub struct VaListImpl
<'f
> {
126 _marker
: PhantomData
<&'f
mut &'f c_void
>,
129 /// PowerPC ABI implementation of a `va_list`.
130 #[cfg(all(target_arch = "powerpc", not(windows)))]
134 feature
= "c_variadic",
135 reason
= "the `c_variadic` feature has not been properly tested on \
136 all supported platforms",
140 pub struct VaListImpl
<'f
> {
144 overflow_arg_area
: *mut c_void
,
145 reg_save_area
: *mut c_void
,
146 _marker
: PhantomData
<&'f
mut &'f c_void
>,
149 /// x86_64 ABI implementation of a `va_list`.
150 #[cfg(all(target_arch = "x86_64", not(windows)))]
154 feature
= "c_variadic",
155 reason
= "the `c_variadic` feature has not been properly tested on \
156 all supported platforms",
160 pub struct VaListImpl
<'f
> {
163 overflow_arg_area
: *mut c_void
,
164 reg_save_area
: *mut c_void
,
165 _marker
: PhantomData
<&'f
mut &'f c_void
>,
168 /// A wrapper for a `va_list`
172 feature
= "c_variadic",
173 reason
= "the `c_variadic` feature has not been properly tested on \
174 all supported platforms",
177 pub struct VaList
<'a
, 'f
: 'a
> {
180 not(target_arch
= "aarch64"),
181 not(target_arch
= "powerpc"),
182 not(target_arch
= "x86_64")
184 all(target_arch
= "aarch64", target_os
= "ios"),
185 target_arch
= "wasm32",
186 target_arch
= "asmjs",
189 inner
: VaListImpl
<'f
>,
192 any(target_arch
= "aarch64", target_arch
= "powerpc", target_arch
= "x86_64"),
193 any(not(target_arch
= "aarch64"), not(target_os
= "ios")),
194 not(target_arch
= "wasm32"),
195 not(target_arch
= "asmjs"),
198 inner
: &'a
mut VaListImpl
<'f
>,
200 _marker
: PhantomData
<&'a
mut VaListImpl
<'f
>>,
204 all(not(target_arch
= "aarch64"), not(target_arch
= "powerpc"), not(target_arch
= "x86_64")),
205 all(target_arch
= "aarch64", target_os
= "ios"),
206 target_arch
= "wasm32",
207 target_arch
= "asmjs",
211 feature
= "c_variadic",
212 reason
= "the `c_variadic` feature has not been properly tested on \
213 all supported platforms",
216 impl<'f
> VaListImpl
<'f
> {
217 /// Convert a `VaListImpl` into a `VaList` that is binary-compatible with C's `va_list`.
219 pub fn as_va_list
<'a
>(&'a
mut self) -> VaList
<'a
, 'f
> {
220 VaList { inner: VaListImpl { ..*self }
, _marker
: PhantomData
}
225 any(target_arch
= "aarch64", target_arch
= "powerpc", target_arch
= "x86_64"),
226 any(not(target_arch
= "aarch64"), not(target_os
= "ios")),
227 not(target_arch
= "wasm32"),
228 not(target_arch
= "asmjs"),
232 feature
= "c_variadic",
233 reason
= "the `c_variadic` feature has not been properly tested on \
234 all supported platforms",
237 impl<'f
> VaListImpl
<'f
> {
238 /// Convert a `VaListImpl` into a `VaList` that is binary-compatible with C's `va_list`.
240 pub fn as_va_list
<'a
>(&'a
mut self) -> VaList
<'a
, 'f
> {
241 VaList { inner: self, _marker: PhantomData }
246 feature
= "c_variadic",
247 reason
= "the `c_variadic` feature has not been properly tested on \
248 all supported platforms",
251 impl<'a
, 'f
: 'a
> Deref
for VaList
<'a
, 'f
> {
252 type Target
= VaListImpl
<'f
>;
255 fn deref(&self) -> &VaListImpl
<'f
> {
261 feature
= "c_variadic",
262 reason
= "the `c_variadic` feature has not been properly tested on \
263 all supported platforms",
266 impl<'a
, 'f
: 'a
> DerefMut
for VaList
<'a
, 'f
> {
268 fn deref_mut(&mut self) -> &mut VaListImpl
<'f
> {
273 // The VaArgSafe trait needs to be used in public interfaces, however, the trait
274 // itself must not be allowed to be used outside this module. Allowing users to
275 // implement the trait for a new type (thereby allowing the va_arg intrinsic to
276 // be used on a new type) is likely to cause undefined behavior.
278 // FIXME(dlrobertson): In order to use the VaArgSafe trait in a public interface
279 // but also ensure it cannot be used elsewhere, the trait needs to be public
280 // within a private module. Once RFC 2145 has been implemented look into
283 /// Trait which whitelists the allowed types to be used with [VaList::arg]
285 /// [VaList::va_arg]: struct.VaList.html#method.arg
287 feature
= "c_variadic",
288 reason
= "the `c_variadic` feature has not been properly tested on \
289 all supported platforms",
292 pub trait VaArgSafe {}
295 macro_rules
! impl_va_arg_safe
{
298 #[unstable(feature = "c_variadic",
299 reason
= "the `c_variadic` feature has not been properly tested on \
300 all supported platforms",
302 impl sealed_trait
::VaArgSafe
for $t {}
307 impl_va_arg_safe
! {i8, i16, i32, i64, usize}
308 impl_va_arg_safe
! {u8, u16, u32, u64, isize}
309 impl_va_arg_safe
! {f64}
312 feature
= "c_variadic",
313 reason
= "the `c_variadic` feature has not been properly tested on \
314 all supported platforms",
317 impl<T
> sealed_trait
::VaArgSafe
for *mut T {}
319 feature
= "c_variadic",
320 reason
= "the `c_variadic` feature has not been properly tested on \
321 all supported platforms",
324 impl<T
> sealed_trait
::VaArgSafe
for *const T {}
327 feature
= "c_variadic",
328 reason
= "the `c_variadic` feature has not been properly tested on \
329 all supported platforms",
332 impl<'f
> VaListImpl
<'f
> {
333 /// Advance to the next arg.
335 pub unsafe fn arg
<T
: sealed_trait
::VaArgSafe
>(&mut self) -> T
{
339 /// Copies the `va_list` at the current location.
340 pub unsafe fn with_copy
<F
, R
>(&self, f
: F
) -> R
342 F
: for<'copy
> FnOnce(VaList
<'copy
, 'f
>) -> R
,
344 let mut ap
= self.clone();
345 let ret
= f(ap
.as_va_list());
352 feature
= "c_variadic",
353 reason
= "the `c_variadic` feature has not been properly tested on \
354 all supported platforms",
357 impl<'f
> Clone
for VaListImpl
<'f
> {
359 fn clone(&self) -> Self {
360 let mut dest
= crate::mem
::MaybeUninit
::uninit();
361 // SAFETY: we write to the `MaybeUninit`, thus it is initialized and `assume_init` is legal
363 va_copy(dest
.as_mut_ptr(), self);
370 feature
= "c_variadic",
371 reason
= "the `c_variadic` feature has not been properly tested on \
372 all supported platforms",
375 impl<'f
> Drop
for VaListImpl
<'f
> {
377 // FIXME: this should call `va_end`, but there's no clean way to
378 // guarantee that `drop` always gets inlined into its caller,
379 // so the `va_end` would get directly called from the same function as
380 // the corresponding `va_copy`. `man va_end` states that C requires this,
381 // and LLVM basically follows the C semantics, so we need to make sure
382 // that `va_end` is always called from the same function as `va_copy`.
383 // For more details, see https://github.com/rust-lang/rust/pull/59625
384 // and https://llvm.org/docs/LangRef.html#llvm-va-end-intrinsic.
386 // This works for now, since `va_end` is a no-op on all current LLVM targets.
390 extern "rust-intrinsic" {
391 /// Destroy the arglist `ap` after initialization with `va_start` or
393 fn va_end(ap
: &mut VaListImpl
<'_
>);
395 /// Copies the current location of arglist `src` to the arglist `dst`.
396 fn va_copy
<'f
>(dest
: *mut VaListImpl
<'f
>, src
: &VaListImpl
<'f
>);
398 /// Loads an argument of type `T` from the `va_list` `ap` and increment the
399 /// argument `ap` points to.
400 fn va_arg
<T
: sealed_trait
::VaArgSafe
>(ap
: &mut VaListImpl
<'_
>) -> T
;