aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc')
-rw-r--r--gcc/c-family/c-common.cc11
-rw-r--r--gcc/c-family/c.opt4
-rw-r--r--gcc/c/c-decl.cc13
-rw-r--r--gcc/c/c-parser.cc22
-rw-r--r--gcc/c/c-tree.h2
-rw-r--r--gcc/c/c-typeck.cc20
-rw-r--r--gcc/config/aarch64/aarch64.cc3
-rw-r--r--gcc/config/alpha/alpha.cc5
-rw-r--r--gcc/config/arc/arc.cc3
-rw-r--r--gcc/config/arm/arm.cc3
-rw-r--r--gcc/config/csky/csky.cc3
-rw-r--r--gcc/config/epiphany/epiphany.cc8
-rw-r--r--gcc/config/fr30/fr30.cc23
-rw-r--r--gcc/config/frv/frv.cc3
-rw-r--r--gcc/config/ft32/ft32.cc6
-rw-r--r--gcc/config/i386/i386.cc3
-rw-r--r--gcc/config/ia64/ia64.cc5
-rw-r--r--gcc/config/loongarch/loongarch.cc3
-rw-r--r--gcc/config/m32r/m32r.cc12
-rw-r--r--gcc/config/mcore/mcore.cc5
-rw-r--r--gcc/config/mips/mips.cc3
-rw-r--r--gcc/config/mmix/mmix.cc3
-rw-r--r--gcc/config/nds32/nds32.cc9
-rw-r--r--gcc/config/nios2/nios2.cc3
-rw-r--r--gcc/config/riscv/riscv.cc3
-rw-r--r--gcc/config/rs6000/rs6000-call.cc7
-rw-r--r--gcc/config/sh/sh.cc9
-rw-r--r--gcc/config/visium/visium.cc3
-rw-r--r--gcc/config/vms/vms-c.cc3
-rw-r--r--gcc/doc/invoke.texi10
-rw-r--r--gcc/doc/tm.texi4
-rw-r--r--gcc/fortran/trans-types.cc4
-rw-r--r--gcc/function.cc6
-rw-r--r--gcc/ginclude/stdarg.h4
-rw-r--r--gcc/lto/lto-common.cc1
-rw-r--r--gcc/objc/objc-next-runtime-abi-01.cc2
-rw-r--r--gcc/target.def4
-rw-r--r--gcc/testsuite/gcc.dg/Wold-style-definition-2.c2
-rw-r--r--gcc/testsuite/gcc.dg/c11-stdarg-1.c7
-rw-r--r--gcc/testsuite/gcc.dg/c11-stdarg-2.c7
-rw-r--r--gcc/testsuite/gcc.dg/c11-stdarg-3.c8
-rw-r--r--gcc/testsuite/gcc.dg/c2x-nullptr-1.c1
-rw-r--r--gcc/testsuite/gcc.dg/c2x-stdarg-1.c22
-rw-r--r--gcc/testsuite/gcc.dg/c2x-stdarg-2.c22
-rw-r--r--gcc/testsuite/gcc.dg/c2x-stdarg-3.c16
-rw-r--r--gcc/testsuite/gcc.dg/c2x-stdarg-4.c164
-rw-r--r--gcc/testsuite/gcc.dg/diagnostic-token-ranges.c4
-rw-r--r--gcc/testsuite/gcc.dg/format/sentinel-1.c2
-rw-r--r--gcc/testsuite/gcc.dg/gnu2x-stdarg-1.c8
-rw-r--r--gcc/testsuite/gcc.dg/torture/c2x-stdarg-split-1a.c37
-rw-r--r--gcc/testsuite/gcc.dg/torture/c2x-stdarg-split-1b.c147
-rw-r--r--gcc/tree-core.h3
-rw-r--r--gcc/tree-streamer-in.cc1
-rw-r--r--gcc/tree-streamer-out.cc1
-rw-r--r--gcc/tree.cc31
-rw-r--r--gcc/tree.h8
56 files changed, 621 insertions, 105 deletions
diff --git a/gcc/c-family/c-common.cc b/gcc/c-family/c-common.cc
index cd54c51..5890c18 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 070f85c..63a300e 100644
--- a/gcc/c-family/c.opt
+++ b/gcc/c-family/c.opt
@@ -1512,8 +1512,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 2b83900e..795c971 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -7295,7 +7295,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
@@ -8060,7 +8061,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,
@@ -8130,6 +8132,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;
}
@@ -8321,6 +8324,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;
}
@@ -9935,7 +9939,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)
@@ -10534,7 +10539,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 4d1dcb1..ca533c9 100644
--- a/gcc/c/c-parser.cc
+++ b/gcc/c/c-parser.cc
@@ -4213,7 +4213,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
@@ -4489,25 +4490,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 d787dd4..facfc12 100644
--- a/gcc/c/c-tree.h
+++ b/gcc/c/c-tree.h
@@ -475,6 +475,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 6c16647..052ae6d 100644
--- a/gcc/c/c-typeck.cc
+++ b/gcc/c/c-typeck.cc
@@ -544,17 +544,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. */
@@ -1702,6 +1704,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,
@@ -1715,6 +1719,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 0458c65..d1f979eb 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 66c1714..333f2c6 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 e6f52d8..604a116 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 ee8f1ba..2eb4d51 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 f7b2bf8..537eee6 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 f8c0493..c4e3cea 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 c9b061d..334bb44 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 6f1904b..5cdb0bf 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 ed2d122..d6b73d4 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 aeea26e..e775ba4 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 995ff90..6df1ce7 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 e9ba337..f54c233 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 bca7681..e3489fb 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 28e7074..605d63b 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 699ea6c..0ac0248 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 ffdd8c7..1ac7b88 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 67a6121..639baef 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 1a33c88..6a894ec 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 77bc65b..32f9ef9 100644
--- a/gcc/config/riscv/riscv.cc
+++ b/gcc/config/riscv/riscv.cc
@@ -3730,7 +3730,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 ac3cb7e..6da4de6 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 9bee618..1aec70a 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 03c1a33..e7d1596 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 2f74fb5..ccf6d5f 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 c0ca765..550aec8 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
@@ -2515,14 +2515,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 110f8df..63c8a31 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 fdce56d..def7552 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 6474a66..d3da20e 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 7545ed3..c704c9f 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 d8d0404..f643097 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 409b777..8d41886 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 a3d3b04..25f94c1 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 a69aae6..8e297c9 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 0000000..984577f
--- /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 0000000..bd115e8
--- /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 0000000..0092924
--- /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 9501b51..9f2cb6c 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 0000000..7def49d3
--- /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 0000000..2778240
--- /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 0000000..e2e1406
--- /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 0000000..1f8718d
--- /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 7d7ec0a..31085be 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 0c8a2ac..16c75a8 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 0000000..bb64cde
--- /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 0000000..f527b8232
--- /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 0000000..55a01b2
--- /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 80b886c..af75522 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 57923da..0fa1eba 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 68a2818..3bf95ff 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 04603c8..1720987 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 a50f7b2..d6a5fdf 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 *);