5
5
//! Utilities related to FFI bindings.
6
6
7
7
use crate :: fmt;
8
+ use crate :: marker:: PhantomData ;
9
+ use crate :: ops:: { Deref , DerefMut } ;
8
10
9
11
/// Equivalent to C's `void` type when used as a [pointer].
10
12
///
@@ -45,25 +47,33 @@ impl fmt::Debug for c_void {
45
47
}
46
48
47
49
/// Basic implementation of a `va_list`.
50
+ // The name is WIP, using `VaListImpl` for now.
48
51
#[ cfg( any( all( not( target_arch = "aarch64" ) , not( target_arch = "powerpc" ) ,
49
- not( target_arch = "x86_64" ) ) ,
52
+ not( target_arch = "x86_64" ) , not ( target_arch = "asmjs" ) ) ,
50
53
all( target_arch = "aarch64" , target_os = "ios" ) ,
51
54
windows) ) ]
55
+ #[ repr( transparent) ]
52
56
#[ unstable( feature = "c_variadic" ,
53
57
reason = "the `c_variadic` feature has not been properly tested on \
54
58
all supported platforms",
55
59
issue = "44930" ) ]
56
- extern {
57
- type VaListImpl ;
60
+ #[ lang = "va_list" ]
61
+ pub struct VaListImpl < ' f > {
62
+ ptr : * mut c_void ,
63
+ _marker : PhantomData < & ' f c_void > ,
58
64
}
59
65
60
66
#[ cfg( any( all( not( target_arch = "aarch64" ) , not( target_arch = "powerpc" ) ,
61
- not( target_arch = "x86_64" ) ) ,
67
+ not( target_arch = "x86_64" ) , not ( target_arch = "asmjs" ) ) ,
62
68
all( target_arch = "aarch64" , target_os = "ios" ) ,
63
69
windows) ) ]
64
- impl fmt:: Debug for VaListImpl {
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 > {
65
75
fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
66
- write ! ( f, "va_list* {:p}" , self )
76
+ write ! ( f, "va_list* {:p}" , self . ptr )
67
77
}
68
78
}
69
79
@@ -79,12 +89,14 @@ impl fmt::Debug for VaListImpl {
79
89
reason = "the `c_variadic` feature has not been properly tested on \
80
90
all supported platforms",
81
91
issue = "44930" ) ]
82
- struct VaListImpl {
92
+ #[ lang = "va_list" ]
93
+ pub struct VaListImpl < ' f > {
83
94
stack : * mut c_void ,
84
95
gr_top : * mut c_void ,
85
96
vr_top : * mut c_void ,
86
97
gr_offs : i32 ,
87
98
vr_offs : i32 ,
99
+ _marker : PhantomData < & ' f c_void > ,
88
100
}
89
101
90
102
/// PowerPC ABI implementation of a `va_list`.
@@ -95,12 +107,14 @@ struct VaListImpl {
95
107
reason = "the `c_variadic` feature has not been properly tested on \
96
108
all supported platforms",
97
109
issue = "44930" ) ]
98
- struct VaListImpl {
110
+ #[ lang = "va_list" ]
111
+ pub struct VaListImpl < ' f > {
99
112
gpr : u8 ,
100
113
fpr : u8 ,
101
114
reserved : u16 ,
102
115
overflow_arg_area : * mut c_void ,
103
116
reg_save_area : * mut c_void ,
117
+ _marker : PhantomData < & ' f c_void > ,
104
118
}
105
119
106
120
/// x86_64 ABI implementation of a `va_list`.
@@ -111,22 +125,131 @@ struct VaListImpl {
111
125
reason = "the `c_variadic` feature has not been properly tested on \
112
126
all supported platforms",
113
127
issue = "44930" ) ]
114
- struct VaListImpl {
128
+ #[ lang = "va_list" ]
129
+ pub struct VaListImpl < ' f > {
115
130
gp_offset : i32 ,
116
131
fp_offset : i32 ,
117
132
overflow_arg_area : * mut c_void ,
118
133
reg_save_area : * mut c_void ,
134
+ _marker : PhantomData < & ' f c_void > ,
119
135
}
120
136
121
- /// A wrapper for a `va_list`
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" ) ]
122
148
#[ lang = "va_list" ]
123
- #[ derive( Debug ) ]
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) ) ) ]
124
155
#[ unstable( feature = "c_variadic" ,
125
156
reason = "the `c_variadic` feature has not been properly tested on \
126
157
all supported platforms",
127
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`
128
170
#[ repr( transparent) ]
129
- pub struct VaList < ' a > ( & ' a mut VaListImpl ) ;
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
+ }
130
253
131
254
// The VaArgSafe trait needs to be used in public interfaces, however, the trait
132
255
// itself must not be allowed to be used outside this module. Allowing users to
@@ -175,56 +298,76 @@ impl<T> sealed_trait::VaArgSafe for *mut T {}
175
298
issue = "44930" ) ]
176
299
impl < T > sealed_trait:: VaArgSafe for * const T { }
177
300
178
- impl < ' a > VaList < ' a > {
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
+ #[ cfg( not( bootstrap) ) ]
306
+ impl < ' f > VaListImpl < ' f > {
179
307
/// Advance to the next arg.
180
- #[ unstable( feature = "c_variadic" ,
181
- reason = "the `c_variadic` feature has not been properly tested on \
182
- all supported platforms",
183
- issue = "44930" ) ]
308
+ #[ inline]
184
309
pub unsafe fn arg < T : sealed_trait:: VaArgSafe > ( & mut self ) -> T {
185
310
va_arg ( self )
186
311
}
187
312
188
313
/// Copies the `va_list` at the current location.
189
- #[ unstable( feature = "c_variadic" ,
190
- reason = "the `c_variadic` feature has not been properly tested on \
191
- all supported platforms",
192
- issue = "44930" ) ]
193
314
pub unsafe fn with_copy < F , R > ( & self , f : F ) -> R
194
- where F : for < ' copy > FnOnce ( VaList < ' copy > ) -> R {
195
- #[ cfg( any( all( not( target_arch = "aarch64" ) , not( target_arch = "powerpc" ) ,
196
- not( target_arch = "x86_64" ) ) ,
197
- all( target_arch = "aarch64" , target_os = "ios" ) ,
198
- windows) ) ]
199
- let mut ap = va_copy ( self ) ;
200
- #[ cfg( all( any( target_arch = "aarch64" , target_arch = "powerpc" , target_arch = "x86_64" ) ,
201
- not( windows) , not( all( target_arch = "aarch64" , target_os = "ios" ) ) ) ) ]
202
- let mut ap_inner = va_copy ( self ) ;
203
- #[ cfg( all( any( target_arch = "aarch64" , target_arch = "powerpc" , target_arch = "x86_64" ) ,
204
- not( windows) , not( all( target_arch = "aarch64" , target_os = "ios" ) ) ) ) ]
205
- let mut ap = VaList ( & mut ap_inner) ;
206
- let ret = f ( VaList ( ap. 0 ) ) ;
315
+ where F : for < ' copy > FnOnce ( VaList < ' copy , ' f > ) -> R {
316
+ let mut ap = self . clone ( ) ;
317
+ let ret = f ( ap. as_va_list ( ) ) ;
207
318
va_end ( & mut ap) ;
208
319
ret
209
320
}
210
321
}
211
322
323
+ #[ unstable( feature = "c_variadic" ,
324
+ reason = "the `c_variadic` feature has not been properly tested on \
325
+ all supported platforms",
326
+ issue = "44930" ) ]
327
+ #[ cfg( not( bootstrap) ) ]
328
+ impl < ' f > Clone for VaListImpl < ' f > {
329
+ #[ inline]
330
+ fn clone ( & self ) -> Self {
331
+ let mut dest = crate :: mem:: MaybeUninit :: uninit ( ) ;
332
+ unsafe {
333
+ va_copy ( dest. as_mut_ptr ( ) , self ) ;
334
+ dest. assume_init ( )
335
+ }
336
+ }
337
+ }
338
+
339
+ #[ unstable( feature = "c_variadic" ,
340
+ reason = "the `c_variadic` feature has not been properly tested on \
341
+ all supported platforms",
342
+ issue = "44930" ) ]
343
+ #[ cfg( not( bootstrap) ) ]
344
+ impl < ' f > Drop for VaListImpl < ' f > {
345
+ fn drop ( & mut self ) {
346
+ // FIXME: this should call `va_end`, but there's no clean way to
347
+ // guarantee that `drop` always gets inlined into its caller,
348
+ // so the `va_end` would get directly called from the same function as
349
+ // the corresponding `va_copy`. `man va_end` states that C requires this,
350
+ // and LLVM basically follows the C semantics, so we need to make sure
351
+ // that `va_end` is always called from the same function as `va_copy`.
352
+ // For more details, see https://github.com/rust-lang/rust/pull/59625
353
+ // and https://llvm.org/docs/LangRef.html#llvm-va-end-intrinsic.
354
+ //
355
+ // This works for now, since `va_end` is a no-op on all current LLVM targets.
356
+ }
357
+ }
358
+
212
359
extern "rust-intrinsic" {
213
360
/// Destroy the arglist `ap` after initialization with `va_start` or
214
361
/// `va_copy`.
215
- fn va_end ( ap : & mut VaList < ' _ > ) ;
362
+ #[ cfg( not( bootstrap) ) ]
363
+ fn va_end ( ap : & mut VaListImpl < ' _ > ) ;
216
364
217
365
/// Copies the current location of arglist `src` to the arglist `dst`.
218
- #[ cfg( any( all( not( target_arch = "aarch64" ) , not( target_arch = "powerpc" ) ,
219
- not( target_arch = "x86_64" ) ) ,
220
- all( target_arch = "aarch64" , target_os = "ios" ) ,
221
- windows) ) ]
222
- fn va_copy < ' a > ( src : & VaList < ' a > ) -> VaList < ' a > ;
223
- #[ cfg( all( any( target_arch = "aarch64" , target_arch = "powerpc" , target_arch = "x86_64" ) ,
224
- not( windows) , not( all( target_arch = "aarch64" , target_os = "ios" ) ) ) ) ]
225
- fn va_copy ( src : & VaList < ' _ > ) -> VaListImpl ;
366
+ #[ cfg( not( bootstrap) ) ]
367
+ fn va_copy < ' f > ( dest : * mut VaListImpl < ' f > , src : & VaListImpl < ' f > ) ;
226
368
227
369
/// Loads an argument of type `T` from the `va_list` `ap` and increment the
228
370
/// argument `ap` points to.
229
- fn va_arg < T : sealed_trait:: VaArgSafe > ( ap : & mut VaList < ' _ > ) -> T ;
371
+ #[ cfg( not( bootstrap) ) ]
372
+ fn va_arg < T : sealed_trait:: VaArgSafe > ( ap : & mut VaListImpl < ' _ > ) -> T ;
230
373
}
0 commit comments