Date: Wed, 12 Nov 2025 13:02:43 -0500
+1
On 11/12/2025 12:39 PM, Jonathan Wakely via Liaison wrote:
>
>
> On Wed, 12 Nov 2025, 15:52 Aaron Ballman via Liaison,
> <liaison_at_[hidden]> wrote:
>
> This is why I'm asking SG22 to step in; this seems like a needless
> incompatibility between C and C++.
>
> void func(int i, ...) {
> va_list list;
>
> va_start(list, blah); // #1
> va_start(list, __COUNTER__); // #2
> }
>
> #1 is required to be diagnosed in C17 and C++23, is required to be
> accepted in C++26.
>
>
> Does it matter though?
>
> Are we really worried that people will start using va_start this way
> in C++26 and ... create code that can't be compiled as C++23? Who cares?
>
> Nobody wrote that code yesterday, because it didn't work. Why would
> anybody write that code today?
>
> C23 is unclear IMO. The standard says the argument is not
> evaluated. So if the implementation expands to `sizeof(blah)` for
> some reason, that's allowed by the standard wording for va_start
> because `blah` is not evaluated? I think the intent for C23 is
> clear in that this code is expected to be semantically well-formed
> regardless of what it expands to, and there's a recommendation to
> diagnose if any additional arguments are passed.
>
> #2 is required to be diagnosed in C17 and C++23, is required to be
> accepted in C23 and C++26, where __COUNTER__ is expected to
> increment in C and expected to not increment in C++.
>
>
> Again, I find it hard to care.
>
> We want to continue accepting existing code, and want to permit (but
> not require) diagnostics for the dumbest mistakes in new code. Beyond
> that, does it matter if there's implementation divergence in edge
> cases that nobody would ever encounter outside of conformance tests?
>
>
> In both cases, I think this boils down to whether the committees
> expect something like:
>
> #define va_start(list, ...) __builtin_va_start(list, __VA_ARGS__)
>
> where the optional arguments passed to the macro are expanded and
> must be valid for a call to a builtin function. I think this is
> how WG14 expected things to work and so #1 would be rejected due
> to use of an undeclared identifier, similar to what would happen
> with `1 || blah` in an expression (`blah` is not evaluated, but it
> still has to be semantically valid). And #2 would increment
> __COUNTER__ because the macro is expanded for the call to the builtin.
>
> Or whether the committees expect something more like:
>
> #define va_start(list, ...) __builtin_va_start(list)
>
> where the optional arguments passed to the macro are not expanded
> and therefore don't have to be valid beyond what the preprocessor
> requires. I think this is how WG21 expected things to work, so #1
> would be accepted and #2 would not increment __COUNTER__.
>
> ~Aaron
>
>
>
> On Tue, Nov 11, 2025 at 6:46 AM Alex Celeste via Liaison
> <liaison_at_[hidden]> wrote:
>
> I believe we discussed basically this same question within
> WG14 before adopting the wording, and the "evaluated" wording
> was a revision/compromise intended to reduce the structness of
> the `va_start` macro so that it could still report errors if
> they were needed, but not to require anything special of it
> above the behaviour that would be expected for any other macro
> that doesn't exand its arguments into an evaluated position.
>
> So that second argument certainly isn't supposed to be being
> discarded by any special mechanism that would block
> incrementing `__COUNTER__` by some means not available to a
> user-defined macro. The original wording was stricter and
> might have implied this, but "evaluated" was chosen to
> indicate that it's the C-level evaluation that definitely
> doesn't happen, without implying anything about macro
> expansion. The macro part of this feature should just follow
> normal macro rules.
>
> Thanks,
>
> Alex
>
> Perforce Software
>
> Alex Celeste | Elder Witch of the C Compiler, Helix QAC
> <https://www.perforce.com/products/helix-qac>
>
> _Perforce Software <https://www.perforce.com>_
>
> P +1 612.517.2100
>
> Visit Us On: _LinkedIn
> <https://www.linkedin.com/company/perforce>_ | _YouTube
> <https://www.youtube.com/user/perforcesoftware>_
>
>
> ------------------------------------------------------------------------
> *From:* Liaison <liaison-bounces_at_[hidden]> on behalf
> of J Decker via Liaison <liaison_at_[hidden]>
> *Sent:* 11 November 2025 10:53
> *To:* liaison_at_[hidden] <liaison_at_[hidden]>
> *Cc:* J Decker <d3ck0r_at_[hidden]>
> *Subject:* Re: [isocpp-wg14/wg21-liaison] Extra arguments to
> va_start
>
>
> 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
>
>
>
> *CAUTION:*This email originated from outside of the
> organization. Do not click on links or open attachments unless
> you recognize the sender and know the content is safe.
>
>
> This e-mail may contain information that is privileged or
> confidential. If you are not the intended recipient, please
> delete the e-mail and any attachments and notify us immediately.
>
>
> _______________________________________________
> Liaison mailing list
> Liaison_at_[hidden]
> Subscription:
> https://lists.isocpp.org/mailman/listinfo.cgi/liaison
> Link to this post:
> http://lists.isocpp.org/liaison/2025/11/1596.php
>
> _______________________________________________
> Liaison mailing list
> Liaison_at_[hidden]
> Subscription: https://lists.isocpp.org/mailman/listinfo.cgi/liaison
> Link to this post: http://lists.isocpp.org/liaison/2025/11/1597.php
>
>
> _______________________________________________
> Liaison mailing list
> Liaison_at_[hidden]
> Subscription:https://lists.isocpp.org/mailman/listinfo.cgi/liaison
> Link to this post:http://lists.isocpp.org/liaison/2025/11/1601.php
On 11/12/2025 12:39 PM, Jonathan Wakely via Liaison wrote:
>
>
> On Wed, 12 Nov 2025, 15:52 Aaron Ballman via Liaison,
> <liaison_at_[hidden]> wrote:
>
> This is why I'm asking SG22 to step in; this seems like a needless
> incompatibility between C and C++.
>
> void func(int i, ...) {
> va_list list;
>
> va_start(list, blah); // #1
> va_start(list, __COUNTER__); // #2
> }
>
> #1 is required to be diagnosed in C17 and C++23, is required to be
> accepted in C++26.
>
>
> Does it matter though?
>
> Are we really worried that people will start using va_start this way
> in C++26 and ... create code that can't be compiled as C++23? Who cares?
>
> Nobody wrote that code yesterday, because it didn't work. Why would
> anybody write that code today?
>
> C23 is unclear IMO. The standard says the argument is not
> evaluated. So if the implementation expands to `sizeof(blah)` for
> some reason, that's allowed by the standard wording for va_start
> because `blah` is not evaluated? I think the intent for C23 is
> clear in that this code is expected to be semantically well-formed
> regardless of what it expands to, and there's a recommendation to
> diagnose if any additional arguments are passed.
>
> #2 is required to be diagnosed in C17 and C++23, is required to be
> accepted in C23 and C++26, where __COUNTER__ is expected to
> increment in C and expected to not increment in C++.
>
>
> Again, I find it hard to care.
>
> We want to continue accepting existing code, and want to permit (but
> not require) diagnostics for the dumbest mistakes in new code. Beyond
> that, does it matter if there's implementation divergence in edge
> cases that nobody would ever encounter outside of conformance tests?
>
>
> In both cases, I think this boils down to whether the committees
> expect something like:
>
> #define va_start(list, ...) __builtin_va_start(list, __VA_ARGS__)
>
> where the optional arguments passed to the macro are expanded and
> must be valid for a call to a builtin function. I think this is
> how WG14 expected things to work and so #1 would be rejected due
> to use of an undeclared identifier, similar to what would happen
> with `1 || blah` in an expression (`blah` is not evaluated, but it
> still has to be semantically valid). And #2 would increment
> __COUNTER__ because the macro is expanded for the call to the builtin.
>
> Or whether the committees expect something more like:
>
> #define va_start(list, ...) __builtin_va_start(list)
>
> where the optional arguments passed to the macro are not expanded
> and therefore don't have to be valid beyond what the preprocessor
> requires. I think this is how WG21 expected things to work, so #1
> would be accepted and #2 would not increment __COUNTER__.
>
> ~Aaron
>
>
>
> On Tue, Nov 11, 2025 at 6:46 AM Alex Celeste via Liaison
> <liaison_at_[hidden]> wrote:
>
> I believe we discussed basically this same question within
> WG14 before adopting the wording, and the "evaluated" wording
> was a revision/compromise intended to reduce the structness of
> the `va_start` macro so that it could still report errors if
> they were needed, but not to require anything special of it
> above the behaviour that would be expected for any other macro
> that doesn't exand its arguments into an evaluated position.
>
> So that second argument certainly isn't supposed to be being
> discarded by any special mechanism that would block
> incrementing `__COUNTER__` by some means not available to a
> user-defined macro. The original wording was stricter and
> might have implied this, but "evaluated" was chosen to
> indicate that it's the C-level evaluation that definitely
> doesn't happen, without implying anything about macro
> expansion. The macro part of this feature should just follow
> normal macro rules.
>
> Thanks,
>
> Alex
>
> Perforce Software
>
> Alex Celeste | Elder Witch of the C Compiler, Helix QAC
> <https://www.perforce.com/products/helix-qac>
>
> _Perforce Software <https://www.perforce.com>_
>
> P +1 612.517.2100
>
> Visit Us On: _LinkedIn
> <https://www.linkedin.com/company/perforce>_ | _YouTube
> <https://www.youtube.com/user/perforcesoftware>_
>
>
> ------------------------------------------------------------------------
> *From:* Liaison <liaison-bounces_at_[hidden]> on behalf
> of J Decker via Liaison <liaison_at_[hidden]>
> *Sent:* 11 November 2025 10:53
> *To:* liaison_at_[hidden] <liaison_at_[hidden]>
> *Cc:* J Decker <d3ck0r_at_[hidden]>
> *Subject:* Re: [isocpp-wg14/wg21-liaison] Extra arguments to
> va_start
>
>
> 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
>
>
>
> *CAUTION:*This email originated from outside of the
> organization. Do not click on links or open attachments unless
> you recognize the sender and know the content is safe.
>
>
> This e-mail may contain information that is privileged or
> confidential. If you are not the intended recipient, please
> delete the e-mail and any attachments and notify us immediately.
>
>
> _______________________________________________
> Liaison mailing list
> Liaison_at_[hidden]
> Subscription:
> https://lists.isocpp.org/mailman/listinfo.cgi/liaison
> Link to this post:
> http://lists.isocpp.org/liaison/2025/11/1596.php
>
> _______________________________________________
> Liaison mailing list
> Liaison_at_[hidden]
> Subscription: https://lists.isocpp.org/mailman/listinfo.cgi/liaison
> Link to this post: http://lists.isocpp.org/liaison/2025/11/1597.php
>
>
> _______________________________________________
> Liaison mailing list
> Liaison_at_[hidden]
> Subscription:https://lists.isocpp.org/mailman/listinfo.cgi/liaison
> Link to this post:http://lists.isocpp.org/liaison/2025/11/1601.php
Received on 2025-11-12 18:02:51
