33//! Better known as "varargs". 
44
55use  crate :: ffi:: c_void; 
6- #[ allow( unused_imports) ]  
76use  crate :: fmt; 
8- use  crate :: intrinsics:: { va_arg,  va_copy,  va_end} ; 
9- use  crate :: marker:: { PhantomData ,  PhantomInvariantLifetime } ; 
10- use  crate :: ops:: { Deref ,  DerefMut } ; 
7+ use  crate :: intrinsics:: { va_arg,  va_copy} ; 
8+ use  crate :: marker:: PhantomCovariantLifetime ; 
119
12- // The name is WIP, using `VaListImpl` for now. 
13- // 
1410// Most targets explicitly specify the layout of `va_list`, this layout is matched here. 
11+ // For `va_list`s which are single-element array in C (and therefore experience array-to-pointer 
12+ // decay when passed as arguments in C), the `VaList` struct is annotated with 
13+ // `#[rustc_pass_indirectly_in_non_rustic_abis]`. This ensures that the compiler uses the correct 
14+ // ABI for functions like `extern "C" fn takes_va_list(va: VaList<'_>)` by passing `va` indirectly. 
1515crate :: cfg_select! { 
1616    all( 
1717        target_arch = "aarch64" , 
@@ -24,68 +24,63 @@ crate::cfg_select! {
2424/// 
2525/// [AArch64 Procedure Call Standard]: 
2626/// http://infocenter.arm.com/help/topic/com.arm.doc.ihi0055b/IHI0055B_aapcs64.pdf 
27- [ cfg_attr ( not ( doc ) ,   repr( C ) ) ]   // work around https://github.com/rust-lang/rust/issues/66401 
27+ [ repr( C ) ] 
2828        #[ derive( Debug ) ] 
29-         #[ lang =  "va_list" ] 
30-         pub   struct  VaListImpl < ' f>  { 
31-             stack:  * mut  c_void, 
32-             gr_top:  * mut  c_void, 
33-             vr_top:  * mut  c_void, 
29+         #[ rustc_pass_indirectly_in_non_rustic_abis ] 
30+         struct  VaListInner  { 
31+             stack:  * const  c_void, 
32+             gr_top:  * const  c_void, 
33+             vr_top:  * const  c_void, 
3434            gr_offs:  i32 , 
3535            vr_offs:  i32 , 
36-             _marker:  PhantomInvariantLifetime <' f>, 
3736        } 
3837    } 
3938    all( target_arch = "powerpc" ,  not( target_os = "uefi" ) ,  not( windows) )  => { 
4039        /// PowerPC ABI implementation of a `va_list`. 
41- [ cfg_attr ( not ( doc ) ,   repr( C ) ) ]   // work around https://github.com/rust-lang/rust/issues/66401 
40+ [ repr( C ) ] 
4241        #[ derive( Debug ) ] 
43-         #[ lang =  "va_list" ] 
44-         pub   struct  VaListImpl < ' f>  { 
42+         #[ rustc_pass_indirectly_in_non_rustic_abis ] 
43+         struct  VaListInner  { 
4544            gpr:  u8 , 
4645            fpr:  u8 , 
4746            reserved:  u16 , 
48-             overflow_arg_area:  * mut  c_void, 
49-             reg_save_area:  * mut  c_void, 
50-             _marker:  PhantomInvariantLifetime <' f>, 
47+             overflow_arg_area:  * const  c_void, 
48+             reg_save_area:  * const  c_void, 
5149        } 
5250    } 
5351    target_arch = "s390x"  => { 
5452        /// s390x ABI implementation of a `va_list`. 
55- [ cfg_attr ( not ( doc ) ,   repr( C ) ) ]   // work around https://github.com/rust-lang/rust/issues/66401 
53+ [ repr( C ) ] 
5654        #[ derive( Debug ) ] 
57-         #[ lang =  "va_list" ] 
58-         pub   struct  VaListImpl < ' f>  { 
55+         #[ rustc_pass_indirectly_in_non_rustic_abis ] 
56+         struct  VaListInner  { 
5957            gpr:  i64 , 
6058            fpr:  i64 , 
61-             overflow_arg_area:  * mut  c_void, 
62-             reg_save_area:  * mut  c_void, 
63-             _marker:  PhantomInvariantLifetime <' f>, 
59+             overflow_arg_area:  * const  c_void, 
60+             reg_save_area:  * const  c_void, 
6461        } 
6562    } 
6663    all( target_arch = "x86_64" ,  not( target_os = "uefi" ) ,  not( windows) )  => { 
6764        /// x86_64 ABI implementation of a `va_list`. 
68- [ cfg_attr ( not ( doc ) ,   repr( C ) ) ]   // work around https://github.com/rust-lang/rust/issues/66401 
65+ [ repr( C ) ] 
6966        #[ derive( Debug ) ] 
70-         #[ lang =  "va_list" ] 
71-         pub   struct  VaListImpl < ' f>  { 
67+         #[ rustc_pass_indirectly_in_non_rustic_abis ] 
68+         struct  VaListInner  { 
7269            gp_offset:  i32 , 
7370            fp_offset:  i32 , 
74-             overflow_arg_area:  * mut  c_void, 
75-             reg_save_area:  * mut  c_void, 
76-             _marker:  PhantomInvariantLifetime <' f>, 
71+             overflow_arg_area:  * const  c_void, 
72+             reg_save_area:  * const  c_void, 
7773        } 
7874    } 
7975    target_arch = "xtensa"  => { 
8076        /// Xtensa ABI implementation of a `va_list`. 
8177[ repr( C ) ] 
8278        #[ derive( Debug ) ] 
83-         #[ lang =  "va_list" ] 
84-         pub   struct  VaListImpl < ' f>  { 
85-             stk:  * mut  i32 , 
86-             reg:  * mut  i32 , 
79+         #[ rustc_pass_indirectly_in_non_rustic_abis ] 
80+         struct  VaListInner  { 
81+             stk:  * const  i32 , 
82+             reg:  * const  i32 , 
8783            ndx:  i32 , 
88-             _marker:  PhantomInvariantLifetime <' f>, 
8984        } 
9085    } 
9186
@@ -94,94 +89,32 @@ crate::cfg_select! {
9489    // - apple aarch64 (see https://github.com/rust-lang/rust/pull/56599) 
9590    // - windows 
9691    // - uefi 
97-     // - any other target for which we don't specify the `VaListImpl ` above 
92+     // - any other target for which we don't specify the `VaListInner ` above 
9893    // 
9994    // In this implementation the `va_list` type is just an alias for an opaque pointer. 
10095    // That pointer is probably just the next variadic argument on the caller's stack. 
10196    _ => { 
10297        /// Basic implementation of a `va_list`. 
10398[ repr( transparent) ] 
104-         #[ lang = "va_list" ] 
105-         pub  struct  VaListImpl <' f> { 
106-             ptr:  * mut  c_void, 
107- 
108-             // Invariant over `'f`, so each `VaListImpl<'f>` object is tied to 
109-             // the region of the function it's defined in 
110-             _marker:  PhantomInvariantLifetime <' f>, 
111-         } 
112- 
113-         impl <' f> fmt:: Debug  for  VaListImpl <' f> { 
114-             fn  fmt( & self ,  f:  & mut  fmt:: Formatter <' _>)  -> fmt:: Result  { 
115-                 write!( f,  "va_list* {:p}" ,  self . ptr) 
116-             } 
117-         } 
118-     } 
119- } 
120- 
121- crate :: cfg_select! { 
122-     all( 
123-         any( 
124-             target_arch = "aarch64" , 
125-             target_arch = "powerpc" , 
126-             target_arch = "s390x" , 
127-             target_arch = "x86_64" 
128-         ) , 
129-         not( target_arch = "xtensa" ) , 
130-         any( not( target_arch = "aarch64" ) ,  not( target_vendor = "apple" ) ) , 
131-         not( target_family = "wasm" ) , 
132-         not( target_os = "uefi" ) , 
133-         not( windows) , 
134-     )  => { 
135-         /// A wrapper for a `va_list` 
136- [ repr( transparent) ] 
137-         #[ derive( Debug ) ] 
138-         pub  struct  VaList <' a,  ' f:  ' a> { 
139-             inner:  & ' a mut  VaListImpl <' f>, 
140-             _marker:  PhantomData <& ' a mut  VaListImpl <' f>>, 
141-         } 
142- 
143- 
144-         impl <' f> VaListImpl <' f> { 
145-             /// Converts a [`VaListImpl`] into a [`VaList`] that is binary-compatible with C's `va_list`. 
146- [ inline] 
147-             pub  fn  as_va_list<' a>( & ' a mut  self )  -> VaList <' a,  ' f> { 
148-                 VaList  {  inner:  self ,  _marker:  PhantomData  } 
149-             } 
150-         } 
151-     } 
152- 
153-     _ => { 
154-         /// A wrapper for a `va_list` 
155- [ repr( transparent) ] 
15699        #[ derive( Debug ) ] 
157-         pub  struct  VaList <' a,  ' f:  ' a> { 
158-             inner:  VaListImpl <' f>, 
159-             _marker:  PhantomData <& ' a mut  VaListImpl <' f>>, 
160-         } 
161- 
162-         impl <' f> VaListImpl <' f> { 
163-             /// Converts a [`VaListImpl`] into a [`VaList`] that is binary-compatible with C's `va_list`. 
164- [ inline] 
165-             pub  fn  as_va_list<' a>( & ' a mut  self )  -> VaList <' a,  ' f> { 
166-                 VaList  {  inner:  VaListImpl  {  ..* self  } ,  _marker:  PhantomData  } 
167-             } 
100+         struct  VaListInner  { 
101+             ptr:  * const  c_void, 
168102        } 
169103    } 
170104} 
171105
172- impl < ' a ,  ' f :  ' a >  Deref  for  VaList < ' a ,  ' f >  { 
173-     type  Target  = VaListImpl < ' f > ; 
174- 
175-     #[ inline]  
176-     fn  deref ( & self )  -> & VaListImpl < ' f >  { 
177-         & self . inner 
178-     } 
106+ /// A variable argument list, equivalent to `va_list` in C. 
107+ #[ repr( transparent) ]  
108+ #[ lang = "va_list" ]  
109+ pub  struct  VaList < ' a >  { 
110+     inner :  VaListInner , 
111+     _marker :  PhantomCovariantLifetime < ' a > , 
179112} 
180113
181- impl < ' a ,   ' f :   ' a >   DerefMut   for  VaList < ' a ,   ' f >  { 
182-     # [ inline ] 
183-     fn   deref_mut ( & mut   self )  ->  & mut   VaListImpl < ' f >   { 
184-         & mut   self . inner 
114+ impl  fmt :: Debug   for  VaList < ' _ >  { 
115+     fn   fmt ( & self ,   f :   & mut  fmt :: Formatter < ' _ > )  -> fmt :: Result   { 
116+          // No need to include `_marker` in debug output. 
117+         f . debug_tuple ( "VaList" ) . field ( & self . inner ) . finish ( ) 
185118    } 
186119} 
187120
@@ -202,7 +135,7 @@ mod sealed {
202135    impl < T >  Sealed  for  * const  T  { } 
203136} 
204137
205- /// Trait which permits the allowed types to be used with [`VaListImpl ::arg`]. 
138+ /// Trait which permits the allowed types to be used with [`VaList ::arg`]. 
206139/// 
207140/// # Safety 
208141/// 
@@ -232,52 +165,31 @@ unsafe impl VaArgSafe for f64 {}
232165unsafe  impl < T >  VaArgSafe  for  * mut  T  { } 
233166unsafe  impl < T >  VaArgSafe  for  * const  T  { } 
234167
235- impl < ' f >  VaListImpl < ' f >  { 
168+ impl < ' f >  VaList < ' f >  { 
236169    /// Advance to the next arg. 
237170#[ inline]  
238171    pub  unsafe  fn  arg < T :  VaArgSafe > ( & mut  self )  -> T  { 
239172        // SAFETY: the caller must uphold the safety contract for `va_arg`. 
240173        unsafe  {  va_arg ( self )  } 
241174    } 
242- 
243-     /// Copies the `va_list` at the current location. 
244- pub  unsafe  fn  with_copy < F ,  R > ( & self ,  f :  F )  -> R 
245-     where 
246-         F :  for < ' copy >  FnOnce ( VaList < ' copy ,  ' f > )  -> R , 
247-     { 
248-         let  mut  ap = self . clone ( ) ; 
249-         let  ret = f ( ap. as_va_list ( ) ) ; 
250-         // SAFETY: the caller must uphold the safety contract for `va_end`. 
251-         unsafe  { 
252-             va_end ( & mut  ap) ; 
253-         } 
254-         ret
255-     } 
256175} 
257176
258- impl < ' f >  Clone  for  VaListImpl < ' f >  { 
177+ impl < ' f >  Clone  for  VaList < ' f >  { 
259178    #[ inline]  
260179    fn  clone ( & self )  -> Self  { 
261180        let  mut  dest = crate :: mem:: MaybeUninit :: uninit ( ) ; 
262-         // SAFETY: we write to the `MaybeUninit`, thus it is initialized and `assume_init` is legal 
181+         // SAFETY: we write to the `MaybeUninit`, thus it is initialized and `assume_init` is legal.  
263182        unsafe  { 
264183            va_copy ( dest. as_mut_ptr ( ) ,  self ) ; 
265184            dest. assume_init ( ) 
266185        } 
267186    } 
268187} 
269188
270- impl < ' f >  Drop  for  VaListImpl < ' f >  { 
189+ impl < ' f >  Drop  for  VaList < ' f >  { 
271190    fn  drop ( & mut  self )  { 
272-         // FIXME: this should call `va_end`, but there's no clean way to 
273-         // guarantee that `drop` always gets inlined into its caller, 
274-         // so the `va_end` would get directly called from the same function as 
275-         // the corresponding `va_copy`. `man va_end` states that C requires this, 
276-         // and LLVM basically follows the C semantics, so we need to make sure 
277-         // that `va_end` is always called from the same function as `va_copy`. 
278-         // For more details, see https://github.com/rust-lang/rust/pull/59625 
279-         // and https://llvm.org/docs/LangRef.html#llvm-va-end-intrinsic. 
280-         // 
281-         // This works for now, since `va_end` is a no-op on all current LLVM targets. 
191+         // Rust requires that not calling `va_end` on a `va_list` does not cause undefined behaviour 
192+         // (as it is safe to leak values). As `va_end` is a no-op on all current LLVM targets, this 
193+         // destructor is empty. 
282194    } 
283195} 
0 commit comments