Uh oh!
There was an error while loading. Please reload this page.
c_variadic: impl va_copy and va_end as Rust intrinsics - #150436
Conversation
| /// Basic implementation of a `va_list`. | ||
| #[repr(transparent)] | ||
| #[derive(Debug)] | ||
| #[derive(Debug, Clone, Copy)] | ||
| struct VaListInner { | ||
| ptr: *const c_void, | ||
| } |
There was a problem hiding this comment.
| /// https://github.com/llvm/llvm-project/blob/0cdc1b6dd4a870fc41d4b15ad97e0001882aba58/clang/lib/CodeGen/Targets/Hexagon.cpp#L407-L417 | ||
| #[repr(C)] | ||
| #[derive(Debug)] | ||
| #[derive(Debug, Clone, Copy)] |
There was a problem hiding this comment.
| /// https://github.com/llvm/llvm-project/blob/af9a4263a1a209953a1d339ef781a954e31268ff/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp#L1211-L1215 | ||
| #[repr(C)] | ||
| #[derive(Debug)] | ||
| #[derive(Debug, Clone, Copy)] |
There was a problem hiding this comment.
| /// https://docs.google.com/gview?embedded=true&url=https://github.com/IBM/s390x-abi/releases/download/v1.7/lzsabi_s390x.pdf | ||
| #[repr(C)] | ||
| #[derive(Debug)] | ||
| #[derive(Debug, Clone, Copy)] |
There was a problem hiding this comment.
| /// [GCC header]: https://web.mit.edu/darwin/src/modules/gcc/gcc/ginclude/va-ppc.h | ||
| #[repr(C)] | ||
| #[derive(Debug)] | ||
| #[derive(Debug, Clone, Copy)] |
There was a problem hiding this comment.
Uh oh!
There was an error while loading. Please reload this page.
This comment has been minimized.
This comment has been minimized.
7a78640 to
8e09112Comparefolkertdev
commented
Jan 2, 2026
The codegen of |
rustbot
commented
Jan 2, 2026
|
rustbot
commented
Jan 2, 2026
RalfJung
commented
Jan 3, 2026
Didn't we say we would avoid that assumption and also support implementations that do malloc/free in va_copy / va_end? See #t-compiler/const-eval > c-variadics in const-eval @ 💬. |
folkertdev
commented
Jan 3, 2026
That's right, we don't actually impl Copy for VaList, so that a future target could implement a meaningful Clone and Drop. It's just that in practice for all current targets Clone happens to be a memcpy and Drop a no-op |
Uh oh!
There was an error while loading. Please reload this page.
RalfJung
commented
Jan 7, 2026
@folkertdev what is your plan for va_copy regarding the const-eval support for this? |
Uh oh!
There was an error while loading. Please reload this page.
c_variadic: use Clone instead of va_copyc_variadic: use Clone instead of LLVM va_copy
This comment has been minimized.
This comment has been minimized.
folkertdev
commented
Jan 7, 2026
Based on further discussion in #t-compiler/const-eval > c-variadics in const-eval, a slight change of plans
I've changed the signature of the intrinsic to be more ergonomic, and made it safe because while the hook is used to detect UB, the intrinsic itself is completely safe. |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
| /// | ||
| /// See the [LLVM source] and [GCC header] for more details. | ||
| /// | ||
| /// `va_copy` is `memcpy`: <https://github.com/llvm/llvm-project/blob/5aee01a3df011e660f26660bc30a8c94a1651d8e/llvm/lib/Target/PowerPC/PPCISelLowering.h#L713> |
There was a problem hiding this comment.
This is also just a header, not the implementation? (same for some of the other ones)
There was a problem hiding this comment.
Ah now I understand what happened: i copied these links from a github search result page. I manually looked them all up now, so all links should be correct.
94ce7b4 to
6011fa6CompareRalfJung
commented
Jan 20, 2026
Sounds great, thanks! @bors delegate+ |
✌️ @folkertdev, you can now approve this pull request! If @RalfJung told you to " |
folkertdev
commented
Jan 20, 2026
@bors r=workingjubilee,RalfJung |
Rollup of 6 pull requests Successful merges: - #150436 (`c_variadic`: impl `va_copy` and `va_end` as Rust intrinsics) - #151340 (Port `#[patchable_function_entry]` to attr parser) - #151351 (Deduplicate diagnostics for const trait supertraits) - #151424 (missing colon after the compile-flags directive) - #151428 (Port variance attrs to attr parser.) - #151429 (s390x: Support aligned stack datalayout) Failed merges: - #151343 (Port some crate level attrs to the attribute parser) r? @ghost
Uh oh!
There was an error while loading. Please reload this page.
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`.
Rollup of 6 pull requests Successful merges: - rust-lang/rust#150436 (`c_variadic`: impl `va_copy` and `va_end` as Rust intrinsics) - rust-lang/rust#151340 (Port `#[patchable_function_entry]` to attr parser) - rust-lang/rust#151351 (Deduplicate diagnostics for const trait supertraits) - rust-lang/rust#151424 (missing colon after the compile-flags directive) - rust-lang/rust#151428 (Port variance attrs to attr parser.) - rust-lang/rust#151429 (s390x: Support aligned stack datalayout) Failed merges: - rust-lang/rust#151343 (Port some crate level attrs to the attribute parser) r? @ghost
Rollup of 6 pull requests Successful merges: - rust-lang/rust#150436 (`c_variadic`: impl `va_copy` and `va_end` as Rust intrinsics) - rust-lang/rust#151340 (Port `#[patchable_function_entry]` to attr parser) - rust-lang/rust#151351 (Deduplicate diagnostics for const trait supertraits) - rust-lang/rust#151424 (missing colon after the compile-flags directive) - rust-lang/rust#151428 (Port variance attrs to attr parser.) - rust-lang/rust#151429 (s390x: Support aligned stack datalayout) Failed merges: - rust-lang/rust#151343 (Port some crate level attrs to the attribute parser) r? @ghost
…fJung `c_variadic`: impl `va_copy` and `va_end` as Rust intrinsics tracking issue: rust-lang#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`.
…comments, r=folkertdev Remove outdated comments from `va_list.rs` Since rust-lang#150436 codegen backends haven't needed to implement `va_copy` or `va_end` as they are implemented using intrinsic fallback bodies, so the comments on the `#[inline]` annotations are no longer relevant. I've left the `#[inline]` annotations themselves as they seem worthwhile since `va_copy` and `va_end` are a memcpy and a no-op respectively.
…comments, r=folkertdev Remove outdated comments from `va_list.rs` Since rust-lang#150436 codegen backends haven't needed to implement `va_copy` or `va_end` as they are implemented using intrinsic fallback bodies, so the comments on the `#[inline]` annotations are no longer relevant. I've left the `#[inline]` annotations themselves as they seem worthwhile since `va_copy` and `va_end` are a memcpy and a no-op respectively.
…comments, r=folkertdev Remove outdated comments from `va_list.rs` Since rust-lang#150436 codegen backends haven't needed to implement `va_copy` or `va_end` as they are implemented using intrinsic fallback bodies, so the comments on the `#[inline]` annotations are no longer relevant. I've left the `#[inline]` annotations themselves as they seem worthwhile since `va_copy` and `va_end` are a memcpy and a no-op respectively.
Rollup merge of #160157 - beetrees:va-list-outdated-backend-comments, r=folkertdev Remove outdated comments from `va_list.rs` Since #150436 codegen backends haven't needed to implement `va_copy` or `va_end` as they are implemented using intrinsic fallback bodies, so the comments on the `#[inline]` annotations are no longer relevant. I've left the `#[inline]` annotations themselves as they seem worthwhile since `va_copy` and `va_end` are a memcpy and a no-op respectively.
… r=folkertdev Remove outdated comments from `va_list.rs` Since rust-lang/rust#150436 codegen backends haven't needed to implement `va_copy` or `va_end` as they are implemented using intrinsic fallback bodies, so the comments on the `#[inline]` annotations are no longer relevant. I've left the `#[inline]` annotations themselves as they seem worthwhile since `va_copy` and `va_end` are a memcpy and a no-op respectively.
tracking issue: #44930
Implement
va_copyas (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.
I've also updated the comment for
Dropa bit. The background here is that the C standard requires thatva_endis used in the same function (and really, in the same scope) as the correspondingva_startorva_copy. That is because historicallyva_startwould start a scope, whichva_endwould then close. e.g.https://softwarepreservation.computerhistory.org/c_plus_plus/cfront/release_3.0.3/source/incl-master/proto-headers/stdarg.sol
The C standard still has to consider such implementations, but for Rust they are irrelevant. Hence we can use
Cloneforva_copyandDropforva_end.