]> git.lizzy.rs Git - rust.git/blob - src/libcore/ffi.rs
Rollup merge of #66186 - GuillaumeGomez:long-err-explanation-E0623, r=Dylan-DPC
[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 /// 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].
24 ///
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
35 //     be UB.
36 #[repr(u8)]
37 #[stable(feature = "core_c_void", since = "1.30.0")]
38 pub enum c_void {
39     #[unstable(feature = "c_void_variant", reason = "temporary implementation detail",
40                issue = "0")]
41     #[doc(hidden)] __variant1,
42     #[unstable(feature = "c_void_variant", reason = "temporary implementation detail",
43                issue = "0")]
44     #[doc(hidden)] __variant2,
45 }
46
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 {
50         f.pad("c_void")
51     }
52 }
53
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",
61           windows))]
62 #[repr(transparent)]
63 #[unstable(feature = "c_variadic",
64            reason = "the `c_variadic` feature has not been properly tested on \
65                      all supported platforms",
66            issue = "44930")]
67 #[lang = "va_list"]
68 pub struct VaListImpl<'f> {
69     ptr: *mut c_void,
70
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>,
74 }
75
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",
81           windows))]
82 #[unstable(feature = "c_variadic",
83            reason = "the `c_variadic` feature has not been properly tested on \
84                      all supported platforms",
85            issue = "44930")]
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)
89     }
90 }
91
92 /// AArch64 ABI implementation of a `va_list`. See the
93 /// [AArch64 Procedure Call Standard] for more details.
94 ///
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)))]
98 #[repr(C)]
99 #[derive(Debug)]
100 #[unstable(feature = "c_variadic",
101            reason = "the `c_variadic` feature has not been properly tested on \
102                      all supported platforms",
103            issue = "44930")]
104 #[lang = "va_list"]
105 pub struct VaListImpl<'f> {
106     stack: *mut c_void,
107     gr_top: *mut c_void,
108     vr_top: *mut c_void,
109     gr_offs: i32,
110     vr_offs: i32,
111     _marker: PhantomData<&'f mut &'f c_void>,
112 }
113
114 /// PowerPC ABI implementation of a `va_list`.
115 #[cfg(all(target_arch = "powerpc", not(windows)))]
116 #[repr(C)]
117 #[derive(Debug)]
118 #[unstable(feature = "c_variadic",
119            reason = "the `c_variadic` feature has not been properly tested on \
120                      all supported platforms",
121            issue = "44930")]
122 #[lang = "va_list"]
123 pub struct VaListImpl<'f> {
124     gpr: u8,
125     fpr: u8,
126     reserved: u16,
127     overflow_arg_area: *mut c_void,
128     reg_save_area: *mut c_void,
129     _marker: PhantomData<&'f mut &'f c_void>,
130 }
131
132 /// x86_64 ABI implementation of a `va_list`.
133 #[cfg(all(target_arch = "x86_64", not(windows)))]
134 #[repr(C)]
135 #[derive(Debug)]
136 #[unstable(feature = "c_variadic",
137            reason = "the `c_variadic` feature has not been properly tested on \
138                      all supported platforms",
139            issue = "44930")]
140 #[lang = "va_list"]
141 pub struct VaListImpl<'f> {
142     gp_offset: i32,
143     fp_offset: i32,
144     overflow_arg_area: *mut c_void,
145     reg_save_area: *mut c_void,
146     _marker: PhantomData<&'f mut &'f c_void>,
147 }
148
149 /// A wrapper for a `va_list`
150 #[repr(transparent)]
151 #[derive(Debug)]
152 #[unstable(feature = "c_variadic",
153            reason = "the `c_variadic` feature has not been properly tested on \
154                      all supported platforms",
155            issue = "44930")]
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",
162               windows))]
163     inner: VaListImpl<'f>,
164
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"),
170               not(windows)))]
171     inner: &'a mut VaListImpl<'f>,
172
173     _marker: PhantomData<&'a mut VaListImpl<'f>>,
174 }
175
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",
181           windows))]
182 #[unstable(feature = "c_variadic",
183            reason = "the `c_variadic` feature has not been properly tested on \
184                      all supported platforms",
185            issue = "44930")]
186 impl<'f> VaListImpl<'f> {
187     /// Convert a `VaListImpl` into a `VaList` that is binary-compatible with C's `va_list`.
188     #[inline]
189     pub fn as_va_list<'a>(&'a mut self) -> VaList<'a, 'f> {
190         VaList {
191             inner: VaListImpl { ..*self },
192             _marker: PhantomData,
193         }
194     }
195 }
196
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"),
202           not(windows)))]
203 #[unstable(feature = "c_variadic",
204            reason = "the `c_variadic` feature has not been properly tested on \
205                      all supported platforms",
206            issue = "44930")]
207 impl<'f> VaListImpl<'f> {
208     /// Convert a `VaListImpl` into a `VaList` that is binary-compatible with C's `va_list`.
209     #[inline]
210     pub fn as_va_list<'a>(&'a mut self) -> VaList<'a, 'f> {
211         VaList {
212             inner: self,
213             _marker: PhantomData,
214         }
215     }
216 }
217
218 #[unstable(feature = "c_variadic",
219            reason = "the `c_variadic` feature has not been properly tested on \
220                      all supported platforms",
221            issue = "44930")]
222 impl<'a, 'f: 'a> Deref for VaList<'a, 'f> {
223     type Target = VaListImpl<'f>;
224
225     #[inline]
226     fn deref(&self) -> &VaListImpl<'f> {
227         &self.inner
228     }
229 }
230
231 #[unstable(feature = "c_variadic",
232            reason = "the `c_variadic` feature has not been properly tested on \
233                      all supported platforms",
234            issue = "44930")]
235 impl<'a, 'f: 'a> DerefMut for VaList<'a, 'f> {
236     #[inline]
237     fn deref_mut(&mut self) -> &mut VaListImpl<'f> {
238         &mut self.inner
239     }
240 }
241
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.
246 //
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
250 // improving this.
251 mod sealed_trait {
252     /// Trait which whitelists the allowed types to be used with [VaList::arg]
253     ///
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",
258                issue = "44930")]
259     pub trait VaArgSafe {}
260 }
261
262 macro_rules! impl_va_arg_safe {
263     ($($t:ty),+) => {
264         $(
265             #[unstable(feature = "c_variadic",
266                        reason = "the `c_variadic` feature has not been properly tested on \
267                                  all supported platforms",
268                        issue = "44930")]
269             impl sealed_trait::VaArgSafe for $t {}
270         )+
271     }
272 }
273
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}
277
278 #[unstable(feature = "c_variadic",
279            reason = "the `c_variadic` feature has not been properly tested on \
280                      all supported platforms",
281            issue = "44930")]
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",
286            issue = "44930")]
287 impl<T> sealed_trait::VaArgSafe for *const T {}
288
289 #[unstable(feature = "c_variadic",
290            reason = "the `c_variadic` feature has not been properly tested on \
291                      all supported platforms",
292            issue = "44930")]
293 impl<'f> VaListImpl<'f> {
294     /// Advance to the next arg.
295     #[inline]
296     pub unsafe fn arg<T: sealed_trait::VaArgSafe>(&mut self) -> T {
297         va_arg(self)
298     }
299
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());
305         va_end(&mut ap);
306         ret
307     }
308 }
309
310 #[unstable(feature = "c_variadic",
311            reason = "the `c_variadic` feature has not been properly tested on \
312                      all supported platforms",
313            issue = "44930")]
314 impl<'f> Clone for VaListImpl<'f> {
315     #[inline]
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
319         unsafe {
320             va_copy(dest.as_mut_ptr(), self);
321             dest.assume_init()
322         }
323     }
324 }
325
326 #[unstable(feature = "c_variadic",
327            reason = "the `c_variadic` feature has not been properly tested on \
328                      all supported platforms",
329            issue = "44930")]
330 impl<'f> Drop for VaListImpl<'f> {
331     fn drop(&mut self) {
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.
340         //
341         // This works for now, since `va_end` is a no-op on all current LLVM targets.
342     }
343 }
344
345 extern "rust-intrinsic" {
346     /// Destroy the arglist `ap` after initialization with `va_start` or
347     /// `va_copy`.
348     fn va_end(ap: &mut VaListImpl<'_>);
349
350     /// Copies the current location of arglist `src` to the arglist `dst`.
351     fn va_copy<'f>(dest: *mut VaListImpl<'f>, src: &VaListImpl<'f>);
352
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;
356 }