From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail-ed1-x536.google.com (mail-ed1-x536.google.com [IPv6:2a00:1450:4864:20::536]) by sourceware.org (Postfix) with ESMTPS id 917A43857BB2 for ; Tue, 25 Oct 2022 11:18:55 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 917A43857BB2 Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=gmail.com Received: by mail-ed1-x536.google.com with SMTP id a5so22587797edb.11 for ; Tue, 25 Oct 2022 04:18:55 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=cc:to:subject:message-id:date:from:in-reply-to:references :mime-version:from:to:cc:subject:date:message-id:reply-to; bh=eglQGburAawEMEyuMQVGz3WBu8ZPHf+W1l/LYzt0Wsc=; b=mMUkbYjH+6dRoOmFhH9Hg1Maw4GVAbPI1Di2i7X1yhV8Dec0SsyFUpMrz5Up0bPZtF xtlvk3aeQjHACTxk99Hb+pqEPMG9blKZfzPoXyyE8p0bYAsbRQ3VCT6ZPVJNMyX3eMPx DH0rPgQM1N0OcNSvRhkYU8iTRGh9tvpEMlQDmpmze/Blwk1kR0jksz+HBsbBUjqMbzUO pMsPL89U1hi42te6egUFSDPeaYcJM7L4sZwLDYrFdsMU5x7NAabstXrLbFvP8M5kfS3L YmRd8LliWhbt67xx3EAlfOTzMX4UtEfVY8tpPVyGUoVc/jvbiiy5EsrqOAL546dWlZOx F2eA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=cc:to:subject:message-id:date:from:in-reply-to:references :mime-version:x-gm-message-state:from:to:cc:subject:date:message-id :reply-to; bh=eglQGburAawEMEyuMQVGz3WBu8ZPHf+W1l/LYzt0Wsc=; b=7PRJUo8FYLsvOsjr426W27QbRm7EP2p/0055wZ29G7TQd7TRaC4k9+LEw90vzxskh1 tyKnYt/z8tffLltLbXEe5SyeytCxEJG7H0XDbiCVeKgiCZ1ca5PwgsiWmI6aPo6o+DuK mAXArQsPAxKADde/WaFhXGccyV8vyL83ArOnRetI4NsyJfOfKLESSFQxNG4QoWRUrQ0k zJQDCKI4gjtwOpHp7Rnm7oNODYsgOStAZy1+DRem8+N9Pt4EW1ueitzL6OfJD1zQKHfW dqQXlDwSBaIm2EXyI+0eaCi11D/O+BmlCPkQtlzPohvlZ0pZyn+4Ljb3suebk8TYUyti zZ9w== X-Gm-Message-State: ACrzQf1QNjEF0AjxKGL3VE78Xx2dAGNNOtYcXpQjTTr8YQ+5YlFUHupd qGR0rm2obIyX3gVgsc6FkDGLUDNtly0otWIemc2+QTvcWE1REg== X-Google-Smtp-Source: AMsMyM4EL3ecQoIVGvhTzM9ufCYKRdBj7SMXmaTStXtPqZRkNzbg6JKy4Ujd805zUdCyYEXFez8j+Nt6B34OJQ3E2LU= X-Received: by 2002:a05:6402:3548:b0:45d:6506:990a with SMTP id f8-20020a056402354800b0045d6506990amr35422196edd.218.1666696733449; Tue, 25 Oct 2022 04:18:53 -0700 (PDT) MIME-Version: 1.0 References: In-Reply-To: From: Richard Biener Date: Tue, 25 Oct 2022 13:18:41 +0200 Message-ID: Subject: Re: c: tree: target: C2x (...) function prototypes and va_start relaxation To: Joseph Myers Cc: gcc-patches@gcc.gnu.org Content-Type: text/plain; charset="UTF-8" X-Spam-Status: No, score=-8.1 required=5.0 tests=BAYES_00,DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,FREEMAIL_FROM,GIT_PATCH_0,RCVD_IN_DNSWL_NONE,SPF_HELO_NONE,SPF_PASS,TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org List-Id: On Sat, Oct 22, 2022 at 1:03 AM Joseph Myers wrote: > > 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 > 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 > 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, the execution test, which would > indicate that this feature is not working correctly. > > Bootstrapped with no regressions for x86_64-pc-linux-gnu. OK to commit? 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? Thanks, Richard. > 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.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/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: 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 80f6e912187..1c29a29b50f 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 fdb96c28c51..868fb781c47 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 1d0f994f281..3e32d3f2b23 100644 > --- a/gcc/config/aarch64/aarch64.cc > +++ b/gcc/config/aarch64/aarch64.cc > @@ -19856,7 +19856,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 480db35f6cd..e92b12129b8 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 387376b3df8..53478e9227b 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 ad57b995e7b..04d21ec8f3a 100644 > --- a/gcc/config/riscv/riscv.cc > +++ b/gcc/config/riscv/riscv.cc > @@ -3728,7 +3728,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 cd4d3c1d72c..9f1481bbeb1 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/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/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 , 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..cb7a5cb9317 > --- /dev/null > +++ b/gcc/testsuite/gcc.dg/c2x-stdarg-4.c > @@ -0,0 +1,42 @@ > +/* Test C2x variadic functions with no named parameters. Execution tests. */ > +/* { dg-do run } */ > +/* { dg-options "-std=c2x -pedantic-errors" } */ > + > +#include > + > +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); > +} > + > +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); > + 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/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.cc b/gcc/tree.cc > index 81a6ceaf181..48ab60d78fe 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 9af971cf401..885df4d0d66 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) \ > @@ -4727,7 +4733,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