public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
From: Richard Biener <richard.guenther@gmail.com>
To: Joseph Myers <joseph@codesourcery.com>
Cc: gcc-patches@gcc.gnu.org
Subject: Re: c: tree: target: C2x (...) function prototypes and va_start relaxation
Date: Fri, 28 Oct 2022 10:34:27 +0200	[thread overview]
Message-ID: <CAFiYyc2udQ2AJXszLD77UjEU5e9W8mJiq+y8oFJ0BY3ZGRF76Q@mail.gmail.com> (raw)
In-Reply-To: <3885b6e1-e6f-de17-b06f-c8dfaf3be15f@codesourcery.com>

On Tue, Oct 25, 2022 at 9:42 PM Joseph Myers <joseph@codesourcery.com> wrote:
>
> On Tue, 25 Oct 2022, Richard Biener wrote:
>
> > You are missing to stream the new type flag in tree-streamer-{in,out}.cc
> > and checking for tree merging in lto-common.cc:compare_tree_sccs_1
> >
> > Otherwise looks reasonable.  Can you add a (multi TU) runtime testcase to the
> > torture exercising the feature so we can see any ABI issues?
>
> I've made those changes.  Those in turn showed up the need for a
> change in fortran/trans-types.cc (to avoid using
> build_varargs_function_type_vec when what was wanted was an
> unprototyped function type rather than a (...) prototype) to avoid a
> failure of gfortran.dg/lto/pr40724.
>
> I've added a two-file testcase to gcc.dg/torture/.  I've also made the
> execution tests cover the case where there are named arguments but the
> last named argument has a declaration that results in undefined
> behavior in previous C standard versions, such as a type changed by
> the default argument promotions.
>
> Here is the revised patch version.

OK.

Thanks,
Richard.

