Skip to content

Conversation

folkertdev
Copy link
Contributor

tracking issue: #44930

We concluded that this trait should be implementable by end users. Many ABIs do support passing additional types (128-bit integers, SIMD vectors, composite types).

r? @workingjubilee

@folkertdev folkertdev added the F-c_variadic `#![feature(c_variadic)]` label Sep 11, 2025
@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-libs Relevant to the library team, which will review and decide on the PR/issue. labels Sep 11, 2025
@rustbot
Copy link
Collaborator

rustbot commented Sep 11, 2025

workingjubilee is currently at their maximum review capacity.
They may take a while to respond.

@Jules-Bertholet
Copy link
Contributor

extern "C" fn foo(_: SomeReprRustType) {} isn’t UB, it just has an unstable ABI. What makes this case different? Why does the trait need to be unsafe? Why does it need to be a trait at all, as opposed to part of the improper_ctypes lint?

@rust-log-analyzer

This comment has been minimized.

@folkertdev
Copy link
Contributor Author

Based no our reading of https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3220.pdf#page=302, something like ap.arg::<u16>() really is UB if the C side passed an unsigned short. This trait was designed catch that pitfall originally.

If a complex type contains fields of types that are not supported by the ABI, then it's not guaranteed that it can be faithfully reconstructed by va_arg, right? The variable arguments ABI is not the same as the standard C ABI.

And update the safety documentation
@workingjubilee
Copy link
Member

workingjubilee commented Sep 12, 2025

extern "C" fn foo(_: SomeReprRustType) {} isn’t UB, it just has an unstable ABI. What makes this case different? Why does the trait need to be unsafe? Why does it need to be a trait at all, as opposed to part of the improper_ctypes lint?

Why do we need to bound future designs which attempt to provide more assurance by what was justifiable at earlier implementation times by expedience? The initial approach did not think we should be, but then attempted to inflict a very strict bound. We are trying to effectively weaken the restrictions to something reasonable, that provides a balance of utility and soundness, without simply sending everyone into the abyss to get flayed alive by wandering compilers wielding a thousand edge cases.

A lint generally signals something that we do not like. Often, something that we would design away if we could. Here, the API is relatively green, even if it is adjacent to some quite scorched fields.

We could do even better hypothetically but that would require a lot more work.

@folkertdev
Copy link
Contributor Author

Hmm, trying a custom implementation with e.g. a u128 reveals that we make some assumptions in the backend

internal error: entered unreachable code: all instances of VaArgSafe have an alignment <= 8
stack backtrace:
   0: __rustc::rust_begin_unwind
   1: core::panicking::panic_fmt
   2: rustc_codegen_llvm::va_arg::x86_64_sysv64_va_arg_from_mem

So this is going to be more work, especially given the matrix of targets and calling conventions.

@folkertdev
Copy link
Contributor Author

Honestly I kind of think we shouldn't open this can of worms for the MVP of stable c-variadics.There is always unsafe if someone really needs non-scalar types.

@folkertdev
Copy link
Contributor Author

closing in favor of #146521

@folkertdev folkertdev closed this Sep 13, 2025
@rustbot rustbot removed the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Sep 13, 2025
jhpratt added a commit to jhpratt/rust that referenced this pull request Sep 13, 2025
…=workingjubilee

document `core::ffi::VaArgSafe`

tracking issue: rust-lang#44930

A modification of rust-lang#146454, keeping just the documentation changes, but not unsealing the trait.

Although conceptually we'd want to unseal the trait, there are many edge cases to supporting arbitrary types. We'd need to exhaustively test that all targets/calling conventions support all types that rust might generate (or generate proper error messages for unsupported cases). At present, many of the `va_arg` implementations assume that the argument is a scalar, and has an alignment of at most 8. That is totally  sufficient for an MVP (accepting all of the "standard" C types), but clearly does not cover all rust types.

This PR also adds some various other tests for edge cases of c-variadic:

- the `#[inline]` attribute in its various forms. At present, LLVM is unable to inline c-variadic functions, but the attribute should still be accepted. `#[rustc_force_inline]` already rejects c-variadic functions.
- naked functions should accept and work with a C variable argument list. In the future we'd like to allow more ABIs with naked functions (basically, any ABI for which we accept defining foreign c-variadic functions), but for now only  `"C"` and `"C-unwind` are supported
- guaranteed tail calls: c-variadic functions cannot be tail-called. That was already rejected, but there was not test for it.

r? `@workingjubilee`
rust-timer added a commit that referenced this pull request Sep 14, 2025
Rollup merge of #146521 - folkertdev:document-va-arg-safe, r=workingjubilee

document `core::ffi::VaArgSafe`

tracking issue: #44930

A modification of #146454, keeping just the documentation changes, but not unsealing the trait.

Although conceptually we'd want to unseal the trait, there are many edge cases to supporting arbitrary types. We'd need to exhaustively test that all targets/calling conventions support all types that rust might generate (or generate proper error messages for unsupported cases). At present, many of the `va_arg` implementations assume that the argument is a scalar, and has an alignment of at most 8. That is totally  sufficient for an MVP (accepting all of the "standard" C types), but clearly does not cover all rust types.

This PR also adds some various other tests for edge cases of c-variadic:

- the `#[inline]` attribute in its various forms. At present, LLVM is unable to inline c-variadic functions, but the attribute should still be accepted. `#[rustc_force_inline]` already rejects c-variadic functions.
- naked functions should accept and work with a C variable argument list. In the future we'd like to allow more ABIs with naked functions (basically, any ABI for which we accept defining foreign c-variadic functions), but for now only  `"C"` and `"C-unwind` are supported
- guaranteed tail calls: c-variadic functions cannot be tail-called. That was already rejected, but there was not test for it.

r? `@workingjubilee`
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
F-c_variadic `#![feature(c_variadic)]` T-libs Relevant to the library team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants