@@ -268,35 +268,73 @@ mod sealed_trait {
268268 reason = "the `c_variadic` feature has not been properly tested on \
269269 all supported platforms",
270270 issue = "44930" ) ]
271- pub trait VaArgSafe { }
271+ pub trait VaArgSafe {
272+ #[ doc( hidden) ]
273+ unsafe fn va_arg ( ap : & mut super :: VaListImpl < ' _ > ) -> Self ;
274+ }
272275}
273276
274- macro_rules! impl_va_arg_safe {
277+ macro_rules! impl_va_arg_safe_integer {
275278 ( $( $t: ty) ,+) => {
276279 $(
277280 #[ unstable( feature = "c_variadic" ,
278281 reason = "the `c_variadic` feature has not been properly tested on \
279282 all supported platforms",
280283 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+ }
282292 ) +
283293 }
284294}
285295
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+ }
289314
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 }
300338
301339#[ unstable( feature = "c_variadic" ,
302340 reason = "the `c_variadic` feature has not been properly tested on \
@@ -306,7 +344,7 @@ impl<'f> VaListImpl<'f> {
306344 /// Advance to the next arg.
307345 #[ inline]
308346 pub unsafe fn arg < T : sealed_trait:: VaArgSafe > ( & mut self ) -> T {
309- va_arg ( self )
347+ T :: va_arg ( self )
310348 }
311349
312350 /// Copies the `va_list` at the current location.
@@ -363,5 +401,64 @@ extern "rust-intrinsic" {
363401
364402 /// Loads an argument of type `T` from the `va_list` `ap` and increment the
365403 /// argument `ap` points to.
404+ #[ cfg( not( all( target_arch = "aarch64" , not( target_os = "ios" ) , not( windows) ) ) ) ]
366405 fn va_arg < T : sealed_trait:: VaArgSafe > ( ap : & mut VaListImpl < ' _ > ) -> T ;
367406}
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