You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Rollup merge of #150436 - va-list-copy, r=workingjubilee,RalfJung
`c_variadic`: impl `va_copy` and `va_end` as Rust intrinsics
tracking issue: #44930
Implement `va_copy` as (the rust equivalent of) `memcpy`, which is the behavior of all current LLVM targets. By providing our own implementation, we can guarantee its behavior. These guarantees are important for implementing c-variadics in e.g. const-eval.
Discussed in [#t-compiler/const-eval > c-variadics in const-eval](https://rust-lang.zulipchat.com/#narrow/channel/146212-t-compiler.2Fconst-eval/topic/c-variadics.20in.20const-eval/with/565509704).
I've also updated the comment for `Drop` a bit. The background here is that the C standard requires that `va_end` is used in the same function (and really, in the same scope) as the corresponding `va_start` or `va_copy`. That is because historically `va_start` would start a scope, which `va_end` would then close. e.g.
https://softwarepreservation.computerhistory.org/c_plus_plus/cfront/release_3.0.3/source/incl-master/proto-headers/stdarg.sol
```c
#define va_start(ap, parmN) {\
va_buf _va;\
_vastart(ap = (va_list)_va, (char *)&parmN + sizeof parmN)
#define va_end(ap) }
#define va_arg(ap, mode) *((mode *)_vaarg(ap, sizeof (mode)))
```
The C standard still has to consider such implementations, but for Rust they are irrelevant. Hence we can use `Clone` for `va_copy` and `Drop` for `va_end`.
Copy file name to clipboardExpand all lines: library/core/src/ffi/va_list.rs
+52-28Lines changed: 52 additions & 28 deletions
Original file line number
Diff line number
Diff line change
@@ -5,7 +5,7 @@
5
5
#[cfg(not(target_arch = "xtensa"))]
6
6
usecrate::ffi::c_void;
7
7
usecrate::fmt;
8
-
usecrate::intrinsics::{va_arg, va_copy};
8
+
usecrate::intrinsics::{va_arg, va_copy, va_end};
9
9
usecrate::marker::PhantomCovariantLifetime;
10
10
11
11
// There are currently three flavors of how a C `va_list` is implemented for
@@ -34,6 +34,10 @@ use crate::marker::PhantomCovariantLifetime;
34
34
//
35
35
// The Clang `BuiltinVaListKind` enumerates the `va_list` variations that Clang supports,
36
36
// and we mirror these here.
37
+
//
38
+
// For all current LLVM targets, `va_copy` lowers to `memcpy`. Hence the inner structs below all
39
+
// derive `Copy`. However, in the future we might want to support a target where `va_copy`
40
+
// allocates, or otherwise violates the requirements of `Copy`. Therefore `VaList` is only `Clone`.
37
41
crate::cfg_select! {
38
42
all(
39
43
target_arch = "aarch64",
@@ -45,10 +49,12 @@ crate::cfg_select! {
45
49
///
46
50
/// See the [AArch64 Procedure Call Standard] for more details.
47
51
///
52
+
/// `va_copy` is `memcpy`: <https://github.com/llvm/llvm-project/blob/5aee01a3df011e660f26660bc30a8c94a1651d8e/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp#L12682-L12700>
/// See the [LLVM source] and [GCC header] for more details.
64
70
///
71
+
/// `va_copy` is `memcpy`: <https://github.com/llvm/llvm-project/blob/5aee01a3df011e660f26660bc30a8c94a1651d8e/llvm/lib/Target/PowerPC/PPCISelLowering.cpp#L3755-L3764>
/// See the [S/390x ELF Application Binary Interface Supplement] for more details.
83
91
///
92
+
/// `va_copy` is `memcpy`: <https://github.com/llvm/llvm-project/blob/5aee01a3df011e660f26660bc30a8c94a1651d8e/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp#L4457-L4472>
/// See the [System V AMD64 ABI] for more details.
100
110
///
111
+
/// `va_copy` is `memcpy`: <https://github.com/llvm/llvm-project/blob/5aee01a3df011e660f26660bc30a8c94a1651d8e/llvm/lib/Target/X86/X86ISelLowering.cpp#26319>
112
+
/// (github won't render that file, look for `SDValue LowerVACOPY`)
/// `va_copy` is `memcpy`: <https://github.com/llvm/llvm-project/blob/5aee01a3df011e660f26660bc30a8c94a1651d8e/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp#L1260>
/// See the [LLVM source] for more details. On bare metal Hexagon uses an opaque pointer.
134
149
///
150
+
/// `va_copy` is `memcpy`: <https://github.com/llvm/llvm-project/blob/5aee01a3df011e660f26660bc30a8c94a1651d8e/llvm/lib/Target/Hexagon/HexagonISelLowering.cpp#L1087-L1102>
// That pointer is probably just the next variadic argument on the caller's stack.
157
174
_ => {
158
175
/// Basic implementation of a `va_list`.
176
+
///
177
+
/// `va_copy` is `memcpy`: <https://github.com/llvm/llvm-project/blob/87e8e7d8f0db53060ef2f6ef4ab612fc0f2b4490/llvm/lib/Transforms/IPO/ExpandVariadics.cpp#L127-L129>
159
178
#[repr(transparent)]
160
-
#[derive(Debug)]
179
+
#[derive(Debug,Clone,Copy)]
161
180
structVaListInner{
162
181
ptr:*const c_void,
163
182
}
@@ -179,6 +198,31 @@ impl fmt::Debug for VaList<'_> {
179
198
}
180
199
}
181
200
201
+
implVaList<'_>{
202
+
// Helper used in the implementation of the `va_copy` intrinsic.
0 commit comments