55use  crate :: ffi:: c_void; 
66#[ allow( unused_imports) ]  
77use  crate :: fmt; 
8- use  crate :: marker:: { PhantomData ,  PhantomInvariantLifetime } ; 
9- use  crate :: ops:: { Deref ,  DerefMut } ; 
8+ use  crate :: marker:: PhantomInvariantLifetime ; 
109
11- // The name is WIP, using `VaListImpl` for now. 
12- // 
1310// 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. 
15+ 
16+ // Note that currently support for `#[rustc_pass_indirectly_in_non_rustic_abis]` is only implemented 
17+ // on architectures which need it here, so when adding support for a new architecture the following 
18+ // will need to happen: 
19+ // 
20+ // - Check that the calling conventions used on the new architecture correctly check 
21+ //   `arg.layout.pass_indirectly_in_non_rustic_abis()` and call `arg.make_indirect()` if it returns 
22+ //   `true`. 
23+ // - Add a revision to the `tests/ui/abi/pass-indirectly-attr.rs` test for the new architecture. 
24+ // - Add the new architecture to the `supported_architectures` array in the 
25+ //   `check_pass_indirectly_in_non_rustic_abis` function in 
26+ //   `compiler/rustc_passes/src/check_attr.rs`. This will stop the compiler from emitting an error 
27+ //   message when the attribute is used on that architecture. 
1428crate :: cfg_select! { 
1529    all( 
1630        target_arch = "aarch64" , 
@@ -26,7 +40,8 @@ crate::cfg_select! {
2640[ cfg_attr( not( doc) ,  repr( C ) ) ]  // work around https://github.com/rust-lang/rust/issues/66401 
2741        #[ derive( Debug ) ] 
2842        #[ lang = "va_list" ] 
29-         pub  struct  VaListImpl <' f> { 
43+         #[ rustc_pass_indirectly_in_non_rustic_abis] 
44+         pub  struct  VaList <' f> { 
3045            stack:  * mut  c_void, 
3146            gr_top:  * mut  c_void, 
3247            vr_top:  * mut  c_void, 
@@ -40,7 +55,8 @@ crate::cfg_select! {
4055[ cfg_attr( not( doc) ,  repr( C ) ) ]  // work around https://github.com/rust-lang/rust/issues/66401 
4156        #[ derive( Debug ) ] 
4257        #[ lang = "va_list" ] 
43-         pub  struct  VaListImpl <' f> { 
58+         #[ rustc_pass_indirectly_in_non_rustic_abis] 
59+         pub  struct  VaList <' f> { 
4460            gpr:  u8 , 
4561            fpr:  u8 , 
4662            reserved:  u16 , 
@@ -54,7 +70,8 @@ crate::cfg_select! {
5470[ cfg_attr( not( doc) ,  repr( C ) ) ]  // work around https://github.com/rust-lang/rust/issues/66401 
5571        #[ derive( Debug ) ] 
5672        #[ lang = "va_list" ] 
57-         pub  struct  VaListImpl <' f> { 
73+         #[ rustc_pass_indirectly_in_non_rustic_abis] 
74+         pub  struct  VaList <' f> { 
5875            gpr:  i64 , 
5976            fpr:  i64 , 
6077            overflow_arg_area:  * mut  c_void, 
@@ -67,7 +84,8 @@ crate::cfg_select! {
6784[ cfg_attr( not( doc) ,  repr( C ) ) ]  // work around https://github.com/rust-lang/rust/issues/66401 
6885        #[ derive( Debug ) ] 
6986        #[ lang = "va_list" ] 
70-         pub  struct  VaListImpl <' f> { 
87+         #[ rustc_pass_indirectly_in_non_rustic_abis] 
88+         pub  struct  VaList <' f> { 
7189            gp_offset:  i32 , 
7290            fp_offset:  i32 , 
7391            overflow_arg_area:  * mut  c_void, 
@@ -80,7 +98,8 @@ crate::cfg_select! {
8098[ repr( C ) ] 
8199        #[ derive( Debug ) ] 
82100        #[ lang = "va_list" ] 
83-         pub  struct  VaListImpl <' f> { 
101+         #[ rustc_pass_indirectly_in_non_rustic_abis] 
102+         pub  struct  VaList <' f> { 
84103            stk:  * mut  i32 , 
85104            reg:  * mut  i32 , 
86105            ndx:  i32 , 
@@ -93,97 +112,30 @@ crate::cfg_select! {
93112    // - apple aarch64 (see https://github.com/rust-lang/rust/pull/56599) 
94113    // - windows 
95114    // - uefi 
96-     // - any other target for which we don't specify the `VaListImpl ` above 
115+     // - any other target for which we don't specify the `VaList ` above 
97116    // 
98117    // In this implementation the `va_list` type is just an alias for an opaque pointer. 
99118    // That pointer is probably just the next variadic argument on the caller's stack. 
100119    _ => { 
101120        /// Basic implementation of a `va_list`. 
102121[ repr( transparent) ] 
103122        #[ lang = "va_list" ] 
104-         pub  struct  VaListImpl <' f> { 
123+         pub  struct  VaList <' f> { 
105124            ptr:  * mut  c_void, 
106125
107-             // Invariant over `'f`, so each `VaListImpl <'f>` object is tied to 
126+             // Invariant over `'f`, so each `VaList <'f>` object is tied to 
108127            // the region of the function it's defined in 
109128            _marker:  PhantomInvariantLifetime <' f>, 
110129        } 
111130
112-         impl <' f> fmt:: Debug  for  VaListImpl <' f> { 
131+         impl <' f> fmt:: Debug  for  VaList <' f> { 
113132            fn  fmt( & self ,  f:  & mut  fmt:: Formatter <' _>)  -> fmt:: Result  { 
114-                 write!( f,  "va_list* {:p}" ,  self . ptr) 
115-             } 
116-         } 
117-     } 
118- } 
119- 
120- crate :: cfg_select! { 
121-     all( 
122-         any( 
123-             target_arch = "aarch64" , 
124-             target_arch = "powerpc" , 
125-             target_arch = "s390x" , 
126-             target_arch = "x86_64" 
127-         ) , 
128-         not( target_arch = "xtensa" ) , 
129-         any( not( target_arch = "aarch64" ) ,  not( target_vendor = "apple" ) ) , 
130-         not( target_family = "wasm" ) , 
131-         not( target_os = "uefi" ) , 
132-         not( windows) , 
133-     )  => { 
134-         /// A wrapper for a `va_list` 
135- [ repr( transparent) ] 
136-         #[ derive( Debug ) ] 
137-         pub  struct  VaList <' a,  ' f:  ' a> { 
138-             inner:  & ' a mut  VaListImpl <' f>, 
139-             _marker:  PhantomData <& ' a mut  VaListImpl <' f>>, 
140-         } 
141- 
142- 
143-         impl <' f> VaListImpl <' f> { 
144-             /// Converts a [`VaListImpl`] into a [`VaList`] that is binary-compatible with C's `va_list`. 
145- [ inline] 
146-             pub  fn  as_va_list<' a>( & ' a mut  self )  -> VaList <' a,  ' f> { 
147-                 VaList  {  inner:  self ,  _marker:  PhantomData  } 
148-             } 
149-         } 
150-     } 
151- 
152-     _ => { 
153-         /// A wrapper for a `va_list` 
154- [ repr( transparent) ] 
155-         #[ derive( Debug ) ] 
156-         pub  struct  VaList <' a,  ' f:  ' a> { 
157-             inner:  VaListImpl <' f>, 
158-             _marker:  PhantomData <& ' a mut  VaListImpl <' f>>, 
159-         } 
160- 
161-         impl <' f> VaListImpl <' f> { 
162-             /// Converts a [`VaListImpl`] into a [`VaList`] that is binary-compatible with C's `va_list`. 
163- [ inline] 
164-             pub  fn  as_va_list<' a>( & ' a mut  self )  -> VaList <' a,  ' f> { 
165-                 VaList  {  inner:  VaListImpl  {  ..* self  } ,  _marker:  PhantomData  } 
133+                 f. debug_tuple( "VaList" ) . field( & self . ptr) . finish( ) 
166134            } 
167135        } 
168136    } 
169137} 
170138
171- impl < ' a ,  ' f :  ' a >  Deref  for  VaList < ' a ,  ' f >  { 
172-     type  Target  = VaListImpl < ' f > ; 
173- 
174-     #[ inline]  
175-     fn  deref ( & self )  -> & VaListImpl < ' f >  { 
176-         & self . inner 
177-     } 
178- } 
179- 
180- impl < ' a ,  ' f :  ' a >  DerefMut  for  VaList < ' a ,  ' f >  { 
181-     #[ inline]  
182-     fn  deref_mut ( & mut  self )  -> & mut  VaListImpl < ' f >  { 
183-         & mut  self . inner 
184-     } 
185- } 
186- 
187139mod  sealed { 
188140    pub  trait  Sealed  { } 
189141
@@ -201,7 +153,7 @@ mod sealed {
201153    impl < T >  Sealed  for  * const  T  { } 
202154} 
203155
204- /// Trait which permits the allowed types to be used with [`VaListImpl ::arg`]. 
156+ /// Trait which permits the allowed types to be used with [`VaList ::arg`]. 
205157/// 
206158/// # Safety 
207159/// 
@@ -231,69 +183,31 @@ unsafe impl VaArgSafe for f64 {}
231183unsafe  impl < T >  VaArgSafe  for  * mut  T  { } 
232184unsafe  impl < T >  VaArgSafe  for  * const  T  { } 
233185
234- impl < ' f >  VaListImpl < ' f >  { 
186+ impl < ' f >  VaList < ' f >  { 
235187    /// Advance to the next arg. 
236188#[ inline]  
237189    pub  unsafe  fn  arg < T :  VaArgSafe > ( & mut  self )  -> T  { 
238190        // SAFETY: the caller must uphold the safety contract for `va_arg`. 
239-         unsafe  {  va_arg ( self )  } 
240-     } 
241- 
242-     /// Copies the `va_list` at the current location. 
243- pub  unsafe  fn  with_copy < F ,  R > ( & self ,  f :  F )  -> R 
244-     where 
245-         F :  for < ' copy >  FnOnce ( VaList < ' copy ,  ' f > )  -> R , 
246-     { 
247-         let  mut  ap = self . clone ( ) ; 
248-         let  ret = f ( ap. as_va_list ( ) ) ; 
249-         // SAFETY: the caller must uphold the safety contract for `va_end`. 
250-         unsafe  { 
251-             va_end ( & mut  ap) ; 
252-         } 
253-         ret
191+         unsafe  {  crate :: intrinsics:: va_arg ( self )  } 
254192    } 
255193} 
256194
257- impl < ' f >  Clone  for  VaListImpl < ' f >  { 
195+ impl < ' f >  Clone  for  VaList < ' f >  { 
258196    #[ inline]  
259197    fn  clone ( & self )  -> Self  { 
260198        let  mut  dest = crate :: mem:: MaybeUninit :: uninit ( ) ; 
261-         // SAFETY: we write to the `MaybeUninit`, thus it is initialized and `assume_init` is legal 
199+         // SAFETY: we write to the `MaybeUninit`, thus it is initialized and `assume_init` is legal.  
262200        unsafe  { 
263-             va_copy ( dest. as_mut_ptr ( ) ,  self ) ; 
201+             crate :: intrinsics :: va_copy ( dest. as_mut_ptr ( ) ,  self ) ; 
264202            dest. assume_init ( ) 
265203        } 
266204    } 
267205} 
268206
269- impl < ' f >  Drop  for  VaListImpl < ' f >  { 
207+ impl < ' f >  Drop  for  VaList < ' f >  { 
270208    fn  drop ( & mut  self )  { 
271-         // FIXME: this should call `va_end`, but there's no clean way to 
272-         // guarantee that `drop` always gets inlined into its caller, 
273-         // so the `va_end` would get directly called from the same function as 
274-         // the corresponding `va_copy`. `man va_end` states that C requires this, 
275-         // and LLVM basically follows the C semantics, so we need to make sure 
276-         // that `va_end` is always called from the same function as `va_copy`. 
277-         // For more details, see https://github.com/rust-lang/rust/pull/59625 
278-         // and https://llvm.org/docs/LangRef.html#llvm-va-end-intrinsic. 
279-         // 
280-         // This works for now, since `va_end` is a no-op on all current LLVM targets. 
209+         // Rust requires that not calling `va_end` on a `va_list` does not cause undefined behaviour 
210+         // (as it is safe to leak values). As `va_end` is a no-op on all current LLVM targets, this 
211+         // destructor is empty. 
281212    } 
282213} 
283- 
284- /// Destroy the arglist `ap` after initialization with `va_start` or 
285- /// `va_copy`. 
286- #[ rustc_intrinsic]  
287- #[ rustc_nounwind]  
288- unsafe  fn  va_end ( ap :  & mut  VaListImpl < ' _ > ) ; 
289- 
290- /// Copies the current location of arglist `src` to the arglist `dst`. 
291- #[ rustc_intrinsic]  
292- #[ rustc_nounwind]  
293- unsafe  fn  va_copy < ' f > ( dest :  * mut  VaListImpl < ' f > ,  src :  & VaListImpl < ' f > ) ; 
294- 
295- /// Loads an argument of type `T` from the `va_list` `ap` and increment the 
296- /// argument `ap` points to. 
297- #[ rustc_intrinsic]  
298- #[ rustc_nounwind]  
299- unsafe  fn  va_arg < T :  VaArgSafe > ( ap :  & mut  VaListImpl < ' _ > )  -> T ; 
0 commit comments