C++ Logo

liaison

Advanced search

Re: [isocpp-wg14/wg21-liaison] Extra arguments to va_start

From: J Decker <d3ck0r_at_[hidden]>
Date: Tue, 11 Nov 2025 02:53:10 -0800
On Mon, Nov 10, 2025 at 9:10 AM Aaron Ballman via Liaison <
liaison_at_[hidden]> wrote:

> I think the situation with va_start is a bit confused and there
> appears to be implementation divergence in the wild. Consider this
> code:
>
> void func(int i, ...) {
> va_list list;
> va_start(list, +);
> }
>
> 7.16.2.5p4: Only the first argument passed to va_start is evaluated.
> If any additional arguments expand to include unbalanced parentheses,
> or a preprocessing token that does not convert to a token, the
> behavior is undefined.
>

'Is Evaluated' means 'computing the value of an expression and carrying out
its associated side effects'
The second argument, not being evaluated, doesn't mean it's ignored, but
that it's a literal that gets stuffed into the result without evaluation.

It doesn't say 'there's only one argument, and others are ignored' it says
'only the first is evaluated'

like doing `&((struct thing *)0)->member ` to get offsetof, the actual
pointer there isn't evaluated...


>
> So "list" is evaluated and "+" is not. Is the + then discarded as a
> token? So is this valid? GCC and TCC accept, Clang and SDCC reject:
> https://godbolt.org/z/Yf317Kxfx What if `+` was an undeclared
> identifier instead?
>
> (Keep in mind, we use the same "only ... is evaluated" in other
> circumstances where the resulting code is still expected to be
> semantically correct. e.g., `1 || undeclared_identifier` is still a
> constraint violation even though `undeclared_identifier` is not
> evaluated.)
>
> Now think about this in terms of __COUNTER__ from C2y, with this code:
>
> void func(int i, ...) {
> va_list list;
> va_start(list, __COUNTER__);
> static_assert(__COUNTER__ == 0);
> }
>
> Does that static assertion pass or fail? It fails in Clang and GCC,
> doesn't compile correctly in SDCC, and TCC it succeeds:
> https://godbolt.org/z/56qT9sarK At least with Clang and GCC, the
> implementation of the macro is to forward to a builtin function so
> that the builtin can generate appropriate diagnostics, so the
> __COUNTER__ macro is expanded. Avoiding that expansion but keeping the
> same level of QoI is a surprisingly large burden (we'd need a new
> builtin and way to count the number of arguments in __VA_ARGS__ which
> does not expand the tokens, I believe).
>
> I think this is an issue SG22 should take up (hence, I've CCed Nina)
> because the C++ wording is different from the C wording. In C++, the
> tokens (if any) are *discarded* explicitly
> (https://eel.is/c++draft/cstdarg.syn#1.2). I believe in C++, both of
> those examples are expected to compile without diagnostics.
>
> Thanks!
>
> ~Aaron
> _______________________________________________
> Liaison mailing list
> Liaison_at_[hidden]
> Subscription: https://lists.isocpp.org/mailman/listinfo.cgi/liaison
> Searchable archives: http://lists.isocpp.org/liaison/2025/11/index.php
>

Received on 2025-11-11 10:53:25