[RFC PATCH] c++: C++26 va_start - part of P3348R4 - C++26 should refer to C23 not C17

Jason Merrill jason@redhat.com
Sun Oct 5 15:00:16 GMT 2025


On 10/4/25 10:13 AM, Jakub Jelinek wrote:
> Hi!
> 
> The C++26 https://wg21.link/P3348R4 C++26 should refer to C23 not C17
> paper among other things changes va_start macro in the similar way
> how C23 has changed it.  Now, unlike C17 and older, C++ has since forever
> allowed int (...) but just one wasn't able to use va_start/va_arg/va_end
> in such functions.
> With the current C++26 draft wording, we'd have to
>    #define va_start(V, ...) __builtin_va_start (V, 0)
> like we've used for C23 before the PR107980 change.
> But Jonathan has kindly filed
> https://cplusplus.github.io/LWG/issue4388
> which similarly to C23 will if accepted allow to define it as
>    #define va_start(...) __builtin_c23_va_start(__VA_ARGS__)
> and let the compiler diagnose undesirable cases (see stdarg6.C
> testcase in the patch for what it can diagnose, basically anything
> that isn't either va_start (ap) or va_start (ap, i) where i is the
> last argument's identifier).  This patch implements what assumes
> LWG4388 will pass.
> 
> Oh, I forgot to enable
>    #define __STDC_VERSION_STDARG_H__ 202311L
> also for C++26, shall I do this in this patch or incrementally?

In this patch seems desirable.

> Anyway, the hardest part is actually something different.
> C23 had to differentiate between C99 void foo (); i.e. unspecified
> arguments (but not stdarg) and the new C23 void bar (...); which
> is stdarg, but in both cases TYPE_ARG_TYPES (fntype) is NULL.
> This has been implemented through the new TYPE_NO_NAMED_ARGS_STDARG_P
> flag, fntypes with that flag set are considered stdarg_p and allow
> va_start in those, while fntypes with NULL TYPE_ARG_TYPES but the
> flag cleared are not stdarg_p, can accept any number of arguments
> but can't use va_start.
> So, I had to change various places in the C++ FE to pass true
> as the third argument to build_function_type for calls which are
> meant to be (...) so that one can actually use va_start in those.
> 
> Could do it only for C++26 if you want, the patch does it for all
> std modes for now.
> 
> Anyway, first bootstrapped/regtested the patch without the
> (def_fn_type, c_common_nodes_and_builtins) hunks in c-common.cc and
> without the g++.dg/opt/pr60849.C test change.
> 
> This resulted in
> +FAIL: g++.dg/opt/pr60849.C  -std=gnu++?? (internal compiler error: canonical types differ for identical types 'int(...)' and 'int(...)')
> +FAIL: g++.dg/opt/pr60849.C  -std=gnu++?? (test for excess errors)
> +UNRESOLVED: c-c++-common/torture/harden-cfr-bret*.c   -O*   scan-tree-dump-times hardcfr "__builtin_trap" 1
> +UNRESOLVED: c-c++-common/torture/harden-cfr-bret*.c   -O*   scan-tree-dump-times hardcfr "__hardcfr_check" 2
> +FAIL: c-c++-common/torture/harden-cfr-bret*.c   -O*  (internal compiler error: canonical types differ for identical types 'void(...)' and 'void(...)')
> +FAIL: c-c++-common/torture/harden-cfr-bret*.c   -O*  (test for excess errors)
> regressions (many different harden-cfr-bret*.c tests and -O* combinations
> and all -std modes of pr60849.C.
> The problem is that c-family/c-common.cc uses TYPE_ARG_TYPES NULL
> FUNCTION_TYPEs for kind of unspecified arguments even for C++ and
> also for C23 (even when it doesn't have them).  Both for some
> builtins (e.g. __builtin_signbit (...) or __builtin_isnan (...)
> or other type-generic builtins or even signbit (...)/isnan (...))
> and for #pragma weak.  The ICEs are because structural_comptypes
> doesn't compare TYPE_NO_NAMED_ARGS_STDARG_P flag yet TYPE_CANONICAL
> for those types are different because that flag is compared by
> the middle-end for type hashing etc.
> 
> Next I've tried the two extra hunks in c-common.cc and
> tweaking pr60849.C as in the patch.  This instead has
> +FAIL: c-c++-common/dfp/signbit-2.c  -std=gnu++?? (test for excess errors)
> +UNRESOLVED: c-c++-common/dfp/signbit-2.c  -std=gnu++?? compilation failed to produce executable
> +FAIL: g++.dg/ext/weak1.C  -std=gnu++?? (test for excess errors)
> +FAIL: g++.dg/other/isnan.C  -std=c++?? (test for excess errors)
> regressions.
> 
> So, I think we need to decide what we want for the builtins
> and #pragma weak.  One possibility is treat them like before,
> non-stdarg functions with unspecified arguments (i.e. kind of C99
> in C++), change structural_comptypes to also compare
> TYPE_NO_NAMED_ARGS_STDARG_P flag (to make the ICE go away), but
> having permerrors when somebody like harden-cfr* or pr60849.C
> tries to cast those builtin/#pragma weak unspecified non-stdarg arguments
> to (...) arguments.  I think this is a better option, though perhaps
> we could error when somebody tries to do decltype (__builtin_signbit)
> or something similar to avoid those magic unspecified argument types
> leaking into normal C++ code.
>
> Or don't have any unspecified argument functions, not even builtins
> and require them to be (...) but then live with
> those 3 tests not working.
> One is trying to declare
> extern "C" int signbit (double);
> which is kind of wrong because signbit is a builtin type-generic
> macro and no signbit function exists, another is doing the same
> for isnan:
> extern "C" int isnan (double);
> (I think we could live with these 2)

Pedantically, these only seem like errors at link time if in fact no 
such function is provided by the library, and glibc provides a 
definition of isnan(double).  And the isnan test isn't even linked.  A 
permerror seems wrong, it should only be a warning.

But also I don't see why we can't handle these redeclarations just as 
before after adding the flag; we just need to adjust the prototype_p 
check in decls_match.

> but weak1.C is
> #pragma weak bar1 = foo1
> extern "C" void foo1 (void) {}
> where #pragma weak kind of introduces a (...) type.

I would think the name introduced by #pragma weak should have the type 
of the target; by the time we declare the alias in 
maybe_apply_pending_pragma_weaks we have a declaration for the target or 
it's an error.

Jason



More information about the Libstdc++ mailing list