> c: tree: target: C2x (...) function prototypes and va_start relaxation
>
> C2x allows function prototypes to be given as (...), a prototype
> meaning a variable-argument function with no named arguments.  To
> allow such functions to access their arguments, requirements for
> va_start calls are relaxed so it ignores all but its first argument
> (i.e. subsequent arguments, if any, can be arbitrary pp-token
> sequences).
>
> Implement this feature accordingly.  The va_start relaxation in
> <stdarg.h> is itself easy: __builtin_va_start already supports a
> second argument of 0 instead of a parameter name, and calls get
> converted internally to the form using 0 for that argument, so
> <stdarg.h> just needs changing to use a variadic macro that passes 0
> as the second argument of __builtin_va_start.  (This is done only in
> C2x mode, on the expectation that users of older standard would expect
> unsupported uses of va_start to be diagnosed.)
>
> For the (...) functions, it's necessary to distinguish these from
> unprototyped functions, whereas previously C++ (...) functions and
> unprototyped functions both used NULL TYPE_ARG_TYPES.  A flag is added
> to tree_type_common to mark the (...) functions; as discussed on gcc@,
> doing things this way is likely to be safer for unchanged code in GCC
> than adding a different form of representation in TYPE_ARG_TYPES, or
> adding a flag that instead signals that the function is unprototyped.
>
> There was previously an option
> -fallow-parameterless-variadic-functions to enable support for (...)
> prototypes.  The support was incomplete - it treated the functions as
> unprototyped, and only parsed some declarations, not e.g.
> "int g (int (...));".  This option is changed into a no-op ignored
> option; (...) is always accepted syntactically, with a pedwarn_c11
> call to given required diagnostics when appropriate.  The peculiarity
> of a parameter list with __attribute__ followed by '...' being
> accepted with that option is removed.
>
> Interfaces in tree.cc that create function types are adjusted to set
> this flag as appropriate.  It is of course possible that some existing
> users of the functions to create variable-argument functions actually
> wanted unprototyped functions in the no-named-argument case, rather
> than functions with a (...) prototype; some such cases in c-common.cc
> (for built-in functions and implicit function declarations) turn out
> to need updating for that reason.
>
> I didn't do anything to change how the C++ front end creates (...)
> function types.  It's very likely there are unchanged places in the
> compiler that in fact turn out to need changes to work properly with
> (...) function prototypes.
>
> Target setup_incoming_varargs hooks, where they used the information
> passed about the last named argument, needed updating to avoid using
> that information in the (...) case.  Note that apart from the x86
> changes, I haven't done any testing of those target changes beyond
> building cc1 to check for syntax errors.  It's possible further
> target-specific fixes will be needed; target maintainers should watch
> out for failures of c2x-stdarg-4.c or c2x-stdarg-split-1a.c, the
> execution tests, which would indicate that this feature is not working
> correctly.  Those tests also verify the case where there are named
> arguments but the last named argument has a declaration that results
> in undefined behavior in previous C standard versions, such as a type
> changed by the default argument promotions.
>
> Bootstrapped with no regressions for x86_64-pc-linux-gnu.
>
> gcc/
>         * config/aarch64/aarch64.cc (aarch64_setup_incoming_varargs):
>         Check TYPE_NO_NAMED_ARGS_STDARG_P.
>         * config/alpha/alpha.cc (alpha_setup_incoming_varargs): Likewise.
>         * config/arc/arc.cc (arc_setup_incoming_varargs): Likewise.
>         * config/arm/arm.cc (arm_setup_incoming_varargs): Likewise.
>         * config/csky/csky.cc (csky_setup_incoming_varargs): Likewise.
>         * config/epiphany/epiphany.cc (epiphany_setup_incoming_varargs):
>         Likewise.
>         * config/fr30/fr30.cc (fr30_setup_incoming_varargs): Likewise.
>         * config/frv/frv.cc (frv_setup_incoming_varargs): Likewise.
>         * config/ft32/ft32.cc (ft32_setup_incoming_varargs): Likewise.
>         * config/i386/i386.cc (ix86_setup_incoming_varargs): Likewise.
>         * config/ia64/ia64.cc (ia64_setup_incoming_varargs): Likewise.
>         * config/loongarch/loongarch.cc
>         (loongarch_setup_incoming_varargs): Likewise.
>         * config/m32r/m32r.cc (m32r_setup_incoming_varargs): Likewise.
>         * config/mcore/mcore.cc (mcore_setup_incoming_varargs): Likewise.
>         * config/mips/mips.cc (mips_setup_incoming_varargs): Likewise.
>         * config/mmix/mmix.cc (mmix_setup_incoming_varargs): Likewise.
>         * config/nds32/nds32.cc (nds32_setup_incoming_varargs): Likewise.
>         * config/nios2/nios2.cc (nios2_setup_incoming_varargs): Likewise.
>         * config/riscv/riscv.cc (riscv_setup_incoming_varargs): Likewise.
>         * config/rs6000/rs6000-call.cc (setup_incoming_varargs): Likewise.
>         * config/sh/sh.cc (sh_setup_incoming_varargs): Likewise.
>         * config/visium/visium.cc (visium_setup_incoming_varargs):
>         Likewise.
>         * config/vms/vms-c.cc (vms_c_common_override_options): Do not set
>         flag_allow_parameterless_variadic_functions.
>         * doc/invoke.texi (-fallow-parameterless-variadic-functions): Do
>         not document option.
>         * function.cc (assign_parms): Call assign_parms_setup_varargs for
>         TYPE_NO_NAMED_ARGS_STDARG_P case.
>         * ginclude/stdarg.h [__STDC_VERSION__ > 201710L] (va_start): Make
>         variadic macro.  Pass second argument of 0 to __builtin_va_start.
>         * target.def (setup_incoming_varargs): Update documentation.
>         * doc/tm.texi: Regenerate.
>         * tree-core.h (struct tree_type_common): Add
>         no_named_args_stdarg_p.
>         * tree-streamer-in.cc (unpack_ts_type_common_value_fields): Unpack
>         TYPE_NO_NAMED_ARGS_STDARG_P.
>         * tree-streamer-out.cc (pack_ts_type_common_value_fields): Pack
>         TYPE_NO_NAMED_ARGS_STDARG_P.
>         * tree.cc (type_cache_hasher::equal): Compare
>         TYPE_NO_NAMED_ARGS_STDARG_P.
>         (build_function_type): Add argument no_named_args_stdarg_p.
>         (build_function_type_list_1, build_function_type_array_1)
>         (reconstruct_complex_type): Update calls to build_function_type.
>         (stdarg_p, prototype_p): Return true for (...) functions.
>         (gimple_canonical_types_compatible_p): Compare
>         TYPE_NO_NAMED_ARGS_STDARG_P.
>         * tree.h (TYPE_NO_NAMED_ARGS_STDARG_P): New.
>         (build_function_type): Update prototype.
>
> gcc/c-family/
>         * c-common.cc (def_fn_type): Call build_function_type for
>         zero-argument variable-argument function.
>         (c_common_nodes_and_builtins): Build default_function_type with
>         build_function_type.
>         * c.opt (fallow-parameterless-variadic-functions): Mark as ignored
>         option.
>
> gcc/c/
>         * c-decl.cc (grokdeclarator): Pass
>         arg_info->no_named_args_stdarg_p to build_function_type.
>         (grokparms): Check arg_info->no_named_args_stdarg_p before
>         converting () to (void).
>         (build_arg_info): Initialize no_named_args_stdarg_p.
>         (get_parm_info): Set no_named_args_stdarg_p.
>         (start_function): Pass TYPE_NO_NAMED_ARGS_STDARG_P to
>         build_function_type.
>         (store_parm_decls): Count (...) functions as prototyped.
>         * c-parser.cc (c_parser_direct_declarator): Allow '...' after open
>         parenthesis to start parameter list.
>         (c_parser_parms_list_declarator): Always allow '...' with no
>         arguments, call pedwarn_c11 and set no_named_args_stdarg_p.
>         * c-tree.h (struct c_arg_info): Add field no_named_args_stdarg_p.
>         * c-typeck.cc (composite_type): Handle
>         TYPE_NO_NAMED_ARGS_STDARG_P.
>         (function_types_compatible_p): Compare
>         TYPE_NO_NAMED_ARGS_STDARG_P.
>
> gcc/fortran/
>         * trans-types.cc (gfc_get_function_type): Do not use
>         build_varargs_function_type_vec for unprototyped function.
>
> gcc/lto/
>         * lto-common.cc (compare_tree_sccs_1): Compare
>         TYPE_NO_NAMED_ARGS_STDARG_P.
>
> gcc/objc/
>         * objc-next-runtime-abi-01.cc (build_next_objc_exception_stuff):
>         Use build_function_type to build type of objc_setjmp_decl.
>
> gcc/testsuite/
>         * gcc.dg/c11-stdarg-1.c, gcc.dg/c11-stdarg-2.c,
>         gcc.dg/c11-stdarg-3.c, gcc.dg/c2x-stdarg-1.c,
>         gcc.dg/c2x-stdarg-2.c, gcc.dg/c2x-stdarg-3.c,
>         gcc.dg/c2x-stdarg-4.c, gcc.dg/gnu2x-stdarg-1.c,
>         gcc.dg/torture/c2x-stdarg-split-1a.c,
>         gcc.dg/torture/c2x-stdarg-split-1b.c: New tests.
>         * gcc.dg/Wold-style-definition-2.c, gcc.dg/format/sentinel-1.c:
>         Update expected diagnostics.
>         * gcc.dg/c2x-nullptr-1.c (test5): Cast unused parameter to (void).
>         * gcc.dg/diagnostic-token-ranges.c: Use -pedantic.  Expect warning
>         in place of error.
>
> diff --git a/gcc/c-family/c-common.cc b/gcc/c-family/c-common.cc
> index cd54c517b18..5890c18bdc3 100644
> --- a/gcc/c-family/c-common.cc
> +++ b/gcc/c-family/c-common.cc
> @@ -4064,7 +4064,8 @@ static tree builtin_types[(int) BT_LAST + 1];
>
>  /* A helper function for c_common_nodes_and_builtins.  Build function type
>     for DEF with return type RET and N arguments.  If VAR is true, then the
> -   function should be variadic after those N arguments.
> +   function should be variadic after those N arguments, or, if N is zero,
> +   unprototyped.
>
>     Takes special care not to ICE if any of the types involved are
>     error_mark_node, which indicates that said type is not in fact available
> @@ -4093,7 +4094,10 @@ def_fn_type (builtin_type def, builtin_type ret, bool var, int n, ...)
>    if (t == error_mark_node)
>      goto egress;
>    if (var)
> -    t = build_varargs_function_type_array (t, n, args);
> +    if (n == 0)
> +      t = build_function_type (t, NULL_TREE);
> +    else
> +      t = build_varargs_function_type_array (t, n, args);
>    else
>      t = build_function_type_array (t, n, args);
>
> @@ -4661,8 +4665,7 @@ c_common_nodes_and_builtins (void)
>      uintptr_type_node =
>        TREE_TYPE (identifier_global_value (c_get_ident (UINTPTR_TYPE)));
>
> -  default_function_type
> -    = build_varargs_function_type_list (integer_type_node, NULL_TREE);
> +  default_function_type = build_function_type (integer_type_node, NULL_TREE);
>    unsigned_ptrdiff_type_node = c_common_unsigned_type (ptrdiff_type_node);
>
>    lang_hooks.decls.pushdecl
> diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt
> index 01d480759ae..5f9f65f9d5b 100644
> --- a/gcc/c-family/c.opt
> +++ b/gcc/c-family/c.opt
> @@ -1508,8 +1508,8 @@ fall-virtual
>  C++ ObjC++ WarnRemoved
>
>  fallow-parameterless-variadic-functions
> -C ObjC Var(flag_allow_parameterless_variadic_functions)
> -Allow variadic functions without named parameter.
> +C ObjC Ignore
> +Does nothing. Preserved for backward compatibility.
>
>  falt-external-templates
>  C++ ObjC++ WarnRemoved
> diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc
> index 4746e310d2d..6a4d6bc4313 100644
> --- a/gcc/c/c-decl.cc
> +++ b/gcc/c/c-decl.cc
> @@ -7252,7 +7252,8 @@ grokdeclarator (const struct c_declarator *declarator,
>               }
>             type_quals = TYPE_UNQUALIFIED;
>
> -           type = build_function_type (type, arg_types);
> +           type = build_function_type (type, arg_types,
> +                                       arg_info->no_named_args_stdarg_p);
>             declarator = declarator->declarator;
>
>             /* Set the TYPE_CONTEXTs for each tagged type which is local to
> @@ -8017,7 +8018,8 @@ grokparms (struct c_arg_info *arg_info, bool funcdef_flag)
>        /* In C2X, convert () to (void).  */
>        if (flag_isoc2x
>           && !arg_types
> -         && !arg_info->parms)
> +         && !arg_info->parms
> +         && !arg_info->no_named_args_stdarg_p)
>         arg_types = arg_info->types = void_list_node;
>
>        /* If there is a parameter of incomplete type in a definition,
> @@ -8087,6 +8089,7 @@ build_arg_info (void)
>    ret->others = NULL_TREE;
>    ret->pending_sizes = NULL;
>    ret->had_vla_unspec = 0;
> +  ret->no_named_args_stdarg_p = 0;
>    return ret;
>  }
>
> @@ -8278,6 +8281,7 @@ get_parm_info (bool ellipsis, tree expr)
>    arg_info->types = types;
>    arg_info->others = others;
>    arg_info->pending_sizes = expr;
> +  arg_info->no_named_args_stdarg_p = ellipsis && !types;
>    return arg_info;
>  }
>
> @@ -9815,7 +9819,8 @@ start_function (struct c_declspecs *declspecs, struct c_declarator *declarator,
>        /* Make it return void instead.  */
>        TREE_TYPE (decl1)
>         = build_function_type (void_type_node,
> -                              TYPE_ARG_TYPES (TREE_TYPE (decl1)));
> +                              TYPE_ARG_TYPES (TREE_TYPE (decl1)),
> +                              TYPE_NO_NAMED_ARGS_STDARG_P (TREE_TYPE (decl1)));
>      }
>
>    if (warn_about_return_type)
> @@ -10414,7 +10419,7 @@ store_parm_decls (void)
>       empty argument list was converted to (void) in grokparms; in
>       older C standard versions, it does not give the function a type
>       with a prototype for future calls.  */
> -  proto = arg_info->types != 0;
> +  proto = arg_info->types != 0 || arg_info->no_named_args_stdarg_p;
>
>    if (proto)
>      store_parm_decls_newstyle (fndecl, arg_info);
> diff --git a/gcc/c/c-parser.cc b/gcc/c/c-parser.cc
> index 602e0235f2d..31438464e4e 100644
> --- a/gcc/c/c-parser.cc
> +++ b/gcc/c/c-parser.cc
> @@ -4119,7 +4119,8 @@ c_parser_direct_declarator (c_parser *parser, bool type_seen_p, c_dtr_syn kind,
>        if (kind != C_DTR_NORMAL
>           && (c_parser_next_token_starts_declspecs (parser)
>               || (!have_gnu_attrs
> -                 && c_parser_nth_token_starts_std_attributes (parser, 1))
> +                 && (c_parser_nth_token_starts_std_attributes (parser, 1)
> +                     || c_parser_next_token_is (parser, CPP_ELLIPSIS)))
>               || c_parser_next_token_is (parser, CPP_CLOSE_PAREN)))
>         {
>           struct c_arg_info *args
> @@ -4395,25 +4396,18 @@ c_parser_parms_list_declarator (c_parser *parser, tree attrs, tree expr,
>        c_parser_consume_token (parser);
>        return ret;
>      }
> -  if (c_parser_next_token_is (parser, CPP_ELLIPSIS))
> +  if (c_parser_next_token_is (parser, CPP_ELLIPSIS) && !have_gnu_attrs)
>      {
>        struct c_arg_info *ret = build_arg_info ();
>
> -      if (flag_allow_parameterless_variadic_functions)
> -        {
> -          /* F (...) is allowed.  */
> -          ret->types = NULL_TREE;
> -        }
> -      else
> -        {
> -          /* Suppress -Wold-style-definition for this case.  */
> -          ret->types = error_mark_node;
> -          error_at (c_parser_peek_token (parser)->location,
> -                    "ISO C requires a named argument before %<...%>");
> -        }
> +      ret->types = NULL_TREE;
> +      pedwarn_c11 (c_parser_peek_token (parser)->location, OPT_Wpedantic,
> +                  "ISO C requires a named argument before %<...%> "
> +                  "before C2X");
>        c_parser_consume_token (parser);
>        if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
>         {
> +         ret->no_named_args_stdarg_p = true;
>           c_parser_consume_token (parser);
>           return ret;
>         }
> diff --git a/gcc/c/c-tree.h b/gcc/c/c-tree.h
> index e7cdd2f11dc..1bdadfffa52 100644
> --- a/gcc/c/c-tree.h
> +++ b/gcc/c/c-tree.h
> @@ -457,6 +457,8 @@ struct c_arg_info {
>    tree pending_sizes;
>    /* True when these arguments had [*].  */
>    BOOL_BITFIELD had_vla_unspec : 1;
> +  /* True when the arguments are a (...) prototype.  */
> +  BOOL_BITFIELD no_named_args_stdarg_p : 1;
>  };
>
>  /* A declarator.  */
> diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc
> index 92f3afc5857..64244c3d80d 100644
> --- a/gcc/c/c-typeck.cc
> +++ b/gcc/c/c-typeck.cc
> @@ -542,17 +542,19 @@ composite_type (tree t1, tree t2)
>
>         /* Simple way if one arg fails to specify argument types.  */
>         if (TYPE_ARG_TYPES (t1) == NULL_TREE)
> -        {
> -           t1 = build_function_type (valtype, TYPE_ARG_TYPES (t2));
> +         {
> +           t1 = build_function_type (valtype, TYPE_ARG_TYPES (t2),
> +                                     TYPE_NO_NAMED_ARGS_STDARG_P (t2));
>             t1 = build_type_attribute_variant (t1, attributes);
>             return qualify_type (t1, t2);
>          }
>         if (TYPE_ARG_TYPES (t2) == NULL_TREE)
> -        {
> -          t1 = build_function_type (valtype, TYPE_ARG_TYPES (t1));
> -          t1 = build_type_attribute_variant (t1, attributes);
> -          return qualify_type (t1, t2);
> -        }
> +         {
> +           t1 = build_function_type (valtype, TYPE_ARG_TYPES (t1),
> +                                     TYPE_NO_NAMED_ARGS_STDARG_P (t1));
> +           t1 = build_type_attribute_variant (t1, attributes);
> +           return qualify_type (t1, t2);
> +         }
>
>         /* If both args specify argument types, we must merge the two
>            lists, argument by argument.  */
> @@ -1700,6 +1702,8 @@ function_types_compatible_p (const_tree f1, const_tree f2,
>
>    if (args1 == NULL_TREE)
>      {
> +      if (TYPE_NO_NAMED_ARGS_STDARG_P (f1) != TYPE_NO_NAMED_ARGS_STDARG_P (f2))
> +       return 0;
>        if (!self_promoting_args_p (args2))
>         return 0;
>        /* If one of these types comes from a non-prototype fn definition,
> @@ -1713,6 +1717,8 @@ function_types_compatible_p (const_tree f1, const_tree f2,
>      }
>    if (args2 == NULL_TREE)
>      {
> +      if (TYPE_NO_NAMED_ARGS_STDARG_P (f1) != TYPE_NO_NAMED_ARGS_STDARG_P (f2))
> +       return 0;
>        if (!self_promoting_args_p (args1))
>         return 0;
>        if (TYPE_ACTUAL_ARG_TYPES (f2)
> diff --git a/gcc/config/aarch64/aarch64.cc b/gcc/config/aarch64/aarch64.cc
> index 5d1ab5aa42b..4d51d800e59 100644
> --- a/gcc/config/aarch64/aarch64.cc
> +++ b/gcc/config/aarch64/aarch64.cc
> @@ -19891,7 +19891,8 @@ aarch64_setup_incoming_varargs (cumulative_args_t cum_v,
>       argument.  Advance a local copy of CUM past the last "real" named
>       argument, to find out how many registers are left over.  */
>    local_cum = *cum;
> -  aarch64_function_arg_advance (pack_cumulative_args(&local_cum), arg);
> +  if (!TYPE_NO_NAMED_ARGS_STDARG_P (TREE_TYPE (current_function_decl)))
> +    aarch64_function_arg_advance (pack_cumulative_args(&local_cum), arg);
>
>    /* Found out how many registers we need to save.
>       Honor tree-stdvar analysis results.  */
> diff --git a/gcc/config/alpha/alpha.cc b/gcc/config/alpha/alpha.cc
> index 66c17149d4d..333f2c602c4 100644
> --- a/gcc/config/alpha/alpha.cc
> +++ b/gcc/config/alpha/alpha.cc
> @@ -6084,8 +6084,9 @@ alpha_setup_incoming_varargs (cumulative_args_t pcum,
>  {
>    CUMULATIVE_ARGS cum = *get_cumulative_args (pcum);
>
> -  /* Skip the current argument.  */
> -  targetm.calls.function_arg_advance (pack_cumulative_args (&cum), arg);
> +  if (!TYPE_NO_NAMED_ARGS_STDARG_P (TREE_TYPE (current_function_decl)))
> +    /* Skip the current argument.  */
> +    targetm.calls.function_arg_advance (pack_cumulative_args (&cum), arg);
>
>  #if TARGET_ABI_OPEN_VMS
>    /* For VMS, we allocate space for all 6 arg registers plus a count.
> diff --git a/gcc/config/arc/arc.cc b/gcc/config/arc/arc.cc
> index e6f52d87714..604a116e966 100644
> --- a/gcc/config/arc/arc.cc
> +++ b/gcc/config/arc/arc.cc
> @@ -2450,7 +2450,8 @@ arc_setup_incoming_varargs (cumulative_args_t args_so_far,
>    /* We must treat `__builtin_va_alist' as an anonymous arg.  */
>
>    next_cum = *get_cumulative_args (args_so_far);
> -  arc_function_arg_advance (pack_cumulative_args (&next_cum), arg);
> +  if (!TYPE_NO_NAMED_ARGS_STDARG_P (TREE_TYPE (current_function_decl)))
> +    arc_function_arg_advance (pack_cumulative_args (&next_cum), arg);
>    first_anon_arg = next_cum;
>
>    if (FUNCTION_ARG_REGNO_P (first_anon_arg))
> diff --git a/gcc/config/arm/arm.cc b/gcc/config/arm/arm.cc
> index ee8f1babf8a..2eb4d51e4a3 100644
> --- a/gcc/config/arm/arm.cc
> +++ b/gcc/config/arm/arm.cc
> @@ -29143,7 +29143,8 @@ arm_setup_incoming_varargs (cumulative_args_t pcum_v,
>    if (pcum->pcs_variant <= ARM_PCS_AAPCS_LOCAL)
>      {
>        nregs = pcum->aapcs_ncrn;
> -      if (nregs & 1)
> +      if (!TYPE_NO_NAMED_ARGS_STDARG_P (TREE_TYPE (current_function_decl))
> +         && (nregs & 1))
>         {
>           int res = arm_needs_doubleword_align (arg.mode, arg.type);
>           if (res < 0 && warn_psabi)
> diff --git a/gcc/config/csky/csky.cc b/gcc/config/csky/csky.cc
> index f7b2bf8e7c1..537eee6ab88 100644
> --- a/gcc/config/csky/csky.cc
> +++ b/gcc/config/csky/csky.cc
> @@ -2086,7 +2086,8 @@ csky_setup_incoming_varargs (cumulative_args_t pcum_v,
>
>    cfun->machine->uses_anonymous_args = 1;
>    local_cum = *pcum;
> -  csky_function_arg_advance (local_cum_v, arg);
> +  if (!TYPE_NO_NAMED_ARGS_STDARG_P (TREE_TYPE (current_function_decl)))
> +    csky_function_arg_advance (local_cum_v, arg);
>    regs_to_push = CSKY_NPARM_REGS - local_cum.reg;
>    if (regs_to_push)
>      *pretend_size  = regs_to_push * UNITS_PER_WORD;
> diff --git a/gcc/config/epiphany/epiphany.cc b/gcc/config/epiphany/epiphany.cc
> index f8c04934085..c4e3ceaeb2a 100644
> --- a/gcc/config/epiphany/epiphany.cc
> +++ b/gcc/config/epiphany/epiphany.cc
> @@ -727,11 +727,13 @@ epiphany_setup_incoming_varargs (cumulative_args_t cum,
>    machine_function_t *mf = MACHINE_FUNCTION (cfun);
>
>    /* All BLKmode values are passed by reference.  */
> -  gcc_assert (arg.mode != BLKmode);
> +  if (!TYPE_NO_NAMED_ARGS_STDARG_P (TREE_TYPE (current_function_decl)))
> +    gcc_assert (arg.mode != BLKmode);
>
>    next_cum = *get_cumulative_args (cum);
> -  next_cum = (ROUND_ADVANCE_CUM (next_cum, arg.mode, arg.type)
> -             + ROUND_ADVANCE_ARG (arg.mode, arg.type));
> +  if (!TYPE_NO_NAMED_ARGS_STDARG_P (TREE_TYPE (current_function_decl)))
> +    next_cum = (ROUND_ADVANCE_CUM (next_cum, arg.mode, arg.type)
> +               + ROUND_ADVANCE_ARG (arg.mode, arg.type));
>    first_anon_arg = next_cum;
>
>    if (first_anon_arg < MAX_EPIPHANY_PARM_REGS && !no_rtl)
> diff --git a/gcc/config/fr30/fr30.cc b/gcc/config/fr30/fr30.cc
> index c9b061d218b..334bb44e37f 100644
> --- a/gcc/config/fr30/fr30.cc
> +++ b/gcc/config/fr30/fr30.cc
> @@ -471,16 +471,19 @@ fr30_setup_incoming_varargs (cumulative_args_t arg_regs_used_so_far_v,
>      = get_cumulative_args (arg_regs_used_so_far_v);
>    int size;
>
> -  /* All BLKmode values are passed by reference.  */
> -  gcc_assert (arg.mode != BLKmode);
> -
> -  /* ??? This run-time test as well as the code inside the if
> -     statement is probably unnecessary.  */
> -  if (targetm.calls.strict_argument_naming (arg_regs_used_so_far_v))
> -    /* If TARGET_STRICT_ARGUMENT_NAMING returns true, then the last named
> -       arg must not be treated as an anonymous arg.  */
> -    /* ??? This is a pointer increment, which makes no sense.  */
> -    arg_regs_used_so_far += fr30_num_arg_regs (arg);
> +  if (!TYPE_NO_NAMED_ARGS_STDARG_P (TREE_TYPE (current_function_decl)))
> +    {
> +      /* All BLKmode values are passed by reference.  */
> +      gcc_assert (arg.mode != BLKmode);
> +
> +      /* ??? This run-time test as well as the code inside the if
> +        statement is probably unnecessary.  */
> +      if (targetm.calls.strict_argument_naming (arg_regs_used_so_far_v))
> +       /* If TARGET_STRICT_ARGUMENT_NAMING returns true, then the last named
> +          arg must not be treated as an anonymous arg.  */
> +       /* ??? This is a pointer increment, which makes no sense.  */
> +       arg_regs_used_so_far += fr30_num_arg_regs (arg);
> +    }
>
>    size = FR30_NUM_ARG_REGS - (* arg_regs_used_so_far);
>
> diff --git a/gcc/config/frv/frv.cc b/gcc/config/frv/frv.cc
> index 6f1904b358c..5cdb0bfe6e9 100644
> --- a/gcc/config/frv/frv.cc
> +++ b/gcc/config/frv/frv.cc
> @@ -2104,7 +2104,8 @@ frv_setup_incoming_varargs (cumulative_args_t cum_v,
>  {
>    CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v);
>
> -  if (TARGET_DEBUG_ARG)
> +  if (!TYPE_NO_NAMED_ARGS_STDARG_P (TREE_TYPE (current_function_decl))
> +      && TARGET_DEBUG_ARG)
>      fprintf (stderr,
>              "setup_vararg: words = %2d, mode = %4s, pretend_size = %d, second_time = %d\n",
>              *cum, GET_MODE_NAME (arg.mode), *pretend_size, second_time);
> diff --git a/gcc/config/ft32/ft32.cc b/gcc/config/ft32/ft32.cc
> index ed2d1229d61..d6b73d48686 100644
> --- a/gcc/config/ft32/ft32.cc
> +++ b/gcc/config/ft32/ft32.cc
> @@ -634,8 +634,10 @@ ft32_setup_incoming_varargs (cumulative_args_t cum_v,
>                              int *pretend_size, int no_rtl ATTRIBUTE_UNUSED)
>  {
>    CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v);
> -  int named_size =
> -    GET_MODE_SIZE (SImode) * (*cum - FT32_R0) + GET_MODE_SIZE (arg.mode);
> +  int named_size = 0;
> +  if (!TYPE_NO_NAMED_ARGS_STDARG_P (TREE_TYPE (current_function_decl)))
> +    named_size =
> +      GET_MODE_SIZE (SImode) * (*cum - FT32_R0) + GET_MODE_SIZE (arg.mode);
>
>    if (named_size < 24)
>      *pretend_size = 24 - named_size;
> diff --git a/gcc/config/i386/i386.cc b/gcc/config/i386/i386.cc
> index aeea26ef4be..e775ba4ad6c 100644
> --- a/gcc/config/i386/i386.cc
> +++ b/gcc/config/i386/i386.cc
> @@ -4559,7 +4559,8 @@ ix86_setup_incoming_varargs (cumulative_args_t cum_v,
>    /* For varargs, we do not want to skip the dummy va_dcl argument.
>       For stdargs, we do want to skip the last named argument.  */
>    next_cum = *cum;
> -  if (stdarg_p (fntype))
> +  if (!TYPE_NO_NAMED_ARGS_STDARG_P (TREE_TYPE (current_function_decl))
> +      && stdarg_p (fntype))
>      ix86_function_arg_advance (pack_cumulative_args (&next_cum), arg);
>
>    if (cum->call_abi == MS_ABI)
> diff --git a/gcc/config/ia64/ia64.cc b/gcc/config/ia64/ia64.cc
> index 995ff906940..6df1ce736bc 100644
> --- a/gcc/config/ia64/ia64.cc
> +++ b/gcc/config/ia64/ia64.cc
> @@ -4596,8 +4596,9 @@ ia64_setup_incoming_varargs (cumulative_args_t cum,
>  {
>    CUMULATIVE_ARGS next_cum = *get_cumulative_args (cum);
>
> -  /* Skip the current argument.  */
> -  ia64_function_arg_advance (pack_cumulative_args (&next_cum), arg);
> +  if (!TYPE_NO_NAMED_ARGS_STDARG_P (TREE_TYPE (current_function_decl)))
> +    /* Skip the current argument.  */
> +    ia64_function_arg_advance (pack_cumulative_args (&next_cum), arg);
>
>    if (next_cum.words < MAX_ARGUMENT_SLOTS)
>      {
> diff --git a/gcc/config/loongarch/loongarch.cc b/gcc/config/loongarch/loongarch.cc
> index e9ba3374e35..f54c233f90c 100644
> --- a/gcc/config/loongarch/loongarch.cc
> +++ b/gcc/config/loongarch/loongarch.cc
> @@ -756,7 +756,8 @@ loongarch_setup_incoming_varargs (cumulative_args_t cum,
>       argument.  Advance a local copy of CUM past the last "real" named
>       argument, to find out how many registers are left over.  */
>    local_cum = *get_cumulative_args (cum);
> -  loongarch_function_arg_advance (pack_cumulative_args (&local_cum), arg);
> +  if (!TYPE_NO_NAMED_ARGS_STDARG_P (TREE_TYPE (current_function_decl)))
> +    loongarch_function_arg_advance (pack_cumulative_args (&local_cum), arg);
>
>    /* Found out how many registers we need to save.  */
>    gp_saved = MAX_ARGS_IN_REGISTERS - local_cum.num_gprs;
> diff --git a/gcc/config/m32r/m32r.cc b/gcc/config/m32r/m32r.cc
> index bca768172b7..e3489fb4dc0 100644
> --- a/gcc/config/m32r/m32r.cc
> +++ b/gcc/config/m32r/m32r.cc
> @@ -1287,11 +1287,15 @@ m32r_setup_incoming_varargs (cumulative_args_t cum,
>      return;
>
>    /* All BLKmode values are passed by reference.  */
> -  gcc_assert (arg.mode != BLKmode);
> +  if (!TYPE_NO_NAMED_ARGS_STDARG_P (TREE_TYPE (current_function_decl)))
> +    gcc_assert (arg.mode != BLKmode);
>
> -  first_anon_arg = (ROUND_ADVANCE_CUM (*get_cumulative_args (cum),
> -                                      arg.mode, arg.type)
> -                   + ROUND_ADVANCE_ARG (arg.mode, arg.type));
> +  if (!TYPE_NO_NAMED_ARGS_STDARG_P (TREE_TYPE (current_function_decl)))
> +    first_anon_arg = (ROUND_ADVANCE_CUM (*get_cumulative_args (cum),
> +                                        arg.mode, arg.type)
> +                     + ROUND_ADVANCE_ARG (arg.mode, arg.type));
> +  else
> +    first_anon_arg = *get_cumulative_args (cum);
>
>    if (first_anon_arg < M32R_MAX_PARM_REGS)
>      {
> diff --git a/gcc/config/mcore/mcore.cc b/gcc/config/mcore/mcore.cc
> index 28e707496d1..605d63b6a70 100644
> --- a/gcc/config/mcore/mcore.cc
> +++ b/gcc/config/mcore/mcore.cc
> @@ -1953,8 +1953,9 @@ mcore_setup_incoming_varargs (cumulative_args_t args_so_far_v,
>    /* We need to know how many argument registers are used before
>       the varargs start, so that we can push the remaining argument
>       registers during the prologue.  */
> -  number_of_regs_before_varargs
> -    = *args_so_far + mcore_num_arg_regs (arg.mode, arg.type);
> +  number_of_regs_before_varargs = *args_so_far;
> +  if (!TYPE_NO_NAMED_ARGS_STDARG_P (TREE_TYPE (current_function_decl)))
> +    number_of_regs_before_varargs += mcore_num_arg_regs (arg.mode, arg.type);
>
>    /* There is a bug somewhere in the arg handling code.
>       Until I can find it this workaround always pushes the
> diff --git a/gcc/config/mips/mips.cc b/gcc/config/mips/mips.cc
> index 699ea6cc128..0ac0248fb9e 100644
> --- a/gcc/config/mips/mips.cc
> +++ b/gcc/config/mips/mips.cc
> @@ -6683,7 +6683,8 @@ mips_setup_incoming_varargs (cumulative_args_t cum,
>       argument.  Advance a local copy of CUM past the last "real" named
>       argument, to find out how many registers are left over.  */
>    local_cum = *get_cumulative_args (cum);
> -  mips_function_arg_advance (pack_cumulative_args (&local_cum), arg);
> +  if (!TYPE_NO_NAMED_ARGS_STDARG_P (TREE_TYPE (current_function_decl)))
> +    mips_function_arg_advance (pack_cumulative_args (&local_cum), arg);
>
>    /* Found out how many registers we need to save.  */
>    gp_saved = MAX_ARGS_IN_REGISTERS - local_cum.num_gprs;
> diff --git a/gcc/config/mmix/mmix.cc b/gcc/config/mmix/mmix.cc
> index ffdd8c71cc1..1ac7b883ac5 100644
> --- a/gcc/config/mmix/mmix.cc
> +++ b/gcc/config/mmix/mmix.cc
> @@ -999,7 +999,8 @@ mmix_setup_incoming_varargs (cumulative_args_t args_so_farp_v,
>
>    /* We assume that one argument takes up one register here.  That should
>       be true until we start messing with multi-reg parameters.  */
> -  if ((7 + (MMIX_FUNCTION_ARG_SIZE (arg.mode, arg.type))) / 8 != 1)
> +  if (!TYPE_NO_NAMED_ARGS_STDARG_P (TREE_TYPE (current_function_decl))
> +      && (7 + (MMIX_FUNCTION_ARG_SIZE (arg.mode, arg.type))) / 8 != 1)
>      internal_error ("MMIX Internal: Last named vararg would not fit in a register");
>  }
>
> diff --git a/gcc/config/nds32/nds32.cc b/gcc/config/nds32/nds32.cc
> index 67a612130fe..639baef6c17 100644
> --- a/gcc/config/nds32/nds32.cc
> +++ b/gcc/config/nds32/nds32.cc
> @@ -2377,9 +2377,12 @@ nds32_setup_incoming_varargs (cumulative_args_t ca,
>       for varargs.  */
>    total_args_regs
>      = NDS32_MAX_GPR_REGS_FOR_ARGS + NDS32_GPR_ARG_FIRST_REGNUM;
> -  num_of_used_regs
> -    = NDS32_AVAILABLE_REGNUM_FOR_GPR_ARG (cum->gpr_offset, arg.mode, arg.type)
> -      + NDS32_NEED_N_REGS_FOR_ARG (arg.mode, arg.type);
> +  if (!TYPE_NO_NAMED_ARGS_STDARG_P (TREE_TYPE (current_function_decl)))
> +    num_of_used_regs
> +      = NDS32_AVAILABLE_REGNUM_FOR_GPR_ARG (cum->gpr_offset, arg.mode, arg.type)
> +        + NDS32_NEED_N_REGS_FOR_ARG (arg.mode, arg.type);
> +  else
> +    num_of_used_regs = cum->gpr_offset + NDS32_GPR_ARG_FIRST_REGNUM;
>
>    remaining_reg_count = total_args_regs - num_of_used_regs;
>    *pretend_args_size = remaining_reg_count * UNITS_PER_WORD;
> diff --git a/gcc/config/nios2/nios2.cc b/gcc/config/nios2/nios2.cc
> index 1a33c88f19f..6a894ec345e 100644
> --- a/gcc/config/nios2/nios2.cc
> +++ b/gcc/config/nios2/nios2.cc
> @@ -3524,7 +3524,8 @@ nios2_setup_incoming_varargs (cumulative_args_t cum_v,
>
>    cfun->machine->uses_anonymous_args = 1;
>    local_cum = *cum;
> -  nios2_function_arg_advance (local_cum_v, arg);
> +  if (!TYPE_NO_NAMED_ARGS_STDARG_P (TREE_TYPE (current_function_decl)))
> +    nios2_function_arg_advance (local_cum_v, arg);
>
>    regs_to_push = NUM_ARG_REGS - local_cum.regs_used;
>
> diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc
> index 4e18a43539a..748a472cb2d 100644
> --- a/gcc/config/riscv/riscv.cc
> +++ b/gcc/config/riscv/riscv.cc
> @@ -3737,7 +3737,8 @@ riscv_setup_incoming_varargs (cumulative_args_t cum,
>       argument.  Advance a local copy of CUM past the last "real" named
>       argument, to find out how many registers are left over.  */
>    local_cum = *get_cumulative_args (cum);
> -  riscv_function_arg_advance (pack_cumulative_args (&local_cum), arg);
> +  if (!TYPE_NO_NAMED_ARGS_STDARG_P (TREE_TYPE (current_function_decl)))
> +    riscv_function_arg_advance (pack_cumulative_args (&local_cum), arg);
>
>    /* Found out how many registers we need to save.  */
>    gp_saved = MAX_ARGS_IN_REGISTERS - local_cum.num_gprs;
> diff --git a/gcc/config/rs6000/rs6000-call.cc b/gcc/config/rs6000/rs6000-call.cc
> index ac3cb7e3d36..6da4de67137 100644
> --- a/gcc/config/rs6000/rs6000-call.cc
> +++ b/gcc/config/rs6000/rs6000-call.cc
> @@ -2253,7 +2253,9 @@ setup_incoming_varargs (cumulative_args_t cum,
>
>    /* Skip the last named argument.  */
>    next_cum = *get_cumulative_args (cum);
> -  rs6000_function_arg_advance_1 (&next_cum, arg.mode, arg.type, arg.named, 0);
> +  if (!TYPE_NO_NAMED_ARGS_STDARG_P (TREE_TYPE (current_function_decl)))
> +    rs6000_function_arg_advance_1 (&next_cum, arg.mode, arg.type, arg.named,
> +                                  0);
>
>    if (DEFAULT_ABI == ABI_V4)
>      {
> @@ -2327,7 +2329,8 @@ setup_incoming_varargs (cumulative_args_t cum,
>        first_reg_offset = next_cum.words;
>        save_area = crtl->args.internal_arg_pointer;
>
> -      if (targetm.calls.must_pass_in_stack (arg))
> +      if (!TYPE_NO_NAMED_ARGS_STDARG_P (TREE_TYPE (current_function_decl))
> +         && targetm.calls.must_pass_in_stack (arg))
>         first_reg_offset += rs6000_arg_size (TYPE_MODE (arg.type), arg.type);
>      }
>
> diff --git a/gcc/config/sh/sh.cc b/gcc/config/sh/sh.cc
> index 9bee618b639..1aec70a23d8 100644
> --- a/gcc/config/sh/sh.cc
> +++ b/gcc/config/sh/sh.cc
> @@ -8183,11 +8183,12 @@ sh_setup_incoming_varargs (cumulative_args_t ca,
>    gcc_assert (cfun->stdarg);
>    if (TARGET_VARARGS_PRETEND_ARGS (current_function_decl))
>      {
> -      int named_parm_regs, anon_parm_regs;
> +      int named_parm_regs = 0, anon_parm_regs;
>
> -      named_parm_regs = (sh_round_reg (*get_cumulative_args (ca), arg.mode)
> -                        + CEIL (arg.promoted_size_in_bytes (),
> -                                UNITS_PER_WORD));
> +      if (!TYPE_NO_NAMED_ARGS_STDARG_P (TREE_TYPE (current_function_decl)))
> +       named_parm_regs = (sh_round_reg (*get_cumulative_args (ca), arg.mode)
> +                          + CEIL (arg.promoted_size_in_bytes (),
> +                                  UNITS_PER_WORD));
>        anon_parm_regs = NPARM_REGS (SImode) - named_parm_regs;
>        if (anon_parm_regs > 0)
>         *pretend_arg_size = anon_parm_regs * 4;
> diff --git a/gcc/config/visium/visium.cc b/gcc/config/visium/visium.cc
> index 03c1a33e1b9..e7d15960fc7 100644
> --- a/gcc/config/visium/visium.cc
> +++ b/gcc/config/visium/visium.cc
> @@ -1481,7 +1481,8 @@ visium_setup_incoming_varargs (cumulative_args_t pcum_v,
>    /* The caller has advanced ARGS_SO_FAR up to, but not beyond, the last named
>       argument.  Advance a local copy of ARGS_SO_FAR past the last "real" named
>       argument, to find out how many registers are left over.  */
> -  TARGET_FUNCTION_ARG_ADVANCE (local_args_so_far, arg);
> +  if (!TYPE_NO_NAMED_ARGS_STDARG_P (TREE_TYPE (current_function_decl)))
> +    TARGET_FUNCTION_ARG_ADVANCE (local_args_so_far, arg);
>
>    /* Find how many registers we need to save.  */
>    locargs = get_cumulative_args (local_args_so_far);
> diff --git a/gcc/config/vms/vms-c.cc b/gcc/config/vms/vms-c.cc
> index 2f74fb574cd..ccf6d5fe3b6 100644
> --- a/gcc/config/vms/vms-c.cc
> +++ b/gcc/config/vms/vms-c.cc
> @@ -455,9 +455,6 @@ vms_c_register_includes (const char *sysroot,
>  void
>  vms_c_common_override_options (void)
>  {
> -  /* Allow variadic functions without parameters (as declared in starlet).  */
> -  flag_allow_parameterless_variadic_functions = TRUE;
> -
>    /* Initialize c_default_pointer_mode.  */
>    switch (flag_vms_pointer_size)
>      {
> diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
> index 64f77e8367a..eddc62c2008 100644
> --- a/gcc/doc/invoke.texi
> +++ b/gcc/doc/invoke.texi
> @@ -198,7 +198,7 @@ in the following sections.
>  @item C Language Options
>  @xref{C Dialect Options,,Options Controlling C Dialect}.
>  @gccoptlist{-ansi  -std=@var{standard}  -aux-info @var{filename} @gol
> --fallow-parameterless-variadic-functions  -fno-asm  @gol
> +-fno-asm  @gol
>  -fno-builtin  -fno-builtin-@var{function}  -fcond-mismatch @gol
>  -ffreestanding  -fgimple  -fgnu-tm  -fgnu89-inline  -fhosted @gol
>  -flax-vector-conversions  -fms-extensions @gol
> @@ -2514,14 +2514,6 @@ character).  In the case of function definitions, a K&R-style list of
>  arguments followed by their declarations is also provided, inside
>  comments, after the declaration.
>
> -@item -fallow-parameterless-variadic-functions
> -@opindex fallow-parameterless-variadic-functions
> -Accept variadic functions without named parameters.
> -
> -Although it is possible to define such a function, this is not very
> -useful as it is not possible to read the arguments.  This is only
> -supported for C as this construct is allowed by C++.
> -
>  @item -fno-asm
>  @opindex fno-asm
>  @opindex fasm
> diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi
> index 110f8dfa0a9..63c8a3177ee 100644
> --- a/gcc/doc/tm.texi
> +++ b/gcc/doc/tm.texi
> @@ -5378,7 +5378,9 @@ pass all their arguments on the stack.
>  The argument @var{args_so_far} points to the @code{CUMULATIVE_ARGS} data
>  structure, containing the values that are obtained after processing the
>  named arguments.  The argument @var{arg} describes the last of these named
> -arguments.
> +arguments.  The argument @var{arg} should not be used if the function type
> +satisfies @code{TYPE_NO_NAMED_ARGS_STDARG_P}, since in that case there are
> +no named arguments and all arguments are accessed with @code{va_arg}.
>
>  The target hook should do two things: first, push onto the stack all the
>  argument registers @emph{not} used for the named arguments, and second,
> diff --git a/gcc/fortran/trans-types.cc b/gcc/fortran/trans-types.cc
> index fdce56defec..def7552ac67 100644
> --- a/gcc/fortran/trans-types.cc
> +++ b/gcc/fortran/trans-types.cc
> @@ -3297,7 +3297,9 @@ arg_type_list_done:
>      type = gfc_sym_type (sym);
>
>    if (is_varargs)
> -    type = build_varargs_function_type_vec (type, typelist);
> +    /* This should be represented as an unprototyped type, not a type
> +       with (...) prototype.  */
> +    type = build_function_type (type, NULL_TREE);
>    else
>      type = build_function_type_vec (type, typelist);
>
> diff --git a/gcc/function.cc b/gcc/function.cc
> index 6474a663b30..d3da20ede7f 100644
> --- a/gcc/function.cc
> +++ b/gcc/function.cc
> @@ -3647,6 +3647,12 @@ assign_parms (tree fndecl)
>    assign_parms_initialize_all (&all);
>    fnargs = assign_parms_augmented_arg_list (&all);
>
> +  if (TYPE_NO_NAMED_ARGS_STDARG_P (TREE_TYPE (fndecl)))
> +    {
> +      struct assign_parm_data_one data = {};
> +      assign_parms_setup_varargs (&all, &data, false);
> +    }
> +
>    FOR_EACH_VEC_ELT (fnargs, i, parm)
>      {
>        struct assign_parm_data_one data;
> diff --git a/gcc/ginclude/stdarg.h b/gcc/ginclude/stdarg.h
> index 7545ed30424..c704c9ffcf2 100644
> --- a/gcc/ginclude/stdarg.h
> +++ b/gcc/ginclude/stdarg.h
> @@ -44,7 +44,11 @@ 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
> +#define va_start(v, ...)       __builtin_va_start(v, 0)
> +#else
>  #define va_start(v,l)  __builtin_va_start(v,l)
> +#endif
>  #define va_end(v)      __builtin_va_end(v)
>  #define va_arg(v,l)    __builtin_va_arg(v,l)
>  #if !defined(__STRICT_ANSI__) || __STDC_VERSION__ + 0 >= 199900L \
> diff --git a/gcc/lto/lto-common.cc b/gcc/lto/lto-common.cc
> index d8d0404c54e..f64309731fa 100644
> --- a/gcc/lto/lto-common.cc
> +++ b/gcc/lto/lto-common.cc
> @@ -1270,6 +1270,7 @@ compare_tree_sccs_1 (tree t1, tree t2, tree **map)
>        if (AGGREGATE_TYPE_P (t1))
>         compare_values (TYPE_TYPELESS_STORAGE);
>        compare_values (TYPE_EMPTY_P);
> +      compare_values (TYPE_NO_NAMED_ARGS_STDARG_P);
>        compare_values (TYPE_PACKED);
>        compare_values (TYPE_RESTRICT);
>        compare_values (TYPE_USER_ALIGN);
> diff --git a/gcc/objc/objc-next-runtime-abi-01.cc b/gcc/objc/objc-next-runtime-abi-01.cc
> index 409b777b9e5..8d41886902b 100644
> --- a/gcc/objc/objc-next-runtime-abi-01.cc
> +++ b/gcc/objc/objc-next-runtime-abi-01.cc
> @@ -2443,7 +2443,7 @@ build_next_objc_exception_stuff (void)
>    /* int _setjmp(...); */
>    /* If the user includes <setjmp.h>, this shall be superseded by
>       'int _setjmp(jmp_buf);' */
> -  temp_type = build_varargs_function_type_list (integer_type_node, NULL_TREE);
> +  temp_type = build_function_type (integer_type_node, NULL_TREE);
>    objc_setjmp_decl
>      = add_builtin_function (TAG_SETJMP, temp_type, 0, NOT_BUILT_IN, NULL, NULL_TREE);
>
> diff --git a/gcc/target.def b/gcc/target.def
> index a3d3b04a165..25f94c19fa7 100644
> --- a/gcc/target.def
> +++ b/gcc/target.def
> @@ -4680,7 +4680,9 @@ pass all their arguments on the stack.\n\
>  The argument @var{args_so_far} points to the @code{CUMULATIVE_ARGS} data\n\
>  structure, containing the values that are obtained after processing the\n\
>  named arguments.  The argument @var{arg} describes the last of these named\n\
> -arguments.\n\
> +arguments.  The argument @var{arg} should not be used if the function type\n\
> +satisfies @code{TYPE_NO_NAMED_ARGS_STDARG_P}, since in that case there are\n\
> +no named arguments and all arguments are accessed with @code{va_arg}.\n\
>  \n\
>  The target hook should do two things: first, push onto the stack all the\n\
>  argument registers @emph{not} used for the named arguments, and second,\n\
> diff --git a/gcc/testsuite/gcc.dg/Wold-style-definition-2.c b/gcc/testsuite/gcc.dg/Wold-style-definition-2.c
> index a69aae6fd27..8e297c96411 100644
> --- a/gcc/testsuite/gcc.dg/Wold-style-definition-2.c
> +++ b/gcc/testsuite/gcc.dg/Wold-style-definition-2.c
> @@ -5,6 +5,6 @@
>  /* { dg-do compile } */
>  /* { dg-options "-Wold-style-definition" } */
>
> -void bar1 ( ... ) {} /* { dg-error "ISO C requires a named argument" } */
> +void bar1 ( ... ) {}
>
>  void bar2 (int a, ... ) {}
> diff --git a/gcc/testsuite/gcc.dg/c11-stdarg-1.c b/gcc/testsuite/gcc.dg/c11-stdarg-1.c
> new file mode 100644
> index 00000000000..984577fe656
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/c11-stdarg-1.c
> @@ -0,0 +1,7 @@
> +/* Test variadic functions with no named parameters not supported in C11.  */
> +/* { dg-do compile } */
> +/* { dg-options "-std=c11 -pedantic-errors" } */
> +
> +int f (...); /* { dg-error "ISO C requires a named argument before" } */
> +int g (int (...)); /* { dg-error "ISO C requires a named argument before" } */
> +int h (...) { return 0; } /* { dg-error "ISO C requires a named argument before" } */
> diff --git a/gcc/testsuite/gcc.dg/c11-stdarg-2.c b/gcc/testsuite/gcc.dg/c11-stdarg-2.c
> new file mode 100644
> index 00000000000..bd115e8850c
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/c11-stdarg-2.c
> @@ -0,0 +1,7 @@
> +/* Test variadic functions with no named parameters not supported in C11.  */
> +/* { dg-do compile } */
> +/* { dg-options "-std=c11 -pedantic" } */
> +
> +int f (...); /* { dg-warning "ISO C requires a named argument before" } */
> +int g (int (...)); /* { dg-warning "ISO C requires a named argument before" } */
> +int h (...) { return 0; } /* { dg-warning "ISO C requires a named argument before" } */
> diff --git a/gcc/testsuite/gcc.dg/c11-stdarg-3.c b/gcc/testsuite/gcc.dg/c11-stdarg-3.c
> new file mode 100644
> index 00000000000..009292461bd
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/c11-stdarg-3.c
> @@ -0,0 +1,8 @@
> +/* Test variadic functions with no named parameters not supported in C11, but
> +   diagnostic disabled with -Wno-c11-c2x-compat.  */
> +/* { dg-do compile } */
> +/* { dg-options "-std=c11 -pedantic-errors -Wno-c11-c2x-compat" } */
> +
> +int f (...);
> +int g (int (...));
> +int h (...) { return 0; }
> diff --git a/gcc/testsuite/gcc.dg/c2x-nullptr-1.c b/gcc/testsuite/gcc.dg/c2x-nullptr-1.c
> index 9501b514f1c..9f2cb6c8256 100644
> --- a/gcc/testsuite/gcc.dg/c2x-nullptr-1.c
> +++ b/gcc/testsuite/gcc.dg/c2x-nullptr-1.c
> @@ -226,6 +226,7 @@ test4 (void)
>  static void
>  test5 (int i, ...)
>  {
> +  (void) i;
>    va_list ap;
>    va_start (ap, i);
>    if (va_arg (ap, void *))
> diff --git a/gcc/testsuite/gcc.dg/c2x-stdarg-1.c b/gcc/testsuite/gcc.dg/c2x-stdarg-1.c
> new file mode 100644
> index 00000000000..7def49d3ce2
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/c2x-stdarg-1.c
> @@ -0,0 +1,22 @@
> +/* Test C2x variadic functions with no named parameters.  Compilation tests,
> +   valid code.  */
> +/* { dg-do compile } */
> +/* { dg-options "-std=c2x -pedantic-errors" } */
> +
> +int f (...);
> +int g (int (...));
> +int h (...) { return 0; }
> +
> +typedef int A[];
> +typedef int A2[2];
> +
> +A *f1 (...);
> +A2 *f1 (...);
> +A *f1 (...) { return 0; }
> +
> +A2 *f2 (...);
> +A *f2 (...);
> +A2 *f2 (...) { return 0; }
> +typeof (f1) f2;
> +
> +int t () { return f () + f (1) + f (1, 2) + h () + h (1.5, 2, f1) + g (f); }
> diff --git a/gcc/testsuite/gcc.dg/c2x-stdarg-2.c b/gcc/testsuite/gcc.dg/c2x-stdarg-2.c
> new file mode 100644
> index 00000000000..27782401c93
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/c2x-stdarg-2.c
> @@ -0,0 +1,22 @@
> +/* Test C2x variadic functions with no named parameters.  Compilation tests,
> +   valid code, verify not considered unprototyped functions.  */
> +/* { dg-do compile } */
> +/* { dg-options "-std=c2x -pedantic-errors -Wstrict-prototypes -Wold-style-definition" } */
> +
> +int f (...);
> +int g (int (...));
> +int h (...) { return 0; }
> +
> +typedef int A[];
> +typedef int A2[2];
> +
> +A *f1 (...);
> +A2 *f1 (...);
> +A *f1 (...) { return 0; }
> +
> +A2 *f2 (...);
> +A *f2 (...);
> +A2 *f2 (...) { return 0; }
> +typeof (f1) f2;
> +
> +int t () { return f () + f (1) + f (1, 2) + h () + h (1.5, 2, f1) + g (f); }
> diff --git a/gcc/testsuite/gcc.dg/c2x-stdarg-3.c b/gcc/testsuite/gcc.dg/c2x-stdarg-3.c
> new file mode 100644
> index 00000000000..e2e14063e91
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/c2x-stdarg-3.c
> @@ -0,0 +1,16 @@
> +/* Test C2x variadic functions with no named parameters.  Compilation tests,
> +   invalid code.  */
> +/* { dg-do compile } */
> +/* { dg-options "-std=c2x -pedantic-errors" } */
> +
> +int f (...); /* { dg-message "previous declaration" } */
> +int f (); /* { dg-error "conflicting types" } */
> +
> +int f2 (...); /* { dg-message "previous declaration" } */
> +int f2 (int); /* { dg-error "conflicting types" } */
> +
> +int g (); /* { dg-message "previous declaration" } */
> +int g (...); /* { dg-error "conflicting types" } */
> +
> +int g2 (int); /* { dg-message "previous declaration" } */
> +int g2 (...); /* { dg-error "conflicting types" } */
> diff --git a/gcc/testsuite/gcc.dg/c2x-stdarg-4.c b/gcc/testsuite/gcc.dg/c2x-stdarg-4.c
> new file mode 100644
> index 00000000000..1f8718dec68
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/c2x-stdarg-4.c
> @@ -0,0 +1,164 @@
> +/* Test C2x variadic functions with no named parameters, or last named
> +   parameter with a declaration not allowed in C17.  Execution tests.  */
> +/* { dg-do run } */
> +/* { dg-options "-std=c2x -pedantic-errors" } */
> +
> +#include <stdarg.h>
> +
> +extern void abort (void);
> +extern void exit (int);
> +
> +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);
> +  for (int i = 0; i < 10; i++)
> +    if (va_arg (ap, double) != i)
> +      abort ();
> +  va_end (ap);
> +}
> +
> +void
> +h1 (register int x, ...)
> +{
> +  va_list ap;
> +  va_start (ap);
> +  for (int i = 0; i < 10; i++)
> +    {
> +      if (va_arg (ap, double) != i)
> +       abort ();
> +      i++;
> +      if (va_arg (ap, int) != i)
> +       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)
> +       abort ();
> +      i++;
> +      if (va_arg (ap, int) != i)
> +       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)
> +       abort ();
> +      i++;
> +      if (va_arg (ap, int) != i)
> +       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)
> +       abort ();
> +      i++;
> +      if (va_arg (ap, int) != i)
> +       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)
> +       abort ();
> +      i++;
> +      if (va_arg (ap, int) != i)
> +       abort ();
> +    }
> +  va_end (ap);
> +}
> +
> +void
> +h6 (volatile long x, ...)
> +{
> +  va_list ap;
> +  va_start (ap);
> +  for (int i = 0; i < 10; i++)
> +    {
> +      if (va_arg (ap, double) != i)
> +       abort ();
> +      i++;
> +      if (va_arg (ap, int) != i)
> +       abort ();
> +    }
> +  va_end (ap);
> +}
> +
> +struct s { char c[1000]; };
> +
> +void
> +h7 (volatile struct s x, ...)
> +{
> +  va_list ap;
> +  va_start (ap);
> +  for (int i = 0; i < 10; i++)
> +    {
> +      if (va_arg (ap, double) != i)
> +       abort ();
> +      i++;
> +      if (va_arg (ap, int) != i)
> +       abort ();
> +    }
> +  va_end (ap);
> +}
> +
> +int
> +main ()
> +{
> +  if (f (1, 2.0, 3, 4.0) != 10.0)
> +    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 ((struct s) {}, 0.0, 1, 2.0, 3, 4.0, 5, 6.0, 7, 8.0, 9);
> +  exit (0);
> +}
> diff --git a/gcc/testsuite/gcc.dg/diagnostic-token-ranges.c b/gcc/testsuite/gcc.dg/diagnostic-token-ranges.c
> index 7d7ec0a9e0b..31085be1421 100644
> --- a/gcc/testsuite/gcc.dg/diagnostic-token-ranges.c
> +++ b/gcc/testsuite/gcc.dg/diagnostic-token-ranges.c
> @@ -1,4 +1,4 @@
> -/* { dg-options "-fdiagnostics-show-caret -Wc++-compat -std=c11" } */
> +/* { dg-options "-fdiagnostics-show-caret -Wc++-compat -std=c11 -pedantic" } */
>
>  /* Verify that various diagnostics show source code ranges.  */
>
> @@ -48,7 +48,7 @@ void test_identifier_conflicts_with_cplusplus (void)
>  }
>
>  extern void
> -bogus_varargs (...); /* { dg-error "ISO C requires a named argument before '...'" } */
> +bogus_varargs (...); /* { dg-warning "ISO C requires a named argument before '...'" } */
>  /*
>  { dg-begin-multiline-output "" }
>   bogus_varargs (...);
> diff --git a/gcc/testsuite/gcc.dg/format/sentinel-1.c b/gcc/testsuite/gcc.dg/format/sentinel-1.c
> index 0c8a2ac7737..16c75a8a961 100644
> --- a/gcc/testsuite/gcc.dg/format/sentinel-1.c
> +++ b/gcc/testsuite/gcc.dg/format/sentinel-1.c
> @@ -15,7 +15,7 @@ extern char *envp[];
>  extern int a ATTR; /* { dg-warning "applies to function types" "sentinel" } */
>
>  extern void foo1 (const char *, ...) ATTR; /* { dg-message "note: declared here" } */
> -extern void foo2 (...) ATTR; /* { dg-error "ISO C requires|named arguments" "sentinel" } */
> +extern void foo2 (...) ATTR;
>  extern void foo3 () ATTR; /* { dg-warning "named arguments" "sentinel" } */
>  extern void foo4 (const char *, int) ATTR; /* { dg-warning "variadic functions" "sentinel" } */
>  extern void foo5 (const char *, ...) __attribute__ ((__sentinel__(1)));
> diff --git a/gcc/testsuite/gcc.dg/gnu2x-stdarg-1.c b/gcc/testsuite/gcc.dg/gnu2x-stdarg-1.c
> new file mode 100644
> index 00000000000..bb64cdeb48a
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/gnu2x-stdarg-1.c
> @@ -0,0 +1,8 @@
> +/* Test variadic functions with no named parameters do not accept GNU
> +   attributes before '...'.  */
> +/* { dg-do compile } */
> +/* { dg-options "-std=gnu2x" } */
> +
> +int f (__attribute__(()) ...); /* { dg-error "expected" } */
> +int g (int (__attribute__(()) ...)); /* { dg-error "expected" } */
> +int h (__attribute__(()) ...) { return 0; } /* { dg-error "expected" } */
> diff --git a/gcc/testsuite/gcc.dg/torture/c2x-stdarg-split-1a.c b/gcc/testsuite/gcc.dg/torture/c2x-stdarg-split-1a.c
> new file mode 100644
> index 00000000000..f527b823287
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/torture/c2x-stdarg-split-1a.c
> @@ -0,0 +1,37 @@
> +/* Test C2x variadic functions with no named parameters, or last named
> +   parameter with a declaration not allowed in C17.  Execution tests split
> +   between source files.  */
> +/* { dg-do run } */
> +/* { dg-options "-std=c2x -pedantic-errors" } */
> +/* { dg-additional-sources "c2x-stdarg-split-1b.c" } */
> +
> +extern void abort (void);
> +extern void exit (int);
> +
> +double f (...);
> +void g (...);
> +void h1 (register int x, ...);
> +void h2 (int x(), ...);
> +void h3 (int x[10], ...);
> +void h4 (char x, ...);
> +void h5 (float x, ...);
> +void h6 (volatile long x, ...);
> +struct s { char c[1000]; };
> +void h7 (volatile struct s x, ...);
> +
> +int
> +main ()
> +{
> +  if (f (1, 2.0, 3, 4.0) != 10.0)
> +    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 ((struct s) {}, 0.0, 1, 2.0, 3, 4.0, 5, 6.0, 7, 8.0, 9);
> +  exit (0);
> +}
> diff --git a/gcc/testsuite/gcc.dg/torture/c2x-stdarg-split-1b.c b/gcc/testsuite/gcc.dg/torture/c2x-stdarg-split-1b.c
> new file mode 100644
> index 00000000000..55a01b20beb
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/torture/c2x-stdarg-split-1b.c
> @@ -0,0 +1,147 @@
> +/* Test C2x variadic functions with no named parameters, or last named
> +   parameter with a declaration not allowed in C17.  Execution tests split
> +   between source files.  */
> +/* { dg-do compile } */
> +/* { dg-options "-std=c2x -pedantic-errors" } */
> +
> +#include <stdarg.h>
> +
> +extern void abort (void);
> +
> +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);
> +  for (int i = 0; i < 10; i++)
> +    if (va_arg (ap, double) != i)
> +      abort ();
> +  va_end (ap);
> +}
> +
> +void
> +h1 (register int x, ...)
> +{
> +  va_list ap;
> +  va_start (ap);
> +  for (int i = 0; i < 10; i++)
> +    {
> +      if (va_arg (ap, double) != i)
> +       abort ();
> +      i++;
> +      if (va_arg (ap, int) != i)
> +       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)
> +       abort ();
> +      i++;
> +      if (va_arg (ap, int) != i)
> +       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)
> +       abort ();
> +      i++;
> +      if (va_arg (ap, int) != i)
> +       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)
> +       abort ();
> +      i++;
> +      if (va_arg (ap, int) != i)
> +       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)
> +       abort ();
> +      i++;
> +      if (va_arg (ap, int) != i)
> +       abort ();
> +    }
> +  va_end (ap);
> +}
> +
> +void
> +h6 (volatile long x, ...)
> +{
> +  va_list ap;
> +  va_start (ap);
> +  for (int i = 0; i < 10; i++)
> +    {
> +      if (va_arg (ap, double) != i)
> +       abort ();
> +      i++;
> +      if (va_arg (ap, int) != i)
> +       abort ();
> +    }
> +  va_end (ap);
> +}
> +
> +struct s { char c[1000]; };
> +
> +void
> +h7 (volatile struct s x, ...)
> +{
> +  va_list ap;
> +  va_start (ap);
> +  for (int i = 0; i < 10; i++)
> +    {
> +      if (va_arg (ap, double) != i)
> +       abort ();
> +      i++;
> +      if (va_arg (ap, int) != i)
> +       abort ();
> +    }
> +  va_end (ap);
> +}
> diff --git a/gcc/tree-core.h b/gcc/tree-core.h
> index 80b886cc3e4..af75522504f 100644
> --- a/gcc/tree-core.h
> +++ b/gcc/tree-core.h
> @@ -1717,7 +1717,8 @@ struct GTY(()) tree_type_common {
>    unsigned typeless_storage : 1;
>    unsigned empty_flag : 1;
>    unsigned indivisible_p : 1;
> -  unsigned spare : 16;
> +  unsigned no_named_args_stdarg_p : 1;
> +  unsigned spare : 15;
>
>    alias_set_type alias_set;
>    tree pointer_to;
> diff --git a/gcc/tree-streamer-in.cc b/gcc/tree-streamer-in.cc
> index 57923da3741..0fa1eba86ab 100644
> --- a/gcc/tree-streamer-in.cc
> +++ b/gcc/tree-streamer-in.cc
> @@ -398,6 +398,7 @@ unpack_ts_type_common_value_fields (struct bitpack_d *bp, tree expr)
>    if (AGGREGATE_TYPE_P (expr))
>      TYPE_TYPELESS_STORAGE (expr) = (unsigned) bp_unpack_value (bp, 1);
>    TYPE_EMPTY_P (expr) = (unsigned) bp_unpack_value (bp, 1);
> +  TYPE_NO_NAMED_ARGS_STDARG_P (expr) = (unsigned) bp_unpack_value (bp, 1);
>    TYPE_PRECISION (expr) = bp_unpack_var_len_unsigned (bp);
>    SET_TYPE_ALIGN (expr, bp_unpack_var_len_unsigned (bp));
>  #ifdef ACCEL_COMPILER
> diff --git a/gcc/tree-streamer-out.cc b/gcc/tree-streamer-out.cc
> index 68a2818a9f9..3bf95ffd66c 100644
> --- a/gcc/tree-streamer-out.cc
> +++ b/gcc/tree-streamer-out.cc
> @@ -365,6 +365,7 @@ pack_ts_type_common_value_fields (struct bitpack_d *bp, tree expr)
>    if (AGGREGATE_TYPE_P (expr))
>      bp_pack_value (bp, TYPE_TYPELESS_STORAGE (expr), 1);
>    bp_pack_value (bp, TYPE_EMPTY_P (expr), 1);
> +  bp_pack_value (bp, TYPE_NO_NAMED_ARGS_STDARG_P (expr), 1);
>    bp_pack_var_len_unsigned (bp, TYPE_PRECISION (expr));
>    bp_pack_var_len_unsigned (bp, TYPE_ALIGN (expr));
>  }
> diff --git a/gcc/tree.cc b/gcc/tree.cc
> index 04603c8c902..172098787dd 100644
> --- a/gcc/tree.cc
> +++ b/gcc/tree.cc
> @@ -6112,7 +6112,9 @@ type_cache_hasher::equal (type_hash *a, type_hash *b)
>                                       TYPE_FIELDS (b->type))));
>
>      case FUNCTION_TYPE:
> -      if (TYPE_ARG_TYPES (a->type) == TYPE_ARG_TYPES (b->type)
> +      if ((TYPE_ARG_TYPES (a->type) == TYPE_ARG_TYPES (b->type)
> +          && (TYPE_NO_NAMED_ARGS_STDARG_P (a->type)
> +              == TYPE_NO_NAMED_ARGS_STDARG_P (b->type)))
>           || (TYPE_ARG_TYPES (a->type)
>               && TREE_CODE (TYPE_ARG_TYPES (a->type)) == TREE_LIST
>               && TYPE_ARG_TYPES (b->type)
> @@ -7364,10 +7366,13 @@ maybe_canonicalize_argtypes (tree argtypes,
>     given arguments of types ARG_TYPES.
>     ARG_TYPES is a chain of TREE_LIST nodes whose TREE_VALUEs
>     are data type nodes for the arguments of the function.
> +   NO_NAMED_ARGS_STDARG_P is true if this is a prototyped
> +   variable-arguments function with (...) prototype (no named arguments).
>     If such a type has already been constructed, reuse it.  */
>
>  tree
> -build_function_type (tree value_type, tree arg_types)
> +build_function_type (tree value_type, tree arg_types,
> +                    bool no_named_args_stdarg_p)
>  {
>    tree t;
>    inchash::hash hstate;
> @@ -7386,6 +7391,11 @@ build_function_type (tree value_type, tree arg_types)
>    t = make_node (FUNCTION_TYPE);
>    TREE_TYPE (t) = value_type;
>    TYPE_ARG_TYPES (t) = arg_types;
> +  if (no_named_args_stdarg_p)
> +    {
> +      gcc_assert (arg_types == NULL_TREE);
> +      TYPE_NO_NAMED_ARGS_STDARG_P (t) = 1;
> +    }
>
>    /* If we already have such a type, use the old one.  */
>    hashval_t hash = type_hash_canon_hash (t);
> @@ -7436,7 +7446,7 @@ build_function_type_list_1 (bool vaargs, tree return_type, va_list argp)
>        args = nreverse (args);
>        TREE_CHAIN (last) = void_list_node;
>      }
> -  args = build_function_type (return_type, args);
> +  args = build_function_type (return_type, args, vaargs && args == NULL_TREE);
>
>    return args;
>  }
> @@ -7491,7 +7501,7 @@ build_function_type_array_1 (bool vaargs, tree return_type, int n,
>    for (i = n - 1; i >= 0; i--)
>      t = tree_cons (NULL_TREE, arg_types[i], t);
>
> -  return build_function_type (return_type, t);
> +  return build_function_type (return_type, t, vaargs && n == 0);
>  }
>
>  /* Build a function type.  RETURN_TYPE is the type returned by the
> @@ -9994,7 +10004,8 @@ reconstruct_complex_type (tree type, tree bottom)
>    else if (TREE_CODE (type) == FUNCTION_TYPE)
>      {
>        inner = 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));
>      }
>    else if (TREE_CODE (type) == METHOD_TYPE)
>      {
> @@ -11612,6 +11623,9 @@ stdarg_p (const_tree fntype)
>    if (!fntype)
>      return false;
>
> +  if (TYPE_NO_NAMED_ARGS_STDARG_P (fntype))
> +    return true;
> +
>    FOREACH_FUNCTION_ARGS (fntype, t, args_iter)
>      {
>        n = t;
> @@ -11629,6 +11643,9 @@ prototype_p (const_tree fntype)
>
>    gcc_assert (fntype != NULL_TREE);
>
> +  if (TYPE_NO_NAMED_ARGS_STDARG_P (fntype))
> +    return true;
> +
>    t = TYPE_ARG_TYPES (fntype);
>    return (t != NULL_TREE);
>  }
> @@ -13647,7 +13664,9 @@ gimple_canonical_types_compatible_p (const_tree t1, const_tree t2,
>                                                 trust_type_canonical))
>         return false;
>
> -      if (TYPE_ARG_TYPES (t1) == TYPE_ARG_TYPES (t2))
> +      if (TYPE_ARG_TYPES (t1) == TYPE_ARG_TYPES (t2)
> +         && (TYPE_NO_NAMED_ARGS_STDARG_P (t1)
> +             == TYPE_NO_NAMED_ARGS_STDARG_P (t2)))
>         return true;
>        else
>         {
> diff --git a/gcc/tree.h b/gcc/tree.h
> index a50f7b2be9d..d6a5fdf6d81 100644
> --- a/gcc/tree.h
> +++ b/gcc/tree.h
> @@ -772,6 +772,12 @@ extern void omp_clause_range_check_failed (const_tree, const char *, int,
>     normal GNU extensions for target-specific vector types.  */
>  #define TYPE_INDIVISIBLE_P(NODE) (TYPE_CHECK (NODE)->type_common.indivisible_p)
>
> +/* True if this is a stdarg function with no named arguments (C2x
> +   (...) prototype, where arguments can be accessed with va_start and
> +   va_arg), as opposed to an unprototyped function.  */
> +#define TYPE_NO_NAMED_ARGS_STDARG_P(NODE) \
> +  (TYPE_CHECK (NODE)->type_common.no_named_args_stdarg_p)
> +
>  /* In an IDENTIFIER_NODE, this means that assemble_name was called with
>     this string as an argument.  */
>  #define TREE_SYMBOL_REFERENCED(NODE) \
> @@ -4734,7 +4740,7 @@ extern tree build_array_type_1 (tree, tree, bool, bool, bool);
>  extern tree build_array_type (tree, tree, bool = false);
>  extern tree build_nonshared_array_type (tree, tree);
>  extern tree build_array_type_nelts (tree, poly_uint64);
> -extern tree build_function_type (tree, tree);
> +extern tree build_function_type (tree, tree, bool = false);
>  extern tree build_function_type_list (tree, ...);
>  extern tree build_varargs_function_type_list (tree, ...);
>  extern tree build_function_type_array (tree, int, tree *);
>
> --
> Joseph S. Myers
> joseph@codesourcery.com

  reply	other threads:[~2022-10-28  8:34 UTC|newest]

Thread overview: 9+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-10-21 22:15 Joseph Myers
2022-10-25 11:18 ` Richard Biener
2022-10-25 19:42   ` Joseph Myers
2022-10-28  8:34     ` Richard Biener [this message]
2022-11-04  5:29 ` Xi Ruoyao
2022-11-04  6:32   ` Xi Ruoyao
2022-11-04  8:19     ` Eric Botcazou
2023-11-25 14:21 ` Gerald Pfeifer
2023-11-28  0:50   ` Joseph Myers

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=CAFiYyc2udQ2AJXszLD77UjEU5e9W8mJiq+y8oFJ0BY3ZGRF76Q@mail.gmail.com \
    --to=richard.guenther@gmail.com \
    --cc=gcc-patches@gcc.gnu.org \
    --cc=joseph@codesourcery.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).