Hi,

On Thu, 9 Oct 2025 at 22:27, Jason Merrill <[email protected]> wrote:
>
> On 10/8/25 6:56 PM, Jakub Jelinek wrote:
> > On Wed, Oct 08, 2025 at 03:13:31PM +0100, Jason Merrill wrote:
> >>> --- gcc/ginclude/stdarg.h.jj        2025-10-04 09:42:23.775001859 +0200
> >>> +++ gcc/ginclude/stdarg.h   2025-10-06 16:05:22.066861182 +0200
> >>> @@ -44,7 +44,8 @@ typedef __builtin_va_list __gnuc_va_list
> >>>       if this invocation was from the user program.  */
> >>>    #ifdef _STDARG_H
> >>> -#if defined __STDC_VERSION__ && __STDC_VERSION__ > 201710L
> >>> +#if (defined __STDC_VERSION__ && __STDC_VERSION__ > 201710L) \
> >>> +    || __cplusplus + 0 >= 202400L
> >>
> >> Why __cplusplus + 0?  I don't see that pattern anywhere else.
> >
> > It was the first time I saw it as well, I thought there is some hidden
> > reason for it, but -Wundef warns about both #if foo >= 202400
> > and #if foo + 0 >= 202400 equally, so I've dropped it.
> > Most likely the header is just too old.
> >
> > It is there in
> > #if !defined(__STRICT_ANSI__) || __STDC_VERSION__ + 0 >= 199900L \
> >      || __cplusplus + 0 >= 201103L
> > #define va_copy(d,s)    __builtin_va_copy(d,s)
> > #endif
> >
> >>> --- gcc/cp/parser.cc.jj     2025-10-04 09:50:00.063564536 +0200
> >>> +++ gcc/cp/parser.cc        2025-10-06 17:05:27.170484820 +0200
> >>> @@ -6407,6 +6407,118 @@ cp_parser_primary_expression (cp_parser
> >>>         return build_x_va_arg (combined_loc, expression, type);
> >>>       }
> >>> +   case RID_C23_VA_START:
> >>
> >> Please factor this out into a separate function, with a grammar summary in
> >> the comment.
> >
> > Done.
> >
> >> Why not use cp_parser_skip_to_closing_parenthesis instead of this loop?
> >> Needs a comment if there's a reason.
> >
> > Added comment.  With the current wording which matches the C23 wording, e.g.
> >    va_start (ap, ()()()[[[}}});
> > and
> >    va_start (ap, ]]]]]]{{{{{{);
> > are valid (though we warn about those), all it requires that ()s are
> > balanced and all preprocessing tokens actually convertible to tokens.
> >
> >>> +       location_t combined_loc
> >>> +         = make_location (arg_loc, start_loc, finish_loc);
> >>> +       parens.require_close (parser);
> >>
> >> require_close returns the token, so it seems unnecessary to peek it first.
> >
> > require_close returns the token or NULL, so I'd need to deal with what to
> > do if it returns NULL.
> >
> >>> @@ -15324,7 +15326,9 @@ grokdeclarator (const cp_declarator *dec
> >>>             is_xobj_member_function = false;
> >>>           }
> >>> -       type = build_function_type (type, arg_types);
> >>> +       type = build_function_type (type, arg_types,
> >>> +                                   cxx_dialect >= cxx26
> >>> +                                   && arg_types == NULL_TREE);
> >>
> >> How about adding cp_build_function_type to encapsulate this pattern?
> >
> > Done.
>
> OK, thanks.
>
> > 2025-10-08  Jakub Jelinek  <[email protected]>
> >
> > gcc/
> >       * ginclude/stdarg.h (va_start): Use __builtin_c23_va_start
> >       also for C++26.
> >       (__STDC_VERSION_STDARG_H__): Also define for C++26.
> > gcc/c-family/
> >       * c-common.h (D_CXX26): Define.
> >       * c-common.cc (c_common_resword): Add D_CXX26 to
> >       __builtin_c23_va_start flags, mention D_CXX26 in comment.
> > gcc/cp/
> >       * cp-tree.h (cp_build_function_type): Declare.
> >       * lex.cc: Implement va_start changes from P3348R4 - C++26 should
> >       refer to C23 not C17 paper.
> >       (init_reswords): Set D_CXX26 in mask for C++23 and older.
> >       * parser.cc (cp_parser_primary_expression): Handle RID_C23_VA_START.
> >       (cp_parser_builtin_c23_va_start): New function.
> >       * cp-objcp-common.cc (names_builtin_p): Likewise.
> >       * decl.cc (grokfndecl, check_function_type): Pass
> >       TYPE_NO_NAMED_ARGS_STDARG_P as last arg to build_function_type.
> >       (grokdeclarator, static_fn_type): Use cp_build_function_type instead
> >       of build_function_type.
> >       * typeck.cc (merge_types): Likewise.
> >       (structural_comptypes): Return false for TYPE_NO_NAMED_ARGS_STDARG_P
> >       differences.
> >       * lambda.cc (maybe_add_lambda_conv_op): Use cp_build_function_type
> >       instead of build_function_type.
> >       * tree.cc (cp_build_function_type): New function.
> >       (strip_typedefs): Pass TYPE_NO_NAMED_ARGS_STDARG_P as last arg to
> >       build_function_type.
> >       * name-lookup.cc (push_local_extern_decl_alias): Likewise.
> >       * module.cc (trees_in::tree_node): Use cp_build_function_type instead
> >       of build_function_type.
> >       * pt.cc (copy_default_args_to_explicit_spec,
> >       rebuild_function_or_method_type, build_deduction_guide): Likewise.
> >       (alias_ctad_tweaks): Pass TYPE_NO_NAMED_ARGS_STDARG_P as last arg to
> >       build_function_type.
> >       * decl2.cc (change_return_type, cp_reconstruct_complex_type):
> >       Likewise.
> > gcc/testsuite/
> >       * c-c++-common/cpp/has-builtin-4.c: Expect
> >       __has_builtin (__builtin_c23_va_start) == 1 also for C++26.
> >       * c-c++-common/Wvarargs.c (foo3): Don't expect undefined behavior
> >       warning for C++26.
> >       * g++.dg/cpp26/stdarg1.C: New test.
> >       * g++.dg/cpp26/stdarg2.C: New test.
> >       * g++.dg/cpp26/stdarg3.C: New test.
> >       * g++.dg/cpp26/stdarg4.C: New test.
> >       * g++.dg/cpp26/stdarg5.C: New test.
> >       * g++.dg/cpp26/stdarg6.C: New test.
> >       * g++.dg/cpp26/stdarg7.C: New test.
> >       * g++.dg/cpp26/stdarg8.C: New test.
> >       * g++.dg/cpp26/stdarg9.C: New test.
> >       * g++.dg/opt/pr60849.C (foo): Add explicit cast.
> >

We've noticed a regression (on aarch64):
Running g++:g++.dg/gomp/gomp.exp ...
FAIL: c-c++-common/gomp/append-args-7.c -std=c++26
scan-tree-dump-times gimple "f3 \\(obj1, obj2, 1, a, cp, d\\);" 1
FAIL: c-c++-common/gomp/append-args-7.c -std=c++26 (test for excess errors)

g++.log says:
/gcc/testsuite/c-c++-common/gomp/append-args-7.c: In function 'void g2(...)':
/gcc/testsuite/c-c++-common/gomp/append-args-7.c:20:6: error: argument
1 of 'void f2(...)' must be of 'omp_interop_t'
/gcc/testsuite/c-c++-common/gomp/append-args-7.c:23:45: note:
'append_args' specified here

Can you have a look?
Thanks,

Christophe

> > --- gcc/ginclude/stdarg.h.jj  2025-10-08 09:23:48.812694862 +0200
> > +++ gcc/ginclude/stdarg.h     2025-10-08 18:44:28.803856008 +0200
> > @@ -44,7 +44,8 @@ typedef __builtin_va_list __gnuc_va_list
> >      if this invocation was from the user program.  */
> >   #ifdef _STDARG_H
> >
> > -#if defined __STDC_VERSION__ && __STDC_VERSION__ > 201710L
> > +#if (defined __STDC_VERSION__ && __STDC_VERSION__ > 201710L) \
> > +    || __cplusplus >= 202400L
> >   #define va_start(...) __builtin_c23_va_start(__VA_ARGS__)
> >   #else
> >   #define va_start(v,l)       __builtin_va_start(v,l)
> > @@ -125,7 +126,8 @@ typedef __gnuc_va_list va_list;
> >
> >   #endif /* not __svr4__ */
> >
> > -#if defined __STDC_VERSION__ && __STDC_VERSION__ > 201710L
> > +#if (defined __STDC_VERSION__ && __STDC_VERSION__ > 201710L) \
> > +    || __cplusplus >= 202400L
> >   #define __STDC_VERSION_STDARG_H__   202311L
> >   #endif
> >
> > --- gcc/c-family/c-common.h.jj        2025-10-08 09:23:47.940706893 +0200
> > +++ gcc/c-family/c-common.h   2025-10-08 18:43:37.988553400 +0200
> > @@ -448,6 +448,7 @@ extern machine_mode c_default_pointer_mo
> >   #define D_CXX20             0x8000  /* In C++, C++20 only.  */
> >   #define D_CXX_COROUTINES 0x10000  /* In C++, only with coroutines.  */
> >   #define D_CXX_MODULES       0x20000  /* In C++, only with modules.  */
> > +#define D_CXX26         0x40000      /* In C++, C++26 only.  */
> >
> >   #define D_CXX_CONCEPTS_FLAGS D_CXXONLY | D_CXX_CONCEPTS
> >   #define D_CXX_CHAR8_T_FLAGS D_CXXONLY | D_CXX_CHAR8_T
> > --- gcc/c-family/c-common.cc.jj       2025-10-08 09:23:47.891707569 +0200
> > +++ gcc/c-family/c-common.cc  2025-10-08 18:43:37.990553372 +0200
> > @@ -376,9 +376,10 @@ static bool nonnull_check_p (tree, unsig
> >      C --std=c17: D_C23 | D_CXXONLY | D_OBJC
> >      C --std=c23: D_CXXONLY | D_OBJC
> >      ObjC is like C except that D_OBJC and D_CXX_OBJC are not set
> > -   C++ --std=c++98: D_CONLY | D_CXX11 | D_CXX20 | D_OBJC
> > -   C++ --std=c++11: D_CONLY | D_CXX20 | D_OBJC
> > -   C++ --std=c++20: D_CONLY | D_OBJC
> > +   C++ --std=c++98: D_CONLY | D_CXX11 | D_CXX20 | D_CXX26 | D_OBJC
> > +   C++ --std=c++11: D_CONLY | D_CXX20 | D_CXX26 | D_OBJC
> > +   C++ --std=c++20: D_CONLY | D_CXX26 | D_OBJC
> > +   C++ --std=c++26: D_CONLY | D_OBJC
> >      ObjC++ is like C++ except that D_OBJC is not set
> >
> >      If -fno-asm is used, D_ASM is added to the mask.  If
> > @@ -462,7 +463,7 @@ const struct c_common_resword c_common_r
> >     { "__builtin_tgmath", RID_BUILTIN_TGMATH, D_CONLY },
> >     { "__builtin_offsetof", RID_OFFSETOF, 0 },
> >     { "__builtin_types_compatible_p", RID_TYPES_COMPATIBLE_P, D_CONLY },
> > -  { "__builtin_c23_va_start", RID_C23_VA_START,      D_C23 },
> > +  { "__builtin_c23_va_start", RID_C23_VA_START,      D_C23 | D_CXX26 },
> >     { "__builtin_va_arg",     RID_VA_ARG,     0 },
> >     { "__complex",    RID_COMPLEX,    0 },
> >     { "__complex__",  RID_COMPLEX,    0 },
> > --- gcc/cp/cp-tree.h.jj       2025-10-08 17:46:23.319698090 +0200
> > +++ gcc/cp/cp-tree.h  2025-10-08 19:36:19.714162019 +0200
> > @@ -8491,6 +8491,7 @@ extern tree cp_build_reference_type             (tr
> >   extern tree move                            (tree);
> >   extern tree cp_build_qualified_type         (tree, int,
> >                                                tsubst_flags_t = 
> > tf_warning_or_error);
> > +extern tree cp_build_function_type           (tree, tree);
> >   extern bool cv_qualified_p                  (const_tree);
> >   extern tree cv_unqualified                  (tree);
> >   extern special_function_kind special_function_p (const_tree);
> > --- gcc/cp/lex.cc.jj  2025-10-08 09:23:48.434700078 +0200
> > +++ gcc/cp/lex.cc     2025-10-08 18:43:37.990553372 +0200
> > @@ -243,6 +243,8 @@ init_reswords (void)
> >       mask |= D_CXX11;
> >     if (cxx_dialect < cxx20)
> >       mask |= D_CXX20;
> > +  if (cxx_dialect < cxx26)
> > +    mask |= D_CXX26;
> >     if (!flag_concepts)
> >       mask |= D_CXX_CONCEPTS;
> >     if (!flag_coroutines)
> > --- gcc/cp/parser.cc.jj       2025-10-08 09:23:48.654697042 +0200
> > +++ gcc/cp/parser.cc  2025-10-08 19:28:36.930512900 +0200
> > @@ -2575,6 +2575,7 @@ static cp_expr cp_parser_expression
> >     (cp_parser *, cp_id_kind * = NULL, bool = false, bool = false, bool = 
> > false);
> >   static cp_expr cp_parser_constant_expression
> >     (cp_parser *, int = 0, bool * = NULL, bool = false);
> > +static cp_expr cp_parser_builtin_c23_va_start (cp_parser *);
> >   static cp_expr cp_parser_builtin_offsetof
> >     (cp_parser *);
> >   static cp_expr cp_parser_lambda_expression
> > @@ -6407,6 +6408,9 @@ cp_parser_primary_expression (cp_parser
> >           return build_x_va_arg (combined_loc, expression, type);
> >         }
> >
> > +     case RID_C23_VA_START:
> > +       return cp_parser_builtin_c23_va_start (parser);
> > +
> >       case RID_OFFSETOF:
> >         return cp_parser_builtin_offsetof (parser);
> >
> > @@ -11497,6 +11501,133 @@ cp_parser_constant_expression (cp_parser
> >     return expression;
> >   }
> >
> > +/* Parse __builtin_c23_va_start.
> > +
> > +   c23-va-start-expression:
> > +     __builtin_c23_va_start ( assignment-expression )
> > +     __builtin_c23_va_start ( assignment-expression , identifier )
> > +     __builtin_c23_va_start ( assignment-expression , tokens[opt] )
> > +
> > +   The first form is the expected new C++26 form, the second if
> > +   identifier is the name of the last parameter before ... is meant
> > +   for backwards compatibility with C++23 and older.
> > +   The third form where LWG4388 requires all the preprocessing tokens
> > +   to be convertible to tokens and it can't contain unbalanced
> > +   parentheses is parsed with a warning and the tokens are just skipped.
> > +   This is because C++26 like C23 defines va_start macro as
> > +   va_start (ap, ...) and says second and later arguments to the macro
> > +   are discarded, yet we want to diagnose when people use something
> > +   which wasn't valid before C++26 and is not the single argument
> > +   va_start either.  */
> > +
> > +static cp_expr
> > +cp_parser_builtin_c23_va_start (cp_parser *parser)
> > +{
> > +  location_t start_loc = cp_lexer_peek_token (parser->lexer)->location;
> > +  cp_lexer_consume_token (parser->lexer);
> > +  /* Look for the opening `('.  */
> > +  matching_parens parens;
> > +  parens.require_open (parser);
> > +  location_t arg_loc = cp_lexer_peek_token (parser->lexer)->location;
> > +  /* Now, parse the assignment-expression.  */
> > +  tree expression = cp_parser_assignment_expression (parser);
> > +  if (!cp_lexer_next_token_is (parser->lexer, CPP_CLOSE_PAREN))
> > +    {
> > +      location_t cloc = cp_lexer_peek_token (parser->lexer)->location;
> > +      if (!cp_parser_require (parser, CPP_COMMA, RT_COMMA))
> > +     {
> > +       cp_parser_skip_to_closing_parenthesis (parser, false, false,
> > +                                              /*consume_paren=*/ true);
> > +       return error_mark_node;
> > +     }
> > +      if (cp_lexer_next_token_is (parser->lexer, CPP_NAME)
> > +       && cp_lexer_nth_token_is (parser->lexer, 2, CPP_CLOSE_PAREN))
> > +     {
> > +       tree name = cp_lexer_peek_token (parser->lexer)->u.value;
> > +       location_t nloc = cp_lexer_peek_token (parser->lexer)->location;
> > +       tree decl = lookup_name (name);
> > +       tree last_parm = tree_last (DECL_ARGUMENTS (current_function_decl));
> > +       if (!last_parm || decl != last_parm)
> > +         warning_at (nloc, OPT_Wvarargs, "optional second parameter of "
> > +                     "%<va_start%> not last named argument");
> > +       else
> > +         {
> > +           /* __builtin_va_start parsing does mark the argument as used and
> > +              read, for -Wunused* purposes mark it the same.  */
> > +           TREE_USED (last_parm) = 1;
> > +           mark_exp_read (last_parm);
> > +         }
> > +       cp_lexer_consume_token (parser->lexer);
> > +     }
> > +      else
> > +     {
> > +       unsigned nesting_depth = 0;
> > +       location_t sloc = cp_lexer_peek_token (parser->lexer)->location;
> > +       location_t eloc = sloc;
> > +
> > +       /* For va_start (ap,) the ) comes from stdarg.h.
> > +          Use location of , in that case, otherwise without 
> > -Wsystem-headers
> > +          nothing is reported.  After all, the problematic token is the
> > +          comma in that case.  */
> > +       if (cp_lexer_next_token_is (parser->lexer, CPP_CLOSE_PAREN))
> > +         sloc = eloc = cloc;
> > +       /* Not using cp_parser_skip_to_closing_parenthesis here, because
> > +          the tokens in second and further arguments don't have to be
> > +          fully balanced, only can't contain unbalanced parentheses.
> > +          So, va_start (ap, [[[[[[[[[{{{{{{{{{}]);
> > +          is valid C++ for which we want to warn,
> > +          #define X id); something (
> > +          va_start (ap, X);
> > +          is IFNDR (not detectable unless the preprocessor special cases
> > +          va_start macro).  */
> > +       while (true)
> > +         {
> > +           cp_token *token = cp_lexer_peek_token (parser->lexer);
> > +           if (token->type == CPP_CLOSE_PAREN && !nesting_depth)
> > +             break;
> > +
> > +           if (token->type == CPP_EOF)
> > +             break;
> > +           if (token->type == CPP_OPEN_PAREN)
> > +             ++nesting_depth;
> > +           else if (token->type == CPP_CLOSE_PAREN)
> > +             --nesting_depth;
> > +           else if (token->type == CPP_PRAGMA)
> > +             {
> > +               cp_parser_skip_to_pragma_eol (parser, token);
> > +               continue;
> > +             }
> > +           eloc = token->location;
> > +           cp_lexer_consume_token (parser->lexer);
> > +         }
> > +       if (sloc != eloc)
> > +         sloc = make_location (sloc, sloc, eloc);
> > +       warning_at (sloc, OPT_Wvarargs,
> > +                   "%<va_start%> macro used with additional "
> > +                   "arguments other than identifier of the "
> > +                   "last named argument");
> > +     }
> > +    }
> > +  /* Look for the closing `)'.  */
> > +  location_t finish_loc = cp_lexer_peek_token (parser->lexer)->location;
> > +  /* Construct a location of the form:
> > +     __builtin_c23_va_start (ap, arg)
> > +     ~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~
> > +     with the caret at the first argument, ranging from the start
> > +     of the "__builtin_c23_va_start" token to the close paren.  */
> > +  location_t combined_loc = make_location (arg_loc, start_loc, finish_loc);
> > +  parens.require_close (parser);
> > +  tree fndecl = builtin_decl_explicit (BUILT_IN_VA_START);
> > +  releasing_vec args;
> > +  vec_safe_push (args, expression);
> > +  vec_safe_push (args, integer_zero_node);
> > +  tree ret = finish_call_expr (fndecl, &args, false, true,
> > +                            tf_warning_or_error);
> > +  if (TREE_CODE (ret) == CALL_EXPR)
> > +    SET_EXPR_LOCATION (ret, combined_loc);
> > +  return cp_expr (ret, combined_loc);
> > +}
> > +
> >   /* Parse __builtin_offsetof.
> >
> >      offsetof-expression:
> > --- gcc/cp/cp-objcp-common.cc.jj      2025-10-08 09:23:48.066705154 +0200
> > +++ gcc/cp/cp-objcp-common.cc 2025-10-08 18:43:37.997553276 +0200
> > @@ -588,6 +588,7 @@ names_builtin_p (const char *name)
> >       case RID_BUILTIN_BIT_CAST:
> >       case RID_OFFSETOF:
> >       case RID_VA_ARG:
> > +    case RID_C23_VA_START:
> >         return 1;
> >       case RID_BUILTIN_OPERATOR_NEW:
> >       case RID_BUILTIN_OPERATOR_DELETE:
> > --- gcc/cp/decl.cc.jj 2025-10-08 09:23:48.125704341 +0200
> > +++ gcc/cp/decl.cc    2025-10-08 19:33:17.164667187 +0200
> > @@ -12413,11 +12413,13 @@ grokfndecl (tree ctype,
> >         if (!same_type_p (TREE_TYPE (TREE_TYPE (decl)),
> >                       integer_type_node))
> >       {
> > -       tree oldtypeargs = TYPE_ARG_TYPES (TREE_TYPE (decl));
> > +       tree dtype = TREE_TYPE (decl);
> > +       tree oldtypeargs = TYPE_ARG_TYPES (dtype);
> >         tree newtype;
> >         error_at (declspecs->locations[ds_type_spec],
> >                   "%<::main%> must return %<int%>");
> > -       newtype = build_function_type (integer_type_node, oldtypeargs);
> > +       newtype = build_function_type (integer_type_node, oldtypeargs,
> > +                                      TYPE_NO_NAMED_ARGS_STDARG_P (dtype));
> >         TREE_TYPE (decl) = newtype;
> >       }
> >         if (warn_main)
> > @@ -15324,7 +15326,7 @@ grokdeclarator (const cp_declarator *dec
> >               is_xobj_member_function = false;
> >             }
> >
> > -         type = build_function_type (type, arg_types);
> > +         type = cp_build_function_type (type, arg_types);
> >
> >           tree attrs = declarator->std_attributes;
> >           if (tx_qual)
> > @@ -19312,7 +19314,8 @@ check_function_type (tree decl, tree cur
> >                                            void_type_node,
> >                                            TREE_CHAIN (args));
> >         else
> > -     fntype = build_function_type (void_type_node, args);
> > +     fntype = build_function_type (void_type_node, args,
> > +                                   TYPE_NO_NAMED_ARGS_STDARG_P (fntype));
> >         fntype = (cp_build_type_attribute_variant
> >               (fntype, TYPE_ATTRIBUTES (TREE_TYPE (decl))));
> >         fntype = cxx_copy_lang_qualifiers (fntype, TREE_TYPE (decl));
> > @@ -20809,7 +20812,7 @@ static_fn_type (tree memfntype)
> >       return memfntype;
> >     gcc_assert (TREE_CODE (memfntype) == METHOD_TYPE);
> >     args = TYPE_ARG_TYPES (memfntype);
> > -  fntype = build_function_type (TREE_TYPE (memfntype), TREE_CHAIN (args));
> > +  fntype = cp_build_function_type (TREE_TYPE (memfntype), TREE_CHAIN 
> > (args));
> >     fntype = apply_memfn_quals (fntype, type_memfn_quals (memfntype));
> >     fntype = (cp_build_type_attribute_variant
> >           (fntype, TYPE_ATTRIBUTES (memfntype)));
> > --- gcc/cp/typeck.cc.jj       2025-10-08 09:23:48.739695870 +0200
> > +++ gcc/cp/typeck.cc  2025-10-08 19:35:25.593904723 +0200
> > @@ -1035,7 +1035,7 @@ merge_types (tree t1, tree t2)
> >       gcc_assert (quals == type_memfn_quals (t2));
> >       gcc_assert (rqual == type_memfn_rqual (t2));
> >
> > -     tree rval = build_function_type (valtype, parms);
> > +     tree rval = cp_build_function_type (valtype, parms);
> >       rval = apply_memfn_quals (rval, quals);
> >       tree raises = merge_exception_specifiers (TYPE_RAISES_EXCEPTIONS (t1),
> >                                                 TYPE_RAISES_EXCEPTIONS 
> > (t2));
> > @@ -1058,10 +1058,10 @@ merge_types (tree t1, tree t2)
> >       /* If this was a member function type, get back to the
> >          original type of type member function (i.e., without
> >          the class instance variable up front.  */
> > -     t1 = build_function_type (TREE_TYPE (t1),
> > -                               TREE_CHAIN (TYPE_ARG_TYPES (t1)));
> > -     t2 = build_function_type (TREE_TYPE (t2),
> > -                               TREE_CHAIN (TYPE_ARG_TYPES (t2)));
> > +     t1 = cp_build_function_type (TREE_TYPE (t1),
> > +                                  TREE_CHAIN (TYPE_ARG_TYPES (t1)));
> > +     t2 = cp_build_function_type (TREE_TYPE (t2),
> > +                                  TREE_CHAIN (TYPE_ARG_TYPES (t2)));
> >       t3 = merge_types (t1, t2);
> >       t3 = build_method_type_directly (basetype, TREE_TYPE (t3),
> >                                        TYPE_ARG_TYPES (t3));
> > @@ -1550,8 +1550,11 @@ structural_comptypes (tree t1, tree t2,
> >       return false;
> >         break;
> >
> > -    case METHOD_TYPE:
> >       case FUNCTION_TYPE:
> > +      if (TYPE_NO_NAMED_ARGS_STDARG_P (t1) != TYPE_NO_NAMED_ARGS_STDARG_P 
> > (t2))
> > +     return false;
> > +      /* FALLTHRU */
> > +    case METHOD_TYPE:
> >         /* Exception specs and memfn_rquals were checked above.  */
> >         if (!same_type_p (TREE_TYPE (t1), TREE_TYPE (t2)))
> >       return false;
> > --- gcc/cp/lambda.cc.jj       2025-10-08 09:23:48.364701044 +0200
> > +++ gcc/cp/lambda.cc  2025-10-08 19:33:52.778178456 +0200
> > @@ -1329,9 +1329,10 @@ maybe_add_lambda_conv_op (tree type)
> >       }
> >
> >     tree stattype
> > -    = build_function_type (fn_result, FUNCTION_FIRST_USER_PARMTYPE 
> > (callop));
> > -  stattype = (cp_build_type_attribute_variant
> > -           (stattype, TYPE_ATTRIBUTES (optype)));
> > +    = cp_build_function_type (fn_result,
> > +                           FUNCTION_FIRST_USER_PARMTYPE (callop));
> > +  stattype = cp_build_type_attribute_variant (stattype,
> > +                                           TYPE_ATTRIBUTES (optype));
> >     if (flag_noexcept_type
> >         && TYPE_NOTHROW_P (TREE_TYPE (callop)))
> >       stattype = build_exception_variant (stattype, noexcept_true_spec);
> > --- gcc/cp/tree.cc.jj 2025-10-08 09:23:48.733695953 +0200
> > +++ gcc/cp/tree.cc    2025-10-08 19:31:49.907864636 +0200
> > @@ -1537,6 +1537,19 @@ cp_build_qualified_type (tree type, int
> >     return result;
> >   }
> >
> > +/* Return a FUNCTION_TYPE for a function returning VALUE_TYPE
> > +   with ARG_TYPES arguments.  Wrapper around build_function_type
> > +   which ensures TYPE_NO_NAMED_ARGS_STDARG_P is set if ARG_TYPES
> > +   is NULL for C++26.  */
> > +
> > +tree
> > +cp_build_function_type (tree value_type, tree arg_types)
> > +{
> > +  return build_function_type (value_type, arg_types,
> > +                           cxx_dialect >= cxx26
> > +                           && arg_types == NULL_TREE);
> > +}
> > +
> >   /* Return TYPE with const and volatile removed.  */
> >
> >   tree
> > @@ -1782,7 +1795,8 @@ strip_typedefs (tree t, bool *remove_att
> >         }
> >       else
> >         {
> > -         result = build_function_type (type, arg_types);
> > +         result = build_function_type (type, arg_types,
> > +                                       TYPE_NO_NAMED_ARGS_STDARG_P (t));
> >           result = apply_memfn_quals (result, type_memfn_quals (t));
> >         }
> >
> > --- gcc/cp/name-lookup.cc.jj  2025-10-08 09:23:48.588697953 +0200
> > +++ gcc/cp/name-lookup.cc     2025-10-08 18:43:38.003553194 +0200
> > @@ -3726,7 +3726,11 @@ push_local_extern_decl_alias (tree decl)
> >                         chain = &TREE_CHAIN (*chain);
> >                       }
> >
> > -                 tree fn_type = build_function_type (TREE_TYPE (type), 
> > nargs);
> > +                 bool no_named_args_stdarg
> > +                   = TYPE_NO_NAMED_ARGS_STDARG_P (type);
> > +                 tree fn_type
> > +                   = build_function_type (TREE_TYPE (type), nargs,
> > +                                          no_named_args_stdarg);
> >
> >                   fn_type = apply_memfn_quals
> >                     (fn_type, type_memfn_quals (type));
> > --- gcc/cp/module.cc.jj       2025-10-08 09:24:14.666338175 +0200
> > +++ gcc/cp/module.cc  2025-10-08 19:34:04.217021479 +0200
> > @@ -10414,7 +10414,7 @@ trees_in::tree_node (bool is_use)
> >                 if (klass)
> >                   res = build_method_type_directly (klass, res, args);
> >                 else
> > -                 res = build_function_type (res, args);
> > +                 res = cp_build_function_type (res, args);
> >               }
> >           }
> >           break;
> > --- gcc/cp/pt.cc.jj   2025-10-08 17:46:17.919772189 +0200
> > +++ gcc/cp/pt.cc      2025-10-08 19:34:34.908600297 +0200
> > @@ -2654,8 +2654,7 @@ copy_default_args_to_explicit_spec (tree
> >                                            new_spec_types);
> >       }
> >     else
> > -    new_type = build_function_type (TREE_TYPE (old_type),
> > -                                 new_spec_types);
> > +    new_type = cp_build_function_type (TREE_TYPE (old_type), 
> > new_spec_types);
> >     new_type = cp_build_type_attribute_variant (new_type,
> >                                             TYPE_ATTRIBUTES (old_type));
> >     new_type = cxx_copy_lang_qualifiers (new_type, old_type);
> > @@ -14779,7 +14778,7 @@ rebuild_function_or_method_type (tree t,
> >     tree new_type;
> >     if (TREE_CODE (t) == FUNCTION_TYPE)
> >       {
> > -      new_type = build_function_type (return_type, arg_types);
> > +      new_type = cp_build_function_type (return_type, arg_types);
> >         new_type = apply_memfn_quals (new_type, type_memfn_quals (t));
> >       }
> >     else
> > @@ -31100,7 +31099,7 @@ build_deduction_guide (tree type, tree c
> >       = copy_node (INNERMOST_TEMPLATE_PARMS (tparms));
> >       }
> >
> > -  tree fntype = build_function_type (type, fparms);
> > +  tree fntype = cp_build_function_type (type, fparms);
> >     tree ded_fn = build_lang_decl_loc (loc,
> >                                    FUNCTION_DECL,
> >                                    dguide_name (type), fntype);
> > @@ -31532,7 +31531,8 @@ alias_ctad_tweaks (tree tmpl, tree uguid
> >         tree fntype = TREE_TYPE (fprime);
> >         ret = lookup_template_class (TPARMS_PRIMARY_TEMPLATE (atparms), 
> > targs,
> >                                      in_decl, NULL_TREE, complain);
> > -       fntype = build_function_type (ret, TYPE_ARG_TYPES (fntype));
> > +       fntype = build_function_type (ret, TYPE_ARG_TYPES (fntype),
> > +                                     TYPE_NO_NAMED_ARGS_STDARG_P (fntype));
> >         TREE_TYPE (fprime) = fntype;
> >         if (TREE_CODE (fprime) == TEMPLATE_DECL)
> >           TREE_TYPE (DECL_TEMPLATE_RESULT (fprime)) = fntype;
> > --- gcc/cp/decl2.cc.jj        2025-10-08 09:23:48.248702644 +0200
> > +++ gcc/cp/decl2.cc   2025-10-08 18:43:38.009553111 +0200
> > @@ -233,7 +233,8 @@ change_return_type (tree new_ret, tree f
> >
> >     if (TREE_CODE (fntype) == FUNCTION_TYPE)
> >       {
> > -      newtype = build_function_type (new_ret, args);
> > +      newtype = build_function_type (new_ret, args,
> > +                                  TYPE_NO_NAMED_ARGS_STDARG_P (fntype));
> >         newtype = apply_memfn_quals (newtype,
> >                                  type_memfn_quals (fntype));
> >       }
> > @@ -1698,7 +1699,8 @@ cp_reconstruct_complex_type (tree type,
> >     else if (TREE_CODE (type) == FUNCTION_TYPE)
> >       {
> >         inner = cp_reconstruct_complex_type (TREE_TYPE (type), bottom);
> > -      outer = build_function_type (inner, TYPE_ARG_TYPES (type));
> > +      outer = build_function_type (inner, TYPE_ARG_TYPES (type),
> > +                                TYPE_NO_NAMED_ARGS_STDARG_P (type));
> >         outer = apply_memfn_quals (outer, type_memfn_quals (type));
> >       }
> >     else if (TREE_CODE (type) == METHOD_TYPE)
> > --- gcc/testsuite/c-c++-common/cpp/has-builtin-4.c.jj 2025-10-08 
> > 09:23:48.937693138 +0200
> > +++ gcc/testsuite/c-c++-common/cpp/has-builtin-4.c    2025-10-08 
> > 18:43:38.025552892 +0200
> > @@ -9,7 +9,7 @@
> >   #if __has_builtin (__builtin_va_arg) != 1
> >   #error "no __builtin_va_arg"
> >   #endif
> > -#if __STDC_VERSION__ >= 202311L
> > +#if (__STDC_VERSION__ >= 202311L || __cplusplus >= 202400L)
> >   #if __has_builtin (__builtin_c23_va_start) != 1
> >   #error "no __builtin_c23_va_start"
> >   #endif
> > --- gcc/testsuite/c-c++-common/Wvarargs.c.jj  2025-10-08 09:23:48.906693566 
> > +0200
> > +++ gcc/testsuite/c-c++-common/Wvarargs.c     2025-10-08 18:43:38.037552727 
> > +0200
> > @@ -50,6 +50,6 @@ foo3 (int a, register int b, ...)   // { d
> >   {
> >       va_list vp;
> >       /* 'b' is declared with register storage, so warn.  */
> > -    va_start (vp, b); /* { dg-warning "undefined behavior" } */
> > +    va_start (vp, b); /* { dg-warning "undefined behavior" "" { target { c 
> > || c++23_down } } } */
> >       va_end (vp);
> >   }
> > --- gcc/testsuite/g++.dg/cpp26/stdarg1.C.jj   2025-10-08 18:43:38.037552727 
> > +0200
> > +++ gcc/testsuite/g++.dg/cpp26/stdarg1.C      2025-10-08 18:43:38.037552727 
> > +0200
> > @@ -0,0 +1,158 @@
> > +// P3348R4 - C++26 should refer to C23 not C17
> > +// { dg-do run { target c++26 } }
> > +
> > +#include <stdarg.h>
> > +
> > +double
> > +f (...)
> > +{
> > +  va_list ap;
> > +  va_start (ap);
> > +  double ret = va_arg (ap, int);
> > +  ret += va_arg (ap, double);
> > +  ret += va_arg (ap, int);
> > +  ret += va_arg (ap, double);
> > +  va_end (ap);
> > +  return ret;
> > +}
> > +
> > +void
> > +g (...)
> > +{
> > +  va_list ap;
> > +  va_start (ap, random ! ignored, ignored ** text);  // { dg-warning 
> > "'va_start' macro used with additional arguments other than identifier of 
> > the last named argument" }
> > +  for (int i = 0; i < 10; i++)
> > +    if (va_arg (ap, double) != i)
> > +      __builtin_abort ();
> > +  va_end (ap);
> > +}
> > +
> > +void
> > +h1 (int x, ...)
> > +{
> > +  va_list ap;
> > +  va_start (ap);
> > +  for (int i = 0; i < 10; i++)
> > +    {
> > +      if (va_arg (ap, double) != i)
> > +     __builtin_abort ();
> > +      i++;
> > +      if (va_arg (ap, int) != i)
> > +     __builtin_abort ();
> > +    }
> > +  va_end (ap);
> > +}
> > +
> > +void
> > +h2 (int x(), ...)
> > +{
> > +  va_list ap;
> > +  va_start (ap);
> > +  for (int i = 0; i < 10; i++)
> > +    {
> > +      if (va_arg (ap, double) != i)
> > +     __builtin_abort ();
> > +      i++;
> > +      if (va_arg (ap, int) != i)
> > +     __builtin_abort ();
> > +    }
> > +  va_end (ap);
> > +}
> > +
> > +void
> > +h3 (int x[10], ...)
> > +{
> > +  va_list ap;
> > +  va_start (ap);
> > +  for (int i = 0; i < 10; i++)
> > +    {
> > +      if (va_arg (ap, double) != i)
> > +     __builtin_abort ();
> > +      i++;
> > +      if (va_arg (ap, int) != i)
> > +     __builtin_abort ();
> > +    }
> > +  va_end (ap);
> > +}
> > +
> > +void
> > +h4 (char x, ...)
> > +{
> > +  va_list ap;
> > +  va_start (ap);
> > +  for (int i = 0; i < 10; i++)
> > +    {
> > +      if (va_arg (ap, double) != i)
> > +     __builtin_abort ();
> > +      i++;
> > +      if (va_arg (ap, int) != i)
> > +     __builtin_abort ();
> > +    }
> > +  va_end (ap);
> > +}
> > +
> > +void
> > +h5 (float x, ...)
> > +{
> > +  va_list ap;
> > +  va_start (ap);
> > +  for (int i = 0; i < 10; i++)
> > +    {
> > +      if (va_arg (ap, double) != i)
> > +     __builtin_abort ();
> > +      i++;
> > +      if (va_arg (ap, int) != i)
> > +     __builtin_abort ();
> > +    }
> > +  va_end (ap);
> > +}
> > +
> > +void
> > +h6 (long x, ...)
> > +{
> > +  va_list ap;
> > +  va_start (ap);
> > +  for (int i = 0; i < 10; i++)
> > +    {
> > +      if (va_arg (ap, double) != i)
> > +     __builtin_abort ();
> > +      i++;
> > +      if (va_arg (ap, int) != i)
> > +     __builtin_abort ();
> > +    }
> > +  va_end (ap);
> > +}
> > +
> > +struct s { char c[1000]; };
> > +
> > +void
> > +h7 (struct s x, ...)
> > +{
> > +  va_list ap;
> > +  va_start (ap);
> > +  for (int i = 0; i < 10; i++)
> > +    {
> > +      if (va_arg (ap, double) != i)
> > +     __builtin_abort ();
> > +      i++;
> > +      if (va_arg (ap, int) != i)
> > +     __builtin_abort ();
> > +    }
> > +  va_end (ap);
> > +}
> > +
> > +int
> > +main ()
> > +{
> > +  if (f (1, 2.0, 3, 4.0) != 10.0)
> > +    __builtin_abort ();
> > +  g (0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0);
> > +  g (0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f);
> > +  h1 (0, 0.0, 1, 2.0, 3, 4.0, 5, 6.0, 7, 8.0, 9);
> > +  h2 (0, 0.0, 1, 2.0, 3, 4.0, 5, 6.0, 7, 8.0, 9);
> > +  h3 (0, 0.0, 1, 2.0, 3, 4.0, 5, 6.0, 7, 8.0, 9);
> > +  h4 (0, 0.0, 1, 2.0, 3, 4.0, 5, 6.0, 7, 8.0, 9);
> > +  h5 (0, 0.0, 1, 2.0, 3, 4.0, 5, 6.0, 7, 8.0, 9);
> > +  h6 (0, 0.0, 1, 2.0, 3, 4.0, 5, 6.0, 7, 8.0, 9);
> > +  h7 (s {}, 0.0, 1, 2.0, 3, 4.0, 5, 6.0, 7, 8.0, 9);
> > +}
> > --- gcc/testsuite/g++.dg/cpp26/stdarg2.C.jj   2025-10-08 18:43:38.037552727 
> > +0200
> > +++ gcc/testsuite/g++.dg/cpp26/stdarg2.C      2025-10-08 18:43:38.037552727 
> > +0200
> > @@ -0,0 +1,212 @@
> > +// P3348R4 - C++26 should refer to C23 not C17
> > +// { dg-do run { target c++26 } }
> > +
> > +#include <stdarg.h>
> > +
> > +struct s { char c[1000]; };
> > +
> > +struct s
> > +f (...)
> > +{
> > +  va_list ap;
> > +  va_start (ap);
> > +  double r = va_arg (ap, int);
> > +  r += va_arg (ap, double);
> > +  r += va_arg (ap, int);
> > +  r += va_arg (ap, double);
> > +  va_end (ap);
> > +  struct s ret = {};
> > +  ret.c[0] = r;
> > +  ret.c[999] = 42;
> > +  return ret;
> > +}
> > +
> > +struct s
> > +g (...)
> > +{
> > +  va_list ap;
> > +  va_start (ap, random ! ignored, ignored ** text);  // { dg-warning 
> > "'va_start' macro used with additional arguments other than identifier of 
> > the last named argument" }
> > +  for (int i = 0; i < 10; i++)
> > +    if (va_arg (ap, double) != i)
> > +      __builtin_abort ();
> > +  va_end (ap);
> > +  struct s ret = {};
> > +  ret.c[0] = 17;
> > +  ret.c[999] = 58;
> > +  return ret;
> > +}
> > +
> > +struct s
> > +h1 (int x, ...)
> > +{
> > +  va_list ap;
> > +  va_start (ap);
> > +  for (int i = 0; i < 10; i++)
> > +    {
> > +      if (va_arg (ap, double) != i)
> > +     __builtin_abort ();
> > +      i++;
> > +      if (va_arg (ap, int) != i)
> > +     __builtin_abort ();
> > +    }
> > +  va_end (ap);
> > +  struct s ret = {};
> > +  ret.c[0] = 32;
> > +  ret.c[999] = 95;
> > +  return ret;
> > +}
> > +
> > +struct s
> > +h2 (int x(), ...)
> > +{
> > +  va_list ap;
> > +  va_start (ap);
> > +  for (int i = 0; i < 10; i++)
> > +    {
> > +      if (va_arg (ap, double) != i)
> > +     __builtin_abort ();
> > +      i++;
> > +      if (va_arg (ap, int) != i)
> > +     __builtin_abort ();
> > +    }
> > +  va_end (ap);
> > +  struct s ret = {};
> > +  ret.c[0] = 5;
> > +  ret.c[999] = 125;
> > +  return ret;
> > +}
> > +
> > +struct s
> > +h3 (int x[10], ...)
> > +{
> > +  va_list ap;
> > +  va_start (ap);
> > +  for (int i = 0; i < 10; i++)
> > +    {
> > +      if (va_arg (ap, double) != i)
> > +     __builtin_abort ();
> > +      i++;
> > +      if (va_arg (ap, int) != i)
> > +     __builtin_abort ();
> > +    }
> > +  va_end (ap);
> > +  struct s ret = {};
> > +  ret.c[0] = 8;
> > +  ret.c[999] = 12;
> > +  return ret;
> > +}
> > +
> > +struct s
> > +h4 (char x, ...)
> > +{
> > +  va_list ap;
> > +  va_start (ap);
> > +  for (int i = 0; i < 10; i++)
> > +    {
> > +      if (va_arg (ap, double) != i)
> > +     __builtin_abort ();
> > +      i++;
> > +      if (va_arg (ap, int) != i)
> > +     __builtin_abort ();
> > +    }
> > +  va_end (ap);
> > +  struct s ret = {};
> > +  ret.c[0] = 18;
> > +  ret.c[999] = 28;
> > +  return ret;
> > +}
> > +
> > +struct s
> > +h5 (float x, ...)
> > +{
> > +  va_list ap;
> > +  va_start (ap);
> > +  for (int i = 0; i < 10; i++)
> > +    {
> > +      if (va_arg (ap, double) != i)
> > +     __builtin_abort ();
> > +      i++;
> > +      if (va_arg (ap, int) != i)
> > +     __builtin_abort ();
> > +    }
> > +  va_end (ap);
> > +  struct s ret = {};
> > +  ret.c[0] = 38;
> > +  ret.c[999] = 48;
> > +  return ret;
> > +}
> > +
> > +struct s
> > +h6 (long x, ...)
> > +{
> > +  va_list ap;
> > +  va_start (ap);
> > +  for (int i = 0; i < 10; i++)
> > +    {
> > +      if (va_arg (ap, double) != i)
> > +     __builtin_abort ();
> > +      i++;
> > +      if (va_arg (ap, int) != i)
> > +     __builtin_abort ();
> > +    }
> > +  va_end (ap);
> > +  struct s ret = {};
> > +  ret.c[0] = 58;
> > +  ret.c[999] = 68;
> > +  return ret;
> > +}
> > +
> > +struct s
> > +h7 (struct s x, ...)
> > +{
> > +  va_list ap;
> > +  va_start (ap);
> > +  for (int i = 0; i < 10; i++)
> > +    {
> > +      if (va_arg (ap, double) != i)
> > +     __builtin_abort ();
> > +      i++;
> > +      if (va_arg (ap, int) != i)
> > +     __builtin_abort ();
> > +    }
> > +  va_end (ap);
> > +  struct s ret = {};
> > +  ret.c[0] = 78;
> > +  ret.c[999] = 88;
> > +  return ret;
> > +}
> > +
> > +int
> > +main ()
> > +{
> > +  struct s x = f (1, 2.0, 3, 4.0);
> > +  if (x.c[0] != 10 || x.c[999] != 42)
> > +    __builtin_abort ();
> > +  x = g (0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0);
> > +  if (x.c[0] != 17 || x.c[999] != 58)
> > +    __builtin_abort ();
> > +  x = g (0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f);
> > +  if (x.c[0] != 17 || x.c[999] != 58)
> > +    __builtin_abort ();
> > +  x = h1 (0, 0.0, 1, 2.0, 3, 4.0, 5, 6.0, 7, 8.0, 9);
> > +  if (x.c[0] != 32 || x.c[999] != 95)
> > +    __builtin_abort ();
> > +  x = h2 (0, 0.0, 1, 2.0, 3, 4.0, 5, 6.0, 7, 8.0, 9);
> > +  if (x.c[0] != 5 || x.c[999] != 125)
> > +    __builtin_abort ();
> > +  x = h3 (0, 0.0, 1, 2.0, 3, 4.0, 5, 6.0, 7, 8.0, 9);
> > +  if (x.c[0] != 8 || x.c[999] != 12)
> > +    __builtin_abort ();
> > +  x = h4 (0, 0.0, 1, 2.0, 3, 4.0, 5, 6.0, 7, 8.0, 9);
> > +  if (x.c[0] != 18 || x.c[999] != 28)
> > +    __builtin_abort ();
> > +  x = h5 (0, 0.0, 1, 2.0, 3, 4.0, 5, 6.0, 7, 8.0, 9);
> > +  if (x.c[0] != 38 || x.c[999] != 48)
> > +    __builtin_abort ();
> > +  x = h6 (0, 0.0, 1, 2.0, 3, 4.0, 5, 6.0, 7, 8.0, 9);
> > +  if (x.c[0] != 58 || x.c[999] != 68)
> > +    __builtin_abort ();
> > +  x = h7 (s {}, 0.0, 1, 2.0, 3, 4.0, 5, 6.0, 7, 8.0, 9);
> > +  if (x.c[0] != 78 || x.c[999] != 88)
> > +    __builtin_abort ();
> > +}
> > --- gcc/testsuite/g++.dg/cpp26/stdarg3.C.jj   2025-10-08 18:43:38.037552727 
> > +0200
> > +++ gcc/testsuite/g++.dg/cpp26/stdarg3.C      2025-10-08 18:43:38.037552727 
> > +0200
> > @@ -0,0 +1,7 @@
> > +// P3348R4 - C++26 should refer to C23 not C17
> > +// { dg-do run { target c++26 } }
> > +// { dg-additional-options "-O2" }
> > +
> > +#include "stdarg1.C"
> > +
> > +// { dg-warning "'va_start' macro used with additional arguments other 
> > than identifier of the last named argument" "" { target *-*-* } 0 }
> > --- gcc/testsuite/g++.dg/cpp26/stdarg4.C.jj   2025-10-08 18:43:38.037552727 
> > +0200
> > +++ gcc/testsuite/g++.dg/cpp26/stdarg4.C      2025-10-08 18:43:38.037552727 
> > +0200
> > @@ -0,0 +1,7 @@
> > +// P3348R4 - C++26 should refer to C23 not C17
> > +// { dg-do run { target c++26 } }
> > +// { dg-additional-options "-O2" }
> > +
> > +#include "stdarg2.C"
> > +
> > +// { dg-warning "'va_start' macro used with additional arguments other 
> > than identifier of the last named argument" "" { target *-*-* } 0 }
> > --- gcc/testsuite/g++.dg/cpp26/stdarg5.C.jj   2025-10-08 18:43:38.037552727 
> > +0200
> > +++ gcc/testsuite/g++.dg/cpp26/stdarg5.C      2025-10-08 18:43:38.037552727 
> > +0200
> > @@ -0,0 +1,5 @@
> > +// P3348R4 - C++26 should refer to C23 not C17
> > +// { dg-do run { target c++26 } }
> > +// { dg-additional-options "-O2" }
> > +
> > +#include "../../gcc.dg/c23-stdarg-9.c"
> > --- gcc/testsuite/g++.dg/cpp26/stdarg6.C.jj   2025-10-08 18:43:38.037552727 
> > +0200
> > +++ gcc/testsuite/g++.dg/cpp26/stdarg6.C      2025-10-08 18:43:38.037552727 
> > +0200
> > @@ -0,0 +1,112 @@
> > +// P3348R4 - C++26 should refer to C23 not C17
> > +// { dg-do compile { target c++26 } }
> > +// { dg-additional-options "-O2" }
> > +
> > +#include <stdarg.h>
> > +
> > +int i;
> > +
> > +void
> > +f0 (...)
> > +{
> > +  va_list ap;
> > +  va_start (ap);
> > +  va_end (ap);
> > +}
> > +
> > +void
> > +f1 (...)
> > +{
> > +  va_list ap;
> > +  va_start (ap, i);                          // { dg-warning "optional 
> > second parameter of 'va_start' not last named argument" }
> > +  va_end (ap);
> > +}
> > +
> > +void
> > +f2 (...)
> > +{
> > +  int j = 0;
> > +  va_list ap;
> > +  va_start (ap, j);                          // { dg-warning "optional 
> > second parameter of 'va_start' not last named argument" }
> > +  va_end (ap);
> > +}
> > +
> > +void
> > +f3 (int k, int l, ...)
> > +{
> > +  va_list ap;
> > +  va_start (ap, k);                          // { dg-warning "optional 
> > second parameter of 'va_start' not last named argument" }
> > +  va_end (ap);
> > +}
> > +
> > +void
> > +f4 (int k, int l, ...)
> > +{
> > +  va_list ap;
> > +  va_start (ap, l);
> > +  va_end (ap);
> > +}
> > +
> > +void
> > +f5 (int k, int l, ...)
> > +{
> > +  va_list ap;
> > +  va_start (ap, (int) l);                    // { dg-warning "'va_start' 
> > macro used with additional arguments other than identifier of the last 
> > named argument" }
> > +  va_end (ap);
> > +}
> > +
> > +void
> > +f6 (int k, int l, ...)
> > +{
> > +  va_list ap;
> > +  va_start (ap, l + 0);                              // { dg-warning 
> > "'va_start' macro used with additional arguments other than identifier of 
> > the last named argument" }
> > +  va_end (ap);
> > +}
> > +
> > +void
> > +f7 (int k, int l, ...)
> > +{
> > +  va_list ap;
> > +  va_start (ap, ()()(), [][][], {}{}{}, *+-/1({[_*_]})%&&!?!?);      // { 
> > dg-warning "'va_start' macro used with additional arguments other than 
> > identifier of the last named argument" }
> > +  va_end (ap);
> > +}
> > +
> > +void
> > +f8 (...)
> > +{
> > +  va_list ap;
> > +  va_start (ap,);                            // { dg-warning "'va_start' 
> > macro used with additional arguments other than identifier of the last 
> > named argument" }
> > +  va_end (ap);
> > +}
> > +
> > +void
> > +f9 (int k, int l, ...)
> > +{
> > +  va_list ap;
> > +  va_start (ap, k+l+****2);                  // { dg-warning "'va_start' 
> > macro used with additional arguments other than identifier of the last 
> > named argument" }
> > +  va_end (ap);
> > +}
> > +
> > +void
> > +f10 (int m, ...)
> > +{
> > +  va_list ap;
> > +  va_start (ap, m);
> > +  va_end (ap);
> > +}
> > +
> > +void
> > +f11 (int k, int l, ...)
> > +{
> > +  va_list ap;
> > +  va_start (ap, ()()()[[[}}});                       // { dg-warning 
> > "'va_start' macro used with additional arguments other than identifier of 
> > the last named argument" }
> > +  va_end (ap);
> > +}
> > +
> > +void
> > +f12 (int k, int l, ...)
> > +{
> > +  va_list ap;
> > +  va_start (ap, ]]]]]]{{{{{{);                       // { dg-warning 
> > "'va_start' macro used with additional arguments other than identifier of 
> > the last named argument" }
> > +  va_end (ap);
> > +}
> > --- gcc/testsuite/g++.dg/cpp26/stdarg7.C.jj   2025-10-08 18:43:38.037552727 
> > +0200
> > +++ gcc/testsuite/g++.dg/cpp26/stdarg7.C      2025-10-08 18:43:38.037552727 
> > +0200
> > @@ -0,0 +1,11 @@
> > +// P3348R4 - C++26 should refer to C23 not C17
> > +// { dg-do compile { target c++26 } }
> > +// { dg-additional-options "-O2" }
> > +
> > +#include <stdarg.h>
> > +
> > +void
> > +f (...)
> > +{
> > +  va_start ();       // { dg-error "expected primary-expression before 
> > '\\\)' token" }
> > +}
> > --- gcc/testsuite/g++.dg/cpp26/stdarg8.C.jj   2025-10-08 18:43:38.038552713 
> > +0200
> > +++ gcc/testsuite/g++.dg/cpp26/stdarg8.C      2025-10-08 18:43:38.038552713 
> > +0200
> > @@ -0,0 +1,26 @@
> > +// P3348R4 - C++26 should refer to C23 not C17
> > +// { dg-do run { target c++26 } }
> > +
> > +#include <stdarg.h>
> > +
> > +int
> > +main ()
> > +{
> > +  int v = 0;
> > +  auto a = [&] (...) {
> > +    va_list ap;
> > +    va_start (ap);
> > +    int b = 42;
> > +    if (v)
> > +      b = va_arg (ap, int);
> > +    va_end (ap);
> > +    return b;
> > +  };
> > +  if (a () != 42)
> > +    __builtin_abort ();
> > +  v = 1;
> > +  if (a (1, 2) != 1)
> > +    __builtin_abort ();
> > +  if (a (13, 2.0f, 2ULL) != 13)
> > +    __builtin_abort ();
> > +}
> > --- gcc/testsuite/g++.dg/cpp26/stdarg9.C.jj   2025-10-08 18:43:38.038552713 
> > +0200
> > +++ gcc/testsuite/g++.dg/cpp26/stdarg9.C      2025-10-08 18:43:38.038552713 
> > +0200
> > @@ -0,0 +1,16 @@
> > +// P3348R4 - C++26 should refer to C23 not C17
> > +// { dg-do compile }
> > +
> > +#include <stdarg.h>
> > +
> > +#if __cplusplus >= 202400L
> > +#ifndef __STDC_VERSION_STDARG_H__
> > +#error __STDC_VERSION_STDARG_H__ not defined for C++26
> > +#elif __STDC_VERSION_STDARG_H__ != 202311L
> > +#error Unexpected __STDC_VERSION_STDARG_H__ value
> > +#endif
> > +#else
> > +#ifdef __STDC_VERSION_STDARG_H__
> > +#error __STDC_VERSION_STDARG_H__ defined for C++ < 26
> > +#endif
> > +#endif
> > --- gcc/testsuite/g++.dg/opt/pr60849.C.jj     2025-10-08 09:23:48.978692572 
> > +0200
> > +++ gcc/testsuite/g++.dg/opt/pr60849.C        2025-10-08 18:43:38.047552590 
> > +0200
> > @@ -7,7 +7,7 @@ extern "C" int isnan ();
> >
> >   void foo(float a) {
> >     int (*xx)(...);
> > -  xx = isnan;
> > +  xx = (int (*)(...)) isnan;
> >     if (xx(a))
> >       g++;
> >   }
> >
> >
> >       Jakub
> >
>

Reply via email to