]> git.proxmox.com Git - rustc.git/blob - src/libcore/ffi.rs
New upstream version 1.41.1+dfsg1
[rustc.git] / src / libcore / ffi.rs
1 #![stable(feature = "", since = "1.30.0")]
2 #![allow(non_camel_case_types)]
3
4 //! Utilities related to FFI bindings.
5
6 use crate::fmt;
7 use crate::marker::PhantomData;
8 use crate::ops::{Deref, DerefMut};
9
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.
15 ///
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.
19 ///
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].
23 ///
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
34 // be UB.
35 #[repr(u8)]
36 #[stable(feature = "core_c_void", since = "1.30.0")]
37 pub enum c_void {
38 #[unstable(
39 feature = "c_void_variant",
40 reason = "temporary implementation detail",
41 issue = "0"
42 )]
43 #[doc(hidden)]
44 __variant1,
45 #[unstable(
46 feature = "c_void_variant",
47 reason = "temporary implementation detail",
48 issue = "0"
49 )]
50 #[doc(hidden)]
51 __variant2,
52 }
53
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 {
57 f.pad("c_void")
58 }
59 }
60
61 /// Basic implementation of a `va_list`.
62 // The name is WIP, using `VaListImpl` for now.
63 #[cfg(any(
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",
68 windows
69 ))]
70 #[repr(transparent)]
71 #[unstable(
72 feature = "c_variadic",
73 reason = "the `c_variadic` feature has not been properly tested on \
74 all supported platforms",
75 issue = "44930"
76 )]
77 #[lang = "va_list"]
78 pub struct VaListImpl<'f> {
79 ptr: *mut c_void,
80
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>,
84 }
85
86 #[cfg(any(
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",
91 windows
92 ))]
93 #[unstable(
94 feature = "c_variadic",
95 reason = "the `c_variadic` feature has not been properly tested on \
96 all supported platforms",
97 issue = "44930"
98 )]
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)
102 }
103 }
104
105 /// AArch64 ABI implementation of a `va_list`. See the
106 /// [AArch64 Procedure Call Standard] for more details.
107 ///
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)))]
111 #[repr(C)]
112 #[derive(Debug)]
113 #[unstable(
114 feature = "c_variadic",
115 reason = "the `c_variadic` feature has not been properly tested on \
116 all supported platforms",
117 issue = "44930"
118 )]
119 #[lang = "va_list"]
120 pub struct VaListImpl<'f> {
121 stack: *mut c_void,
122 gr_top: *mut c_void,
123 vr_top: *mut c_void,
124 gr_offs: i32,
125 vr_offs: i32,
126 _marker: PhantomData<&'f mut &'f c_void>,
127 }
128
129 /// PowerPC ABI implementation of a `va_list`.
130 #[cfg(all(target_arch = "powerpc", not(windows)))]
131 #[repr(C)]
132 #[derive(Debug)]
133 #[unstable(
134 feature = "c_variadic",
135 reason = "the `c_variadic` feature has not been properly tested on \
136 all supported platforms",
137 issue = "44930"
138 )]
139 #[lang = "va_list"]
140 pub struct VaListImpl<'f> {
141 gpr: u8,
142 fpr: u8,
143 reserved: u16,
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 /// x86_64 ABI implementation of a `va_list`.
150 #[cfg(all(target_arch = "x86_64", not(windows)))]
151 #[repr(C)]
152 #[derive(Debug)]
153 #[unstable(
154 feature = "c_variadic",
155 reason = "the `c_variadic` feature has not been properly tested on \
156 all supported platforms",
157 issue = "44930"
158 )]
159 #[lang = "va_list"]
160 pub struct VaListImpl<'f> {
161 gp_offset: i32,
162 fp_offset: i32,
163 overflow_arg_area: *mut c_void,
164 reg_save_area: *mut c_void,
165 _marker: PhantomData<&'f mut &'f c_void>,
166 }
167
168 /// A wrapper for a `va_list`
169 #[repr(transparent)]
170 #[derive(Debug)]
171 #[unstable(
172 feature = "c_variadic",
173 reason = "the `c_variadic` feature has not been properly tested on \
174 all supported platforms",
175 issue = "44930"
176 )]
177 pub struct VaList<'a, 'f: 'a> {
178 #[cfg(any(
179 all(
180 not(target_arch = "aarch64"),
181 not(target_arch = "powerpc"),
182 not(target_arch = "x86_64")
183 ),
184 all(target_arch = "aarch64", target_os = "ios"),
185 target_arch = "wasm32",
186 target_arch = "asmjs",
187 windows
188 ))]
189 inner: VaListImpl<'f>,
190
191 #[cfg(all(
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"),
196 not(windows)
197 ))]
198 inner: &'a mut VaListImpl<'f>,
199
200 _marker: PhantomData<&'a mut VaListImpl<'f>>,
201 }
202
203 #[cfg(any(
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",
208 windows
209 ))]
210 #[unstable(
211 feature = "c_variadic",
212 reason = "the `c_variadic` feature has not been properly tested on \
213 all supported platforms",
214 issue = "44930"
215 )]
216 impl<'f> VaListImpl<'f> {
217 /// Convert a `VaListImpl` into a `VaList` that is binary-compatible with C's `va_list`.
218 #[inline]
219 pub fn as_va_list<'a>(&'a mut self) -> VaList<'a, 'f> {
220 VaList { inner: VaListImpl { ..*self }, _marker: PhantomData }
221 }
222 }
223
224 #[cfg(all(
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"),
229 not(windows)
230 ))]
231 #[unstable(
232 feature = "c_variadic",
233 reason = "the `c_variadic` feature has not been properly tested on \
234 all supported platforms",
235 issue = "44930"
236 )]
237 impl<'f> VaListImpl<'f> {
238 /// Convert a `VaListImpl` into a `VaList` that is binary-compatible with C's `va_list`.
239 #[inline]
240 pub fn as_va_list<'a>(&'a mut self) -> VaList<'a, 'f> {
241 VaList { inner: self, _marker: PhantomData }
242 }
243 }
244
245 #[unstable(
246 feature = "c_variadic",
247 reason = "the `c_variadic` feature has not been properly tested on \
248 all supported platforms",
249 issue = "44930"
250 )]
251 impl<'a, 'f: 'a> Deref for VaList<'a, 'f> {
252 type Target = VaListImpl<'f>;
253
254 #[inline]
255 fn deref(&self) -> &VaListImpl<'f> {
256 &self.inner
257 }
258 }
259
260 #[unstable(
261 feature = "c_variadic",
262 reason = "the `c_variadic` feature has not been properly tested on \
263 all supported platforms",
264 issue = "44930"
265 )]
266 impl<'a, 'f: 'a> DerefMut for VaList<'a, 'f> {
267 #[inline]
268 fn deref_mut(&mut self) -> &mut VaListImpl<'f> {
269 &mut self.inner
270 }
271 }
272
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.
277 //
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
281 // improving this.
282 mod sealed_trait {
283 /// Trait which whitelists the allowed types to be used with [VaList::arg]
284 ///
285 /// [VaList::va_arg]: struct.VaList.html#method.arg
286 #[unstable(
287 feature = "c_variadic",
288 reason = "the `c_variadic` feature has not been properly tested on \
289 all supported platforms",
290 issue = "44930"
291 )]
292 pub trait VaArgSafe {}
293 }
294
295 macro_rules! impl_va_arg_safe {
296 ($($t:ty),+) => {
297 $(
298 #[unstable(feature = "c_variadic",
299 reason = "the `c_variadic` feature has not been properly tested on \
300 all supported platforms",
301 issue = "44930")]
302 impl sealed_trait::VaArgSafe for $t {}
303 )+
304 }
305 }
306
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}
310
311 #[unstable(
312 feature = "c_variadic",
313 reason = "the `c_variadic` feature has not been properly tested on \
314 all supported platforms",
315 issue = "44930"
316 )]
317 impl<T> sealed_trait::VaArgSafe for *mut T {}
318 #[unstable(
319 feature = "c_variadic",
320 reason = "the `c_variadic` feature has not been properly tested on \
321 all supported platforms",
322 issue = "44930"
323 )]
324 impl<T> sealed_trait::VaArgSafe for *const T {}
325
326 #[unstable(
327 feature = "c_variadic",
328 reason = "the `c_variadic` feature has not been properly tested on \
329 all supported platforms",
330 issue = "44930"
331 )]
332 impl<'f> VaListImpl<'f> {
333 /// Advance to the next arg.
334 #[inline]
335 pub unsafe fn arg<T: sealed_trait::VaArgSafe>(&mut self) -> T {
336 va_arg(self)
337 }
338
339 /// Copies the `va_list` at the current location.
340 pub unsafe fn with_copy<F, R>(&self, f: F) -> R
341 where
342 F: for<'copy> FnOnce(VaList<'copy, 'f>) -> R,
343 {
344 let mut ap = self.clone();
345 let ret = f(ap.as_va_list());
346 va_end(&mut ap);
347 ret
348 }
349 }
350
351 #[unstable(
352 feature = "c_variadic",
353 reason = "the `c_variadic` feature has not been properly tested on \
354 all supported platforms",
355 issue = "44930"
356 )]
357 impl<'f> Clone for VaListImpl<'f> {
358 #[inline]
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
362 unsafe {
363 va_copy(dest.as_mut_ptr(), self);
364 dest.assume_init()
365 }
366 }
367 }
368
369 #[unstable(
370 feature = "c_variadic",
371 reason = "the `c_variadic` feature has not been properly tested on \
372 all supported platforms",
373 issue = "44930"
374 )]
375 impl<'f> Drop for VaListImpl<'f> {
376 fn drop(&mut self) {
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.
385 //
386 // This works for now, since `va_end` is a no-op on all current LLVM targets.
387 }
388 }
389
390 extern "rust-intrinsic" {
391 /// Destroy the arglist `ap` after initialization with `va_start` or
392 /// `va_copy`.
393 fn va_end(ap: &mut VaListImpl<'_>);
394
395 /// Copies the current location of arglist `src` to the arglist `dst`.
396 fn va_copy<'f>(dest: *mut VaListImpl<'f>, src: &VaListImpl<'f>);
397
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;
401 }