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
52
not( target_arch = "x86_64" ) ) ,
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
67
not( target_arch = "x86_64" ) ) ,
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,99 @@ 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
137
/// A wrapper for a `va_list`
122
- #[ lang = "va_list" ]
138
+ #[ repr ( transparent ) ]
123
139
#[ derive( Debug ) ]
124
140
#[ unstable( feature = "c_variadic" ,
125
141
reason = "the `c_variadic` feature has not been properly tested on \
126
142
all supported platforms",
127
143
issue = "44930" ) ]
128
- #[ repr( transparent) ]
129
- pub struct VaList < ' a > ( & ' a mut VaListImpl ) ;
144
+ pub struct VaList < ' a , ' f : ' a > {
145
+ #[ cfg( any( all( not( target_arch = "aarch64" ) , not( target_arch = "powerpc" ) ,
146
+ not( target_arch = "x86_64" ) ) ,
147
+ all( target_arch = "aarch64" , target_os = "ios" ) ,
148
+ windows) ) ]
149
+ inner : VaListImpl < ' f > ,
150
+
151
+ #[ cfg( all( any( target_arch = "aarch64" , target_arch = "powerpc" ,
152
+ target_arch = "x86_64" ) ,
153
+ any( not( target_arch = "aarch64" ) , not( target_os = "ios" ) ) ,
154
+ not( windows) ) ) ]
155
+ inner : & ' a mut VaListImpl < ' f > ,
156
+
157
+ _marker : PhantomData < & ' a mut VaListImpl < ' f > > ,
158
+ }
159
+
160
+ #[ cfg( any( all( not( target_arch = "aarch64" ) , not( target_arch = "powerpc" ) ,
161
+ not( target_arch = "x86_64" ) ) ,
162
+ all( target_arch = "aarch64" , target_os = "ios" ) ,
163
+ windows) ) ]
164
+ #[ unstable( feature = "c_variadic" ,
165
+ reason = "the `c_variadic` feature has not been properly tested on \
166
+ all supported platforms",
167
+ issue = "44930" ) ]
168
+ impl < ' f > VaListImpl < ' f > {
169
+ /// Convert a `VaListImpl` into a `VaList` that is binary-compatible with C's `va_list`.
170
+ #[ inline]
171
+ pub fn as_va_list < ' a > ( & ' a mut self ) -> VaList < ' a , ' f > {
172
+ VaList {
173
+ inner : VaListImpl { ..* self } ,
174
+ _marker : PhantomData ,
175
+ }
176
+ }
177
+ }
178
+
179
+ #[ cfg( all( any( target_arch = "aarch64" , target_arch = "powerpc" ,
180
+ target_arch = "x86_64" ) ,
181
+ any( not( target_arch = "aarch64" ) , not( target_os = "ios" ) ) ,
182
+ not( windows) ) ) ]
183
+ #[ unstable( feature = "c_variadic" ,
184
+ reason = "the `c_variadic` feature has not been properly tested on \
185
+ all supported platforms",
186
+ issue = "44930" ) ]
187
+ impl < ' f > VaListImpl < ' f > {
188
+ /// Convert a `VaListImpl` into a `VaList` that is binary-compatible with C's `va_list`.
189
+ #[ inline]
190
+ pub fn as_va_list < ' a > ( & ' a mut self ) -> VaList < ' a , ' f > {
191
+ VaList {
192
+ inner : self ,
193
+ _marker : PhantomData ,
194
+ }
195
+ }
196
+ }
197
+
198
+ #[ unstable( feature = "c_variadic" ,
199
+ reason = "the `c_variadic` feature has not been properly tested on \
200
+ all supported platforms",
201
+ issue = "44930" ) ]
202
+ impl < ' a , ' f : ' a > Deref for VaList < ' a , ' f > {
203
+ type Target = VaListImpl < ' f > ;
204
+
205
+ #[ inline]
206
+ fn deref ( & self ) -> & VaListImpl < ' f > {
207
+ & self . inner
208
+ }
209
+ }
210
+
211
+ #[ unstable( feature = "c_variadic" ,
212
+ reason = "the `c_variadic` feature has not been properly tested on \
213
+ all supported platforms",
214
+ issue = "44930" ) ]
215
+ impl < ' a , ' f : ' a > DerefMut for VaList < ' a , ' f > {
216
+ #[ inline]
217
+ fn deref_mut ( & mut self ) -> & mut VaListImpl < ' f > {
218
+ & mut self . inner
219
+ }
220
+ }
130
221
131
222
// The VaArgSafe trait needs to be used in public interfaces, however, the trait
132
223
// itself must not be allowed to be used outside this module. Allowing users to
@@ -175,56 +266,76 @@ impl<T> sealed_trait::VaArgSafe for *mut T {}
175
266
issue = "44930" ) ]
176
267
impl < T > sealed_trait:: VaArgSafe for * const T { }
177
268
178
- impl < ' a > VaList < ' a > {
269
+ #[ unstable( feature = "c_variadic" ,
270
+ reason = "the `c_variadic` feature has not been properly tested on \
271
+ all supported platforms",
272
+ issue = "44930" ) ]
273
+ #[ cfg( not( stage0) ) ]
274
+ impl < ' f > VaListImpl < ' f > {
179
275
/// 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" ) ]
276
+ #[ inline]
184
277
pub unsafe fn arg < T : sealed_trait:: VaArgSafe > ( & mut self ) -> T {
185
278
va_arg ( self )
186
279
}
187
280
188
281
/// 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
282
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 ) ) ;
283
+ where F : for < ' copy > FnOnce ( VaList < ' copy , ' f > ) -> R {
284
+ let mut ap = self . clone ( ) ;
285
+ let ret = f ( ap. as_va_list ( ) ) ;
207
286
va_end ( & mut ap) ;
208
287
ret
209
288
}
210
289
}
211
290
291
+ #[ unstable( feature = "c_variadic" ,
292
+ reason = "the `c_variadic` feature has not been properly tested on \
293
+ all supported platforms",
294
+ issue = "44930" ) ]
295
+ #[ cfg( not( stage0) ) ]
296
+ impl < ' f > Clone for VaListImpl < ' f > {
297
+ #[ inline]
298
+ fn clone ( & self ) -> Self {
299
+ let mut dest = crate :: mem:: MaybeUninit :: uninit ( ) ;
300
+ unsafe {
301
+ va_copy ( dest. as_mut_ptr ( ) , self ) ;
302
+ dest. assume_init ( )
303
+ }
304
+ }
305
+ }
306
+
307
+ #[ unstable( feature = "c_variadic" ,
308
+ reason = "the `c_variadic` feature has not been properly tested on \
309
+ all supported platforms",
310
+ issue = "44930" ) ]
311
+ #[ cfg( not( stage0) ) ]
312
+ impl < ' f > Drop for VaListImpl < ' f > {
313
+ fn drop ( & mut self ) {
314
+ // FIXME: this should call `va_end`, but there's no clean way to
315
+ // guarantee that `drop` always gets inlined into its caller,
316
+ // so the `va_end` would get directly called from the same function as
317
+ // the corresponding `va_copy`. `man va_end` states that C requires this,
318
+ // and LLVM basically follows the C semantics, so we need to make sure
319
+ // that `va_end` is always called from the same function as `va_copy`.
320
+ // For more details, see https://github.com/rust-lang/rust/pull/59625
321
+ // and https://llvm.org/docs/LangRef.html#llvm-va-end-intrinsic.
322
+ //
323
+ // This works for now, since `va_end` is a no-op on all current LLVM targets.
324
+ }
325
+ }
326
+
212
327
extern "rust-intrinsic" {
213
328
/// Destroy the arglist `ap` after initialization with `va_start` or
214
329
/// `va_copy`.
215
- fn va_end ( ap : & mut VaList < ' _ > ) ;
330
+ #[ cfg( not( stage0) ) ]
331
+ fn va_end ( ap : & mut VaListImpl < ' _ > ) ;
216
332
217
333
/// 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 ;
334
+ #[ cfg( not( stage0) ) ]
335
+ fn va_copy < ' f > ( dest : * mut VaListImpl < ' f > , src : & VaListImpl < ' f > ) ;
226
336
227
337
/// Loads an argument of type `T` from the `va_list` `ap` and increment the
228
338
/// argument `ap` points to.
229
- fn va_arg < T : sealed_trait:: VaArgSafe > ( ap : & mut VaList < ' _ > ) -> T ;
339
+ #[ cfg( not( stage0) ) ]
340
+ fn va_arg < T : sealed_trait:: VaArgSafe > ( ap : & mut VaListImpl < ' _ > ) -> T ;
230
341
}
0 commit comments