]>
Commit | Line | Data |
---|---|---|
b7449926 XL |
1 | #![stable(feature = "", since = "1.30.0")] |
2 | ||
3 | #![allow(non_camel_case_types)] | |
4 | ||
5 | //! Utilities related to FFI bindings. | |
6 | ||
7 | use ::fmt; | |
8 | ||
9 | /// Equivalent to C's `void` type when used as a [pointer]. | |
10 | /// | |
11 | /// In essence, `*const c_void` is equivalent to C's `const void*` | |
12 | /// and `*mut c_void` is equivalent to C's `void*`. That said, this is | |
13 | /// *not* the same as C's `void` return type, which is Rust's `()` type. | |
14 | /// | |
9fa01778 XL |
15 | /// To model pointers to opaque types in FFI, until `extern type` is |
16 | /// stabilized, it is recommended to use a newtype wrapper around an empty | |
17 | /// byte array. See the [Nomicon] for details. | |
b7449926 | 18 | /// |
b7449926 | 19 | /// [pointer]: ../../std/primitive.pointer.html |
9fa01778 | 20 | /// [Nomicon]: https://doc.rust-lang.org/nomicon/ffi.html#representing-opaque-structs |
0731742a | 21 | // N.B., for LLVM to recognize the void pointer type and by extension |
b7449926 XL |
22 | // functions like malloc(), we need to have it represented as i8* in |
23 | // LLVM bitcode. The enum used here ensures this and prevents misuse | |
9fa01778 | 24 | // of the "raw" type by only having private variants. We need two |
b7449926 | 25 | // variants, because the compiler complains about the repr attribute |
9fa01778 XL |
26 | // otherwise and we need at least one variant as otherwise the enum |
27 | // would be uninhabited and at least dereferencing such pointers would | |
28 | // be UB. | |
b7449926 XL |
29 | #[repr(u8)] |
30 | #[stable(feature = "raw_os", since = "1.1.0")] | |
31 | pub enum c_void { | |
9fa01778 | 32 | #[unstable(feature = "c_void_variant", reason = "temporary implementation detail", |
b7449926 XL |
33 | issue = "0")] |
34 | #[doc(hidden)] __variant1, | |
9fa01778 | 35 | #[unstable(feature = "c_void_variant", reason = "temporary implementation detail", |
b7449926 XL |
36 | issue = "0")] |
37 | #[doc(hidden)] __variant2, | |
38 | } | |
39 | ||
40 | #[stable(feature = "std_debug", since = "1.16.0")] | |
41 | impl fmt::Debug for c_void { | |
42 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | |
43 | f.pad("c_void") | |
44 | } | |
45 | } | |
a1dfa0c6 XL |
46 | |
47 | /// Basic implementation of a `va_list`. | |
48 | #[cfg(any(all(not(target_arch = "aarch64"), not(target_arch = "powerpc"), | |
49 | not(target_arch = "x86_64")), | |
0731742a | 50 | all(target_arch = "aarch4", target_os = "ios"), |
a1dfa0c6 XL |
51 | windows))] |
52 | #[unstable(feature = "c_variadic", | |
53 | reason = "the `c_variadic` feature has not been properly tested on \ | |
54 | all supported platforms", | |
9fa01778 | 55 | issue = "44930")] |
a1dfa0c6 XL |
56 | extern { |
57 | type VaListImpl; | |
58 | } | |
59 | ||
60 | #[cfg(any(all(not(target_arch = "aarch64"), not(target_arch = "powerpc"), | |
61 | not(target_arch = "x86_64")), | |
62 | windows))] | |
63 | impl fmt::Debug for VaListImpl { | |
64 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | |
65 | write!(f, "va_list* {:p}", self) | |
66 | } | |
67 | } | |
68 | ||
69 | /// AArch64 ABI implementation of a `va_list`. See the | |
70 | /// [Aarch64 Procedure Call Standard] for more details. | |
71 | /// | |
72 | /// [AArch64 Procedure Call Standard]: | |
73 | /// http://infocenter.arm.com/help/topic/com.arm.doc.ihi0055b/IHI0055B_aapcs64.pdf | |
74 | #[cfg(all(target_arch = "aarch64", not(windows)))] | |
75 | #[repr(C)] | |
76 | #[derive(Debug)] | |
77 | #[unstable(feature = "c_variadic", | |
78 | reason = "the `c_variadic` feature has not been properly tested on \ | |
79 | all supported platforms", | |
9fa01778 | 80 | issue = "44930")] |
a1dfa0c6 XL |
81 | struct VaListImpl { |
82 | stack: *mut (), | |
83 | gr_top: *mut (), | |
84 | vr_top: *mut (), | |
85 | gr_offs: i32, | |
86 | vr_offs: i32, | |
87 | } | |
88 | ||
89 | /// PowerPC ABI implementation of a `va_list`. | |
90 | #[cfg(all(target_arch = "powerpc", not(windows)))] | |
91 | #[repr(C)] | |
92 | #[derive(Debug)] | |
93 | #[unstable(feature = "c_variadic", | |
94 | reason = "the `c_variadic` feature has not been properly tested on \ | |
95 | all supported platforms", | |
9fa01778 | 96 | issue = "44930")] |
a1dfa0c6 XL |
97 | struct VaListImpl { |
98 | gpr: u8, | |
99 | fpr: u8, | |
100 | reserved: u16, | |
101 | overflow_arg_area: *mut (), | |
102 | reg_save_area: *mut (), | |
103 | } | |
104 | ||
105 | /// x86_64 ABI implementation of a `va_list`. | |
106 | #[cfg(all(target_arch = "x86_64", not(windows)))] | |
107 | #[repr(C)] | |
108 | #[derive(Debug)] | |
109 | #[unstable(feature = "c_variadic", | |
110 | reason = "the `c_variadic` feature has not been properly tested on \ | |
111 | all supported platforms", | |
9fa01778 | 112 | issue = "44930")] |
a1dfa0c6 XL |
113 | struct VaListImpl { |
114 | gp_offset: i32, | |
115 | fp_offset: i32, | |
116 | overflow_arg_area: *mut (), | |
117 | reg_save_area: *mut (), | |
118 | } | |
119 | ||
120 | /// A wrapper for a `va_list` | |
121 | #[lang = "va_list"] | |
122 | #[derive(Debug)] | |
123 | #[unstable(feature = "c_variadic", | |
124 | reason = "the `c_variadic` feature has not been properly tested on \ | |
125 | all supported platforms", | |
9fa01778 | 126 | issue = "44930")] |
a1dfa0c6 | 127 | #[repr(transparent)] |
a1dfa0c6 XL |
128 | pub struct VaList<'a>(&'a mut VaListImpl); |
129 | ||
130 | // The VaArgSafe trait needs to be used in public interfaces, however, the trait | |
131 | // itself must not be allowed to be used outside this module. Allowing users to | |
132 | // implement the trait for a new type (thereby allowing the va_arg intrinsic to | |
133 | // be used on a new type) is likely to cause undefined behavior. | |
134 | // | |
135 | // FIXME(dlrobertson): In order to use the VaArgSafe trait in a public interface | |
136 | // but also ensure it cannot be used elsewhere, the trait needs to be public | |
137 | // within a private module. Once RFC 2145 has been implemented look into | |
138 | // improving this. | |
139 | mod sealed_trait { | |
140 | /// Trait which whitelists the allowed types to be used with [VaList::arg] | |
141 | /// | |
142 | /// [VaList::va_arg]: struct.VaList.html#method.arg | |
143 | #[unstable(feature = "c_variadic", | |
144 | reason = "the `c_variadic` feature has not been properly tested on \ | |
145 | all supported platforms", | |
9fa01778 | 146 | issue = "44930")] |
a1dfa0c6 XL |
147 | pub trait VaArgSafe {} |
148 | } | |
149 | ||
150 | macro_rules! impl_va_arg_safe { | |
151 | ($($t:ty),+) => { | |
152 | $( | |
153 | #[unstable(feature = "c_variadic", | |
154 | reason = "the `c_variadic` feature has not been properly tested on \ | |
155 | all supported platforms", | |
9fa01778 | 156 | issue = "44930")] |
a1dfa0c6 XL |
157 | impl sealed_trait::VaArgSafe for $t {} |
158 | )+ | |
159 | } | |
160 | } | |
161 | ||
162 | impl_va_arg_safe!{i8, i16, i32, i64, usize} | |
163 | impl_va_arg_safe!{u8, u16, u32, u64, isize} | |
164 | impl_va_arg_safe!{f64} | |
165 | ||
166 | #[unstable(feature = "c_variadic", | |
167 | reason = "the `c_variadic` feature has not been properly tested on \ | |
168 | all supported platforms", | |
9fa01778 | 169 | issue = "44930")] |
a1dfa0c6 XL |
170 | impl<T> sealed_trait::VaArgSafe for *mut T {} |
171 | #[unstable(feature = "c_variadic", | |
172 | reason = "the `c_variadic` feature has not been properly tested on \ | |
173 | all supported platforms", | |
9fa01778 | 174 | issue = "44930")] |
a1dfa0c6 XL |
175 | impl<T> sealed_trait::VaArgSafe for *const T {} |
176 | ||
a1dfa0c6 XL |
177 | impl<'a> VaList<'a> { |
178 | /// Advance to the next arg. | |
179 | #[unstable(feature = "c_variadic", | |
180 | reason = "the `c_variadic` feature has not been properly tested on \ | |
181 | all supported platforms", | |
9fa01778 | 182 | issue = "44930")] |
a1dfa0c6 XL |
183 | pub unsafe fn arg<T: sealed_trait::VaArgSafe>(&mut self) -> T { |
184 | va_arg(self) | |
185 | } | |
186 | ||
9fa01778 | 187 | /// Copies the `va_list` at the current location. |
a1dfa0c6 XL |
188 | #[unstable(feature = "c_variadic", |
189 | reason = "the `c_variadic` feature has not been properly tested on \ | |
190 | all supported platforms", | |
9fa01778 | 191 | issue = "44930")] |
0731742a | 192 | pub unsafe fn copy<F, R>(&self, f: F) -> R |
a1dfa0c6 XL |
193 | where F: for<'copy> FnOnce(VaList<'copy>) -> R { |
194 | #[cfg(any(all(not(target_arch = "aarch64"), not(target_arch = "powerpc"), | |
195 | not(target_arch = "x86_64")), | |
0731742a | 196 | all(target_arch = "aarch4", target_os = "ios"), |
a1dfa0c6 XL |
197 | windows))] |
198 | let mut ap = va_copy(self); | |
199 | #[cfg(all(any(target_arch = "aarch64", target_arch = "powerpc", target_arch = "x86_64"), | |
200 | not(windows)))] | |
201 | let mut ap_inner = va_copy(self); | |
202 | #[cfg(all(any(target_arch = "aarch64", target_arch = "powerpc", target_arch = "x86_64"), | |
203 | not(windows)))] | |
204 | let mut ap = VaList(&mut ap_inner); | |
205 | let ret = f(VaList(ap.0)); | |
206 | va_end(&mut ap); | |
207 | ret | |
208 | } | |
209 | } | |
210 | ||
a1dfa0c6 XL |
211 | extern "rust-intrinsic" { |
212 | /// Destroy the arglist `ap` after initialization with `va_start` or | |
213 | /// `va_copy`. | |
214 | fn va_end(ap: &mut VaList); | |
215 | ||
9fa01778 | 216 | /// Copies the current location of arglist `src` to the arglist `dst`. |
a1dfa0c6 XL |
217 | #[cfg(any(all(not(target_arch = "aarch64"), not(target_arch = "powerpc"), |
218 | not(target_arch = "x86_64")), | |
219 | windows))] | |
220 | fn va_copy<'a>(src: &VaList<'a>) -> VaList<'a>; | |
221 | #[cfg(all(any(target_arch = "aarch64", target_arch = "powerpc", target_arch = "x86_64"), | |
222 | not(windows)))] | |
223 | fn va_copy(src: &VaList) -> VaListImpl; | |
224 | ||
225 | /// Loads an argument of type `T` from the `va_list` `ap` and increment the | |
226 | /// argument `ap` points to. | |
227 | fn va_arg<T: sealed_trait::VaArgSafe>(ap: &mut VaList) -> T; | |
228 | } |