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