@@ -268,35 +268,73 @@ mod sealed_trait {
268
268
reason = "the `c_variadic` feature has not been properly tested on \
269
269
all supported platforms",
270
270
issue = "44930" ) ]
271
- pub trait VaArgSafe { }
271
+ pub trait VaArgSafe {
272
+ #[ doc( hidden) ]
273
+ unsafe fn va_arg ( ap : & mut super :: VaListImpl < ' _ > ) -> Self ;
274
+ }
272
275
}
273
276
274
- macro_rules! impl_va_arg_safe {
277
+ macro_rules! impl_va_arg_safe_integer {
275
278
( $( $t: ty) ,+) => {
276
279
$(
277
280
#[ unstable( feature = "c_variadic" ,
278
281
reason = "the `c_variadic` feature has not been properly tested on \
279
282
all supported platforms",
280
283
issue = "44930" ) ]
281
- impl sealed_trait:: VaArgSafe for $t { }
284
+ impl sealed_trait:: VaArgSafe for $t {
285
+ unsafe fn va_arg( ap: & mut VaListImpl <' _>) -> Self {
286
+ #[ cfg( not( all( target_arch = "aarch64" , not( target_os = "ios" ) , not( windows) ) ) ) ]
287
+ return va_arg( ap) ;
288
+ #[ cfg( all( target_arch = "aarch64" , not( target_os = "ios" ) , not( windows) ) ) ]
289
+ return ap. va_arg_gr( ) ;
290
+ }
291
+ }
282
292
) +
283
293
}
284
294
}
285
295
286
- impl_va_arg_safe ! { i8 , i16 , i32 , i64 , usize }
287
- impl_va_arg_safe ! { u8 , u16 , u32 , u64 , isize }
288
- impl_va_arg_safe ! { f64 }
296
+ macro_rules! impl_va_arg_safe_float {
297
+ ( $( $t: ty) ,+) => {
298
+ $(
299
+ #[ unstable( feature = "c_variadic" ,
300
+ reason = "the `c_variadic` feature has not been properly tested on \
301
+ all supported platforms",
302
+ issue = "44930" ) ]
303
+ impl sealed_trait:: VaArgSafe for $t {
304
+ unsafe fn va_arg( ap: & mut VaListImpl <' _>) -> Self {
305
+ #[ cfg( not( all( target_arch = "aarch64" , not( target_os = "ios" ) , not( windows) ) ) ) ]
306
+ return va_arg( ap) ;
307
+ #[ cfg( all( target_arch = "aarch64" , not( target_os = "ios" ) , not( windows) ) ) ]
308
+ return ap. va_arg_vr( ) ;
309
+ }
310
+ }
311
+ ) +
312
+ }
313
+ }
289
314
290
- #[ unstable( feature = "c_variadic" ,
291
- reason = "the `c_variadic` feature has not been properly tested on \
292
- all supported platforms",
293
- issue = "44930" ) ]
294
- impl < T > sealed_trait:: VaArgSafe for * mut T { }
295
- #[ unstable( feature = "c_variadic" ,
296
- reason = "the `c_variadic` feature has not been properly tested on \
297
- all supported platforms",
298
- issue = "44930" ) ]
299
- impl < T > sealed_trait:: VaArgSafe for * const T { }
315
+ macro_rules! impl_va_arg_safe_pointer {
316
+ ( $( $t: ident) ,+) => {
317
+ $(
318
+ #[ unstable( feature = "c_variadic" ,
319
+ reason = "the `c_variadic` feature has not been properly tested on \
320
+ all supported platforms",
321
+ issue = "44930" ) ]
322
+ impl <T > sealed_trait:: VaArgSafe for * $t T {
323
+ unsafe fn va_arg( ap: & mut VaListImpl <' _>) -> Self {
324
+ #[ cfg( not( all( target_arch = "aarch64" , not( target_os = "ios" ) , not( windows) ) ) ) ]
325
+ return va_arg( ap) ;
326
+ #[ cfg( all( target_arch = "aarch64" , not( target_os = "ios" ) , not( windows) ) ) ]
327
+ return ap. va_arg_gr( ) ;
328
+ }
329
+ }
330
+ ) +
331
+ }
332
+ }
333
+
334
+ impl_va_arg_safe_integer ! { i8 , i16 , i32 , i64 , usize }
335
+ impl_va_arg_safe_integer ! { u8 , u16 , u32 , u64 , isize }
336
+ impl_va_arg_safe_float ! { f64 }
337
+ impl_va_arg_safe_pointer ! { mut , const }
300
338
301
339
#[ unstable( feature = "c_variadic" ,
302
340
reason = "the `c_variadic` feature has not been properly tested on \
@@ -306,7 +344,7 @@ impl<'f> VaListImpl<'f> {
306
344
/// Advance to the next arg.
307
345
#[ inline]
308
346
pub unsafe fn arg < T : sealed_trait:: VaArgSafe > ( & mut self ) -> T {
309
- va_arg ( self )
347
+ T :: va_arg ( self )
310
348
}
311
349
312
350
/// Copies the `va_list` at the current location.
@@ -363,5 +401,64 @@ extern "rust-intrinsic" {
363
401
364
402
/// Loads an argument of type `T` from the `va_list` `ap` and increment the
365
403
/// argument `ap` points to.
404
+ #[ cfg( not( all( target_arch = "aarch64" , not( target_os = "ios" ) , not( windows) ) ) ) ]
366
405
fn va_arg < T : sealed_trait:: VaArgSafe > ( ap : & mut VaListImpl < ' _ > ) -> T ;
367
406
}
407
+
408
+ #[ cfg( all( target_arch = "aarch64" , not( target_os = "ios" ) , not( windows) ) ) ]
409
+ use crate :: { mem, ptr} ;
410
+
411
+ // Implemenation for AArch64 linux (and others that follow the standard PCS)
412
+ // based on https://developer.arm.com/docs/ihi0055/d/procedure-call-standard-for-the-arm-64-bit-architecture
413
+ // APPENDIX Variable argument Lists -> The va_start() macro
414
+ #[ cfg( all( target_arch = "aarch64" , not( target_os = "ios" ) , not( windows) ) ) ]
415
+ impl < ' f > VaListImpl < ' f > {
416
+ unsafe fn get_begin_and_end < T > ( current_pos : usize , reg_size : usize ) -> ( usize , usize ) {
417
+ let mut begin = current_pos;
418
+ if mem:: align_of :: < T > ( ) > 8 && reg_size == 8 {
419
+ begin = begin. wrapping_add ( 15 ) & !15 ; // round up
420
+ }
421
+ let nreg = ( mem:: size_of :: < T > ( ) + reg_size - 1 ) / reg_size;
422
+ let end = begin. wrapping_add ( nreg * reg_size) ;
423
+ #[ cfg( target_endian = "big" ) ]
424
+ {
425
+ if
426
+ /* classof(type) != "aggregate" && */
427
+ mem:: size_of :: < T > ( ) < reg_size {
428
+ begin = begin. wrapping_add ( reg_size - mem:: size_of :: < T > ( ) ) ;
429
+ }
430
+ }
431
+ ( begin, end)
432
+ }
433
+
434
+ unsafe fn va_arg_on_stack < T : sealed_trait:: VaArgSafe > ( stack : & mut * mut c_void ) -> T {
435
+ let ( begin, end) = Self :: get_begin_and_end :: < T > ( * stack as usize , 8 ) ;
436
+ * stack = end as * mut c_void ;
437
+ ptr:: read ( begin as * const T )
438
+ }
439
+
440
+ unsafe fn va_arg_gr_or_vr < T : sealed_trait:: VaArgSafe > (
441
+ r_top : * mut c_void ,
442
+ r_offs : & mut i32 ,
443
+ stack : & mut * mut c_void ,
444
+ reg_size : usize ,
445
+ ) -> T {
446
+ if * r_offs >= 0 {
447
+ return Self :: va_arg_on_stack ( stack) ; // reg save area empty
448
+ }
449
+ let ( begin, end) = Self :: get_begin_and_end :: < T > ( * r_offs as usize , reg_size) ;
450
+ * r_offs = end as i32 ;
451
+ if * r_offs > 0 {
452
+ return Self :: va_arg_on_stack ( stack) ; // overflowed reg save area
453
+ }
454
+ ptr:: read ( ( r_top as usize ) . wrapping_add ( begin) as * const T )
455
+ }
456
+
457
+ unsafe fn va_arg_gr < T : sealed_trait:: VaArgSafe > ( & mut self ) -> T {
458
+ Self :: va_arg_gr_or_vr ( self . gr_top , & mut self . gr_offs , & mut self . stack , 8 )
459
+ }
460
+
461
+ unsafe fn va_arg_vr < T : sealed_trait:: VaArgSafe > ( & mut self ) -> T {
462
+ Self :: va_arg_gr_or_vr ( self . vr_top , & mut self . vr_offs , & mut self . stack , 16 )
463
+ }
464
+ }
0 commit comments