@@ -48,7 +48,7 @@ crate::cfg_select! {
4848 /// [AArch64 Procedure Call Standard]:
4949 /// http://infocenter.arm.com/help/topic/com.arm.doc.ihi0055b/IHI0055B_aapcs64.pdf
5050 #[ repr( C ) ]
51- #[ derive( Debug ) ]
51+ #[ derive( Debug , Clone , Copy ) ]
5252 struct VaListInner {
5353 stack: * const c_void,
5454 gr_top: * const c_void,
@@ -66,7 +66,7 @@ crate::cfg_select! {
6666 /// https://github.com/llvm/llvm-project/blob/af9a4263a1a209953a1d339ef781a954e31268ff/llvm/lib/Target/PowerPC/PPCISelLowering.cpp#L4089-L4111
6767 /// [GCC header]: https://web.mit.edu/darwin/src/modules/gcc/gcc/ginclude/va-ppc.h
6868 #[ repr( C ) ]
69- #[ derive( Debug ) ]
69+ #[ derive( Debug , Clone , Copy ) ]
7070 #[ rustc_pass_indirectly_in_non_rustic_abis]
7171 struct VaListInner {
7272 gpr: u8 ,
@@ -84,7 +84,7 @@ crate::cfg_select! {
8484 /// [S/390x ELF Application Binary Interface Supplement]:
8585 /// https://docs.google.com/gview?embedded=true&url=https://github.com/IBM/s390x-abi/releases/download/v1.7/lzsabi_s390x.pdf
8686 #[ repr( C ) ]
87- #[ derive( Debug ) ]
87+ #[ derive( Debug , Clone , Copy ) ]
8888 #[ rustc_pass_indirectly_in_non_rustic_abis]
8989 struct VaListInner {
9090 gpr: i64 ,
@@ -101,7 +101,7 @@ crate::cfg_select! {
101101 /// [System V AMD64 ABI]:
102102 /// https://refspecs.linuxbase.org/elf/x86_64-abi-0.99.pdf
103103 #[ repr( C ) ]
104- #[ derive( Debug ) ]
104+ #[ derive( Debug , Clone , Copy ) ]
105105 #[ rustc_pass_indirectly_in_non_rustic_abis]
106106 struct VaListInner {
107107 gp_offset: i32 ,
@@ -118,7 +118,7 @@ crate::cfg_select! {
118118 /// [LLVM source]:
119119 /// https://github.com/llvm/llvm-project/blob/af9a4263a1a209953a1d339ef781a954e31268ff/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp#L1211-L1215
120120 #[ repr( C ) ]
121- #[ derive( Debug ) ]
121+ #[ derive( Debug , Clone , Copy ) ]
122122 #[ rustc_pass_indirectly_in_non_rustic_abis]
123123 struct VaListInner {
124124 stk: * const i32 ,
@@ -135,7 +135,7 @@ crate::cfg_select! {
135135 /// [LLVM source]:
136136 /// https://github.com/llvm/llvm-project/blob/0cdc1b6dd4a870fc41d4b15ad97e0001882aba58/clang/lib/CodeGen/Targets/Hexagon.cpp#L407-L417
137137 #[ repr( C ) ]
138- #[ derive( Debug ) ]
138+ #[ derive( Debug , Clone , Copy ) ]
139139 #[ rustc_pass_indirectly_in_non_rustic_abis]
140140 struct VaListInner {
141141 __current_saved_reg_area_pointer: * const c_void,
@@ -157,7 +157,7 @@ crate::cfg_select! {
157157 _ => {
158158 /// Basic implementation of a `va_list`.
159159 #[ repr( transparent) ]
160- #[ derive( Debug ) ]
160+ #[ derive( Debug , Clone , Copy ) ]
161161 struct VaListInner {
162162 ptr: * const c_void,
163163 }
@@ -179,6 +179,39 @@ impl fmt::Debug for VaList<'_> {
179179 }
180180}
181181
182+ impl VaList < ' _ > {
183+ // Helper used in the implementation of the `va_copy` intrinsic.
184+ pub ( crate ) fn duplicate ( & self ) -> Self {
185+ Self { inner : self . inner . clone ( ) , _marker : self . __marker }
186+ }
187+ }
188+
189+ impl Clone for VaList < ' _ > {
190+ #[ inline]
191+ fn clone ( & self ) -> Self {
192+ // We only implement Clone and not Copy because some future target might not be able to
193+ // implement Copy (e.g. because it allocates).
194+
195+ // We still use a `va_copy` intrinsic to provide a hook for const evaluation. The hook is
196+ // used to report UB when a variable argument list is duplicated with a manual `memcpy`.
197+ // While that works in practice for all current targets, we want to be able to support
198+ // targets in the future where that is not the case.
199+ va_copy ( self )
200+ }
201+ }
202+
203+ impl Drop for VaList < ' _ > {
204+ fn drop ( & mut self ) {
205+ // For all current LLVM targets `va_end` is a no-op.
206+ //
207+ // We implement `Drop` here because some future target might need to actually run
208+ // destructors (e.g. to deallocate).
209+ //
210+ // Rust requires that not calling `va_end` on a `va_list` does not cause undefined
211+ // behaviour: it is safe to leak values.
212+ }
213+ }
214+
182215mod sealed {
183216 pub trait Sealed { }
184217
@@ -253,26 +286,6 @@ impl<'f> VaList<'f> {
253286 }
254287}
255288
256- impl < ' f > Clone for VaList < ' f > {
257- #[ inline]
258- fn clone ( & self ) -> Self {
259- let mut dest = crate :: mem:: MaybeUninit :: uninit ( ) ;
260- // SAFETY: we write to the `MaybeUninit`, thus it is initialized and `assume_init` is legal.
261- unsafe {
262- va_copy ( dest. as_mut_ptr ( ) , self ) ;
263- dest. assume_init ( )
264- }
265- }
266- }
267-
268- impl < ' f > Drop for VaList < ' f > {
269- fn drop ( & mut self ) {
270- // Rust requires that not calling `va_end` on a `va_list` does not cause undefined behaviour
271- // (as it is safe to leak values). As `va_end` is a no-op on all current LLVM targets, this
272- // destructor is empty.
273- }
274- }
275-
276289// Checks (via an assert in `compiler/rustc_ty_utils/src/abi.rs`) that the C ABI for the current
277290// target correctly implements `rustc_pass_indirectly_in_non_rustic_abis`.
278291const _: ( ) = {
0 commit comments