]> git.lizzy.rs Git - rust.git/blob - src/libcore/ffi.rs
More questionmarks in doctests
[rust.git] / src / libcore / ffi.rs
1 #![stable(feature = "", since = "1.30.0")]
2
3 #![allow(non_camel_case_types)]
4
5 //! Utilities related to FFI bindings.
6
7 use crate::fmt;
8 use crate::marker::PhantomData;
9 use crate::ops::{Deref, DerefMut};
10
11 /// Equivalent to C's `void` type when used as a [pointer].
12 ///
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.
16 ///
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.
20 ///
21 /// [pointer]: ../../std/primitive.pointer.html
22 /// [Nomicon]: https://doc.rust-lang.org/nomicon/ffi.html#representing-opaque-structs
23 // N.B., for LLVM to recognize the void pointer type and by extension
24 //     functions like malloc(), we need to have it represented as i8* in
25 //     LLVM bitcode. The enum used here ensures this and prevents misuse
26 //     of the "raw" type by only having private variants. We need two
27 //     variants, because the compiler complains about the repr attribute
28 //     otherwise and we need at least one variant as otherwise the enum
29 //     would be uninhabited and at least dereferencing such pointers would
30 //     be UB.
31 #[repr(u8)]
32 #[stable(feature = "raw_os", since = "1.1.0")]
33 pub enum c_void {
34     #[unstable(feature = "c_void_variant", reason = "temporary implementation detail",
35                issue = "0")]
36     #[doc(hidden)] __variant1,
37     #[unstable(feature = "c_void_variant", reason = "temporary implementation detail",
38                issue = "0")]
39     #[doc(hidden)] __variant2,
40 }
41
42 #[stable(feature = "std_debug", since = "1.16.0")]
43 impl fmt::Debug for c_void {
44     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
45         f.pad("c_void")
46     }
47 }
48
49 /// Basic implementation of a `va_list`.
50 // The name is WIP, using `VaListImpl` for now.
51 #[cfg(any(all(not(target_arch = "aarch64"), not(target_arch = "powerpc"),
52               not(target_arch = "x86_64"), not(target_arch = "asmjs")),
53           all(target_arch = "aarch64", target_os = "ios"),
54           windows))]
55 #[repr(transparent)]
56 #[unstable(feature = "c_variadic",
57            reason = "the `c_variadic` feature has not been properly tested on \
58                      all supported platforms",
59            issue = "44930")]
60 #[lang = "va_list"]
61 pub struct VaListImpl<'f> {
62     ptr: *mut c_void,
63     _marker: PhantomData<&'f c_void>,
64 }
65
66 #[cfg(any(all(not(target_arch = "aarch64"), not(target_arch = "powerpc"),
67               not(target_arch = "x86_64"), not(target_arch = "asmjs")),
68           all(target_arch = "aarch64", target_os = "ios"),
69           windows))]
70 #[unstable(feature = "c_variadic",
71            reason = "the `c_variadic` feature has not been properly tested on \
72                      all supported platforms",
73            issue = "44930")]
74 impl<'f> fmt::Debug for VaListImpl<'f> {
75     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
76         write!(f, "va_list* {:p}", self.ptr)
77     }
78 }
79
80 /// AArch64 ABI implementation of a `va_list`. See the
81 /// [AArch64 Procedure Call Standard] for more details.
82 ///
83 /// [AArch64 Procedure Call Standard]:
84 /// http://infocenter.arm.com/help/topic/com.arm.doc.ihi0055b/IHI0055B_aapcs64.pdf
85 #[cfg(all(target_arch = "aarch64", not(target_os = "ios"), not(windows)))]
86 #[repr(C)]
87 #[derive(Debug)]
88 #[unstable(feature = "c_variadic",
89            reason = "the `c_variadic` feature has not been properly tested on \
90                      all supported platforms",
91            issue = "44930")]
92 #[lang = "va_list"]
93 pub struct VaListImpl<'f> {
94     stack: *mut c_void,
95     gr_top: *mut c_void,
96     vr_top: *mut c_void,
97     gr_offs: i32,
98     vr_offs: i32,
99     _marker: PhantomData<&'f c_void>,
100 }
101
102 /// PowerPC ABI implementation of a `va_list`.
103 #[cfg(all(target_arch = "powerpc", not(windows)))]
104 #[repr(C)]
105 #[derive(Debug)]
106 #[unstable(feature = "c_variadic",
107            reason = "the `c_variadic` feature has not been properly tested on \
108                      all supported platforms",
109            issue = "44930")]
110 #[lang = "va_list"]
111 pub struct VaListImpl<'f> {
112     gpr: u8,
113     fpr: u8,
114     reserved: u16,
115     overflow_arg_area: *mut c_void,
116     reg_save_area: *mut c_void,
117     _marker: PhantomData<&'f c_void>,
118 }
119
120 /// x86_64 ABI implementation of a `va_list`.
121 #[cfg(all(target_arch = "x86_64", not(windows)))]
122 #[repr(C)]
123 #[derive(Debug)]
124 #[unstable(feature = "c_variadic",
125            reason = "the `c_variadic` feature has not been properly tested on \
126                      all supported platforms",
127            issue = "44930")]
128 #[lang = "va_list"]
129 pub struct VaListImpl<'f> {
130     gp_offset: i32,
131     fp_offset: i32,
132     overflow_arg_area: *mut c_void,
133     reg_save_area: *mut c_void,
134     _marker: PhantomData<&'f c_void>,
135 }
136
137 /// asm.js ABI implementation of a `va_list`.
138 // asm.js uses the PNaCl ABI, which specifies that a `va_list` is
139 // an array of 4 32-bit integers, according to the old PNaCl docs at
140 // https://web.archive.org/web/20130518054430/https://www.chromium.org/nativeclient/pnacl/bitcode-abi#TOC-Derived-Types
141 // and clang does the same in `CreatePNaClABIBuiltinVaListDecl` from `lib/AST/ASTContext.cpp`
142 #[cfg(all(target_arch = "asmjs", not(windows)))]
143 #[repr(C)]
144 #[unstable(feature = "c_variadic",
145            reason = "the `c_variadic` feature has not been properly tested on \
146                      all supported platforms",
147            issue = "44930")]
148 #[lang = "va_list"]
149 pub struct VaListImpl<'f> {
150     inner: [crate::mem::MaybeUninit<i32>; 4],
151     _marker: PhantomData<&'f c_void>,
152 }
153
154 #[cfg(all(target_arch = "asmjs", not(windows)))]
155 #[unstable(feature = "c_variadic",
156            reason = "the `c_variadic` feature has not been properly tested on \
157                      all supported platforms",
158            issue = "44930")]
159 impl<'f> fmt::Debug for VaListImpl<'f> {
160     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
161         unsafe {
162             write!(f, "va_list* [{:#x}, {:#x}, {:#x}, {:#x}]",
163                    self.inner[0].read(), self.inner[1].read(),
164                    self.inner[2].read(), self.inner[3].read())
165         }
166     }
167 }
168
169 /// A wrapper for a `va_list`
170 #[repr(transparent)]
171 #[derive(Debug)]
172 #[unstable(feature = "c_variadic",
173            reason = "the `c_variadic` feature has not been properly tested on \
174                      all supported platforms",
175            issue = "44930")]
176 pub struct VaList<'a, 'f: 'a> {
177     #[cfg(any(all(not(target_arch = "aarch64"), not(target_arch = "powerpc"),
178                   not(target_arch = "x86_64"), not(target_arch = "asmjs")),
179               all(target_arch = "aarch64", target_os = "ios"),
180               windows))]
181     inner: VaListImpl<'f>,
182
183     #[cfg(all(any(target_arch = "aarch64", target_arch = "powerpc",
184                   target_arch = "x86_64", target_arch = "asmjs"),
185               any(not(target_arch = "aarch64"), not(target_os = "ios")),
186               not(windows)))]
187     inner: &'a mut VaListImpl<'f>,
188
189     _marker: PhantomData<&'a mut VaListImpl<'f>>,
190 }
191
192 #[cfg(any(all(not(target_arch = "aarch64"), not(target_arch = "powerpc"),
193               not(target_arch = "x86_64"), not(target_arch = "asmjs")),
194           all(target_arch = "aarch64", target_os = "ios"),
195           windows))]
196 #[unstable(feature = "c_variadic",
197            reason = "the `c_variadic` feature has not been properly tested on \
198                      all supported platforms",
199            issue = "44930")]
200 impl<'f> VaListImpl<'f> {
201     /// Convert a `VaListImpl` into a `VaList` that is binary-compatible with C's `va_list`.
202     #[inline]
203     pub fn as_va_list<'a>(&'a mut self) -> VaList<'a, 'f> {
204         VaList {
205             inner: VaListImpl { ..*self },
206             _marker: PhantomData,
207         }
208     }
209 }
210
211 #[cfg(all(any(target_arch = "aarch64", target_arch = "powerpc",
212               target_arch = "x86_64", target_arch = "asmjs"),
213           any(not(target_arch = "aarch64"), not(target_os = "ios")),
214           not(windows)))]
215 #[unstable(feature = "c_variadic",
216            reason = "the `c_variadic` feature has not been properly tested on \
217                      all supported platforms",
218            issue = "44930")]
219 impl<'f> VaListImpl<'f> {
220     /// Convert a `VaListImpl` into a `VaList` that is binary-compatible with C's `va_list`.
221     #[inline]
222     pub fn as_va_list<'a>(&'a mut self) -> VaList<'a, 'f> {
223         VaList {
224             inner: self,
225             _marker: PhantomData,
226         }
227     }
228 }
229
230 #[unstable(feature = "c_variadic",
231            reason = "the `c_variadic` feature has not been properly tested on \
232                      all supported platforms",
233            issue = "44930")]
234 impl<'a, 'f: 'a> Deref for VaList<'a, 'f> {
235     type Target = VaListImpl<'f>;
236
237     #[inline]
238     fn deref(&self) -> &VaListImpl<'f> {
239         &self.inner
240     }
241 }
242
243 #[unstable(feature = "c_variadic",
244            reason = "the `c_variadic` feature has not been properly tested on \
245                      all supported platforms",
246            issue = "44930")]
247 impl<'a, 'f: 'a> DerefMut for VaList<'a, 'f> {
248     #[inline]
249     fn deref_mut(&mut self) -> &mut VaListImpl<'f> {
250         &mut self.inner
251     }
252 }
253
254 // The VaArgSafe trait needs to be used in public interfaces, however, the trait
255 // itself must not be allowed to be used outside this module. Allowing users to
256 // implement the trait for a new type (thereby allowing the va_arg intrinsic to
257 // be used on a new type) is likely to cause undefined behavior.
258 //
259 // FIXME(dlrobertson): In order to use the VaArgSafe trait in a public interface
260 // but also ensure it cannot be used elsewhere, the trait needs to be public
261 // within a private module. Once RFC 2145 has been implemented look into
262 // improving this.
263 mod sealed_trait {
264     /// Trait which whitelists the allowed types to be used with [VaList::arg]
265     ///
266     /// [VaList::va_arg]: struct.VaList.html#method.arg
267     #[unstable(feature = "c_variadic",
268                reason = "the `c_variadic` feature has not been properly tested on \
269                          all supported platforms",
270                issue = "44930")]
271     pub trait VaArgSafe {}
272 }
273
274 macro_rules! impl_va_arg_safe {
275     ($($t:ty),+) => {
276         $(
277             #[unstable(feature = "c_variadic",
278                        reason = "the `c_variadic` feature has not been properly tested on \
279                                  all supported platforms",
280                        issue = "44930")]
281             impl sealed_trait::VaArgSafe for $t {}
282         )+
283     }
284 }
285
286 impl_va_arg_safe!{i8, i16, i32, i64, usize}
287 impl_va_arg_safe!{u8, u16, u32, u64, isize}
288 impl_va_arg_safe!{f64}
289
290 #[unstable(feature = "c_variadic",
291            reason = "the `c_variadic` feature has not been properly tested on \
292                      all supported platforms",
293            issue = "44930")]
294 impl<T> sealed_trait::VaArgSafe for *mut T {}
295 #[unstable(feature = "c_variadic",
296            reason = "the `c_variadic` feature has not been properly tested on \
297                      all supported platforms",
298            issue = "44930")]
299 impl<T> sealed_trait::VaArgSafe for *const T {}
300
301 #[unstable(feature = "c_variadic",
302            reason = "the `c_variadic` feature has not been properly tested on \
303                      all supported platforms",
304            issue = "44930")]
305 impl<'f> VaListImpl<'f> {
306     /// Advance to the next arg.
307     #[inline]
308     pub unsafe fn arg<T: sealed_trait::VaArgSafe>(&mut self) -> T {
309         va_arg(self)
310     }
311
312     /// Copies the `va_list` at the current location.
313     pub unsafe fn with_copy<F, R>(&self, f: F) -> R
314             where F: for<'copy> FnOnce(VaList<'copy, 'f>) -> R {
315         let mut ap = self.clone();
316         let ret = f(ap.as_va_list());
317         va_end(&mut ap);
318         ret
319     }
320 }
321
322 #[unstable(feature = "c_variadic",
323            reason = "the `c_variadic` feature has not been properly tested on \
324                      all supported platforms",
325            issue = "44930")]
326 impl<'f> Clone for VaListImpl<'f> {
327     #[inline]
328     fn clone(&self) -> Self {
329         let mut dest = crate::mem::MaybeUninit::uninit();
330         unsafe {
331             va_copy(dest.as_mut_ptr(), self);
332             dest.assume_init()
333         }
334     }
335 }
336
337 #[unstable(feature = "c_variadic",
338            reason = "the `c_variadic` feature has not been properly tested on \
339                      all supported platforms",
340            issue = "44930")]
341 impl<'f> Drop for VaListImpl<'f> {
342     fn drop(&mut self) {
343         // FIXME: this should call `va_end`, but there's no clean way to
344         // guarantee that `drop` always gets inlined into its caller,
345         // so the `va_end` would get directly called from the same function as
346         // the corresponding `va_copy`. `man va_end` states that C requires this,
347         // and LLVM basically follows the C semantics, so we need to make sure
348         // that `va_end` is always called from the same function as `va_copy`.
349         // For more details, see https://github.com/rust-lang/rust/pull/59625
350         // and https://llvm.org/docs/LangRef.html#llvm-va-end-intrinsic.
351         //
352         // This works for now, since `va_end` is a no-op on all current LLVM targets.
353     }
354 }
355
356 extern "rust-intrinsic" {
357     /// Destroy the arglist `ap` after initialization with `va_start` or
358     /// `va_copy`.
359     fn va_end(ap: &mut VaListImpl<'_>);
360
361     /// Copies the current location of arglist `src` to the arglist `dst`.
362     fn va_copy<'f>(dest: *mut VaListImpl<'f>, src: &VaListImpl<'f>);
363
364     /// Loads an argument of type `T` from the `va_list` `ap` and increment the
365     /// argument `ap` points to.
366     fn va_arg<T: sealed_trait::VaArgSafe>(ap: &mut VaListImpl<'_>) -> T;
367 }