1 #![stable(feature = "", since = "1.30.0")]
3 #![allow(non_camel_case_types)]
5 //! Utilities related to FFI bindings.
8 use crate::marker::PhantomData;
9 use crate::ops::{Deref, DerefMut};
11 /// Equivalent to C's `void` type when used as a [pointer].
13 /// In essence, `*const c_void` is equivalent to C's `const void*`
14 /// and `*mut c_void` is equivalent to C's `void*`. That said, this is
15 /// *not* the same as C's `void` return type, which is Rust's `()` type.
17 /// To model pointers to opaque types in FFI, until `extern type` is
18 /// stabilized, it is recommended to use a newtype wrapper around an empty
19 /// byte array. See the [Nomicon] for details.
21 /// One could use `std::os::raw::c_void` if they want to support old Rust
22 /// compiler down to 1.1.0. After Rust 1.30.0, it was re-exported by
23 /// this definition. For more information, please read [RFC 2521].
25 /// [pointer]: ../../std/primitive.pointer.html
26 /// [Nomicon]: https://doc.rust-lang.org/nomicon/ffi.html#representing-opaque-structs
27 /// [RFC 2521]: https://github.com/rust-lang/rfcs/blob/master/text/2521-c_void-reunification.md
28 // N.B., for LLVM to recognize the void pointer type and by extension
29 // functions like malloc(), we need to have it represented as i8* in
30 // LLVM bitcode. The enum used here ensures this and prevents misuse
31 // of the "raw" type by only having private variants. We need two
32 // variants, because the compiler complains about the repr attribute
33 // otherwise and we need at least one variant as otherwise the enum
34 // would be uninhabited and at least dereferencing such pointers would
37 #[stable(feature = "core_c_void", since = "1.30.0")]
39 #[unstable(feature = "c_void_variant", reason = "temporary implementation detail",
41 #[doc(hidden)] __variant1,
42 #[unstable(feature = "c_void_variant", reason = "temporary implementation detail",
44 #[doc(hidden)] __variant2,
47 #[stable(feature = "std_debug", since = "1.16.0")]
48 impl fmt::Debug for c_void {
49 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
54 /// Basic implementation of a `va_list`.
55 // The name is WIP, using `VaListImpl` for now.
56 #[cfg(any(all(not(target_arch = "aarch64"), not(target_arch = "powerpc"),
57 not(target_arch = "x86_64")),
58 all(target_arch = "aarch64", target_os = "ios"),
59 target_arch = "wasm32",
60 target_arch = "asmjs",
63 #[unstable(feature = "c_variadic",
64 reason = "the `c_variadic` feature has not been properly tested on \
65 all supported platforms",
68 pub struct VaListImpl<'f> {
71 // Invariant over `'f`, so each `VaListImpl<'f>` object is tied to
72 // the region of the function it's defined in
73 _marker: PhantomData<&'f mut &'f c_void>,
76 #[cfg(any(all(not(target_arch = "aarch64"), not(target_arch = "powerpc"),
77 not(target_arch = "x86_64")),
78 all(target_arch = "aarch64", target_os = "ios"),
79 target_arch = "wasm32",
80 target_arch = "asmjs",
82 #[unstable(feature = "c_variadic",
83 reason = "the `c_variadic` feature has not been properly tested on \
84 all supported platforms",
86 impl<'f> fmt::Debug for VaListImpl<'f> {
87 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
88 write!(f, "va_list* {:p}", self.ptr)
92 /// AArch64 ABI implementation of a `va_list`. See the
93 /// [AArch64 Procedure Call Standard] for more details.
95 /// [AArch64 Procedure Call Standard]:
96 /// http://infocenter.arm.com/help/topic/com.arm.doc.ihi0055b/IHI0055B_aapcs64.pdf
97 #[cfg(all(target_arch = "aarch64", not(target_os = "ios"), not(windows)))]
100 #[unstable(feature = "c_variadic",
101 reason = "the `c_variadic` feature has not been properly tested on \
102 all supported platforms",
105 pub struct VaListImpl<'f> {
111 _marker: PhantomData<&'f mut &'f c_void>,
114 /// PowerPC ABI implementation of a `va_list`.
115 #[cfg(all(target_arch = "powerpc", not(windows)))]
118 #[unstable(feature = "c_variadic",
119 reason = "the `c_variadic` feature has not been properly tested on \
120 all supported platforms",
123 pub struct VaListImpl<'f> {
127 overflow_arg_area: *mut c_void,
128 reg_save_area: *mut c_void,
129 _marker: PhantomData<&'f mut &'f c_void>,
132 /// x86_64 ABI implementation of a `va_list`.
133 #[cfg(all(target_arch = "x86_64", not(windows)))]
136 #[unstable(feature = "c_variadic",
137 reason = "the `c_variadic` feature has not been properly tested on \
138 all supported platforms",
141 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 /// A wrapper for a `va_list`
152 #[unstable(feature = "c_variadic",
153 reason = "the `c_variadic` feature has not been properly tested on \
154 all supported platforms",
156 pub struct VaList<'a, 'f: 'a> {
157 #[cfg(any(all(not(target_arch = "aarch64"), not(target_arch = "powerpc"),
158 not(target_arch = "x86_64")),
159 all(target_arch = "aarch64", target_os = "ios"),
160 target_arch = "wasm32",
161 target_arch = "asmjs",
163 inner: VaListImpl<'f>,
165 #[cfg(all(any(target_arch = "aarch64", target_arch = "powerpc",
166 target_arch = "x86_64"),
167 any(not(target_arch = "aarch64"), not(target_os = "ios")),
168 not(target_arch = "wasm32"),
169 not(target_arch = "asmjs"),
171 inner: &'a mut VaListImpl<'f>,
173 _marker: PhantomData<&'a mut VaListImpl<'f>>,
176 #[cfg(any(all(not(target_arch = "aarch64"), not(target_arch = "powerpc"),
177 not(target_arch = "x86_64")),
178 all(target_arch = "aarch64", target_os = "ios"),
179 target_arch = "wasm32",
180 target_arch = "asmjs",
182 #[unstable(feature = "c_variadic",
183 reason = "the `c_variadic` feature has not been properly tested on \
184 all supported platforms",
186 impl<'f> VaListImpl<'f> {
187 /// Convert a `VaListImpl` into a `VaList` that is binary-compatible with C's `va_list`.
189 pub fn as_va_list<'a>(&'a mut self) -> VaList<'a, 'f> {
191 inner: VaListImpl { ..*self },
192 _marker: PhantomData,
197 #[cfg(all(any(target_arch = "aarch64", target_arch = "powerpc",
198 target_arch = "x86_64"),
199 any(not(target_arch = "aarch64"), not(target_os = "ios")),
200 not(target_arch = "wasm32"),
201 not(target_arch = "asmjs"),
203 #[unstable(feature = "c_variadic",
204 reason = "the `c_variadic` feature has not been properly tested on \
205 all supported platforms",
207 impl<'f> VaListImpl<'f> {
208 /// Convert a `VaListImpl` into a `VaList` that is binary-compatible with C's `va_list`.
210 pub fn as_va_list<'a>(&'a mut self) -> VaList<'a, 'f> {
213 _marker: PhantomData,
218 #[unstable(feature = "c_variadic",
219 reason = "the `c_variadic` feature has not been properly tested on \
220 all supported platforms",
222 impl<'a, 'f: 'a> Deref for VaList<'a, 'f> {
223 type Target = VaListImpl<'f>;
226 fn deref(&self) -> &VaListImpl<'f> {
231 #[unstable(feature = "c_variadic",
232 reason = "the `c_variadic` feature has not been properly tested on \
233 all supported platforms",
235 impl<'a, 'f: 'a> DerefMut for VaList<'a, 'f> {
237 fn deref_mut(&mut self) -> &mut VaListImpl<'f> {
242 // The VaArgSafe trait needs to be used in public interfaces, however, the trait
243 // itself must not be allowed to be used outside this module. Allowing users to
244 // implement the trait for a new type (thereby allowing the va_arg intrinsic to
245 // be used on a new type) is likely to cause undefined behavior.
247 // FIXME(dlrobertson): In order to use the VaArgSafe trait in a public interface
248 // but also ensure it cannot be used elsewhere, the trait needs to be public
249 // within a private module. Once RFC 2145 has been implemented look into
252 /// Trait which whitelists the allowed types to be used with [VaList::arg]
254 /// [VaList::va_arg]: struct.VaList.html#method.arg
255 #[unstable(feature = "c_variadic",
256 reason = "the `c_variadic` feature has not been properly tested on \
257 all supported platforms",
259 pub trait VaArgSafe {}
262 macro_rules! impl_va_arg_safe {
265 #[unstable(feature = "c_variadic",
266 reason = "the `c_variadic` feature has not been properly tested on \
267 all supported platforms",
269 impl sealed_trait::VaArgSafe for $t {}
274 impl_va_arg_safe!{i8, i16, i32, i64, usize}
275 impl_va_arg_safe!{u8, u16, u32, u64, isize}
276 impl_va_arg_safe!{f64}
278 #[unstable(feature = "c_variadic",
279 reason = "the `c_variadic` feature has not been properly tested on \
280 all supported platforms",
282 impl<T> sealed_trait::VaArgSafe for *mut T {}
283 #[unstable(feature = "c_variadic",
284 reason = "the `c_variadic` feature has not been properly tested on \
285 all supported platforms",
287 impl<T> sealed_trait::VaArgSafe for *const T {}
289 #[unstable(feature = "c_variadic",
290 reason = "the `c_variadic` feature has not been properly tested on \
291 all supported platforms",
293 impl<'f> VaListImpl<'f> {
294 /// Advance to the next arg.
296 pub unsafe fn arg<T: sealed_trait::VaArgSafe>(&mut self) -> T {
300 /// Copies the `va_list` at the current location.
301 pub unsafe fn with_copy<F, R>(&self, f: F) -> R
302 where F: for<'copy> FnOnce(VaList<'copy, 'f>) -> R {
303 let mut ap = self.clone();
304 let ret = f(ap.as_va_list());
310 #[unstable(feature = "c_variadic",
311 reason = "the `c_variadic` feature has not been properly tested on \
312 all supported platforms",
314 impl<'f> Clone for VaListImpl<'f> {
316 fn clone(&self) -> Self {
317 let mut dest = crate::mem::MaybeUninit::uninit();
318 // SAFETY: we write to the `MaybeUninit`, thus it is initialized and `assume_init` is legal
320 va_copy(dest.as_mut_ptr(), self);
326 #[unstable(feature = "c_variadic",
327 reason = "the `c_variadic` feature has not been properly tested on \
328 all supported platforms",
330 impl<'f> Drop for VaListImpl<'f> {
332 // FIXME: this should call `va_end`, but there's no clean way to
333 // guarantee that `drop` always gets inlined into its caller,
334 // so the `va_end` would get directly called from the same function as
335 // the corresponding `va_copy`. `man va_end` states that C requires this,
336 // and LLVM basically follows the C semantics, so we need to make sure
337 // that `va_end` is always called from the same function as `va_copy`.
338 // For more details, see https://github.com/rust-lang/rust/pull/59625
339 // and https://llvm.org/docs/LangRef.html#llvm-va-end-intrinsic.
341 // This works for now, since `va_end` is a no-op on all current LLVM targets.
345 extern "rust-intrinsic" {
346 /// Destroy the arglist `ap` after initialization with `va_start` or
348 fn va_end(ap: &mut VaListImpl<'_>);
350 /// Copies the current location of arglist `src` to the arglist `dst`.
351 fn va_copy<'f>(dest: *mut VaListImpl<'f>, src: &VaListImpl<'f>);
353 /// Loads an argument of type `T` from the `va_list` `ap` and increment the
354 /// argument `ap` points to.
355 fn va_arg<T: sealed_trait::VaArgSafe>(ap: &mut VaListImpl<'_>) -> T;