/* 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
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);
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
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
}
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
/* 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,
ret->others = NULL_TREE;
ret->pending_sizes = NULL;
ret->had_vla_unspec = 0;
+ ret->no_named_args_stdarg_p = 0;
return ret;
}
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;
}
\f
/* 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)
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);
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
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;
}
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. */
/* 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. */
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,
}
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)
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. */
{
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.
/* 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))
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)
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;
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)
= 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);
{
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);
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;
/* 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)
{
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)
{
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;
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)
{
/* 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
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;
/* 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");
}
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;
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;
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;
/* 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)
{
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);
}
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;
/* 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);
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)
{
@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
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
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,
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);
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;
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 \
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);
/* 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);
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\
/* { dg-do compile } */
/* { dg-options "-Wold-style-definition" } */
-void bar1 ( ... ) {} /* { dg-error "ISO C requires a named argument" } */
+void bar1 ( ... ) {}
void bar2 (int a, ... ) {}
--- /dev/null
+/* 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" } */
--- /dev/null
+/* 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" } */
--- /dev/null
+/* 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; }
static void
test5 (int i, ...)
{
+ (void) i;
va_list ap;
va_start (ap, i);
if (va_arg (ap, void *))
--- /dev/null
+/* 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); }
--- /dev/null
+/* 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); }
--- /dev/null
+/* 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" } */
--- /dev/null
+/* 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);
+}
-/* { 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. */
}
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 (...);
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)));
--- /dev/null
+/* 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" } */
--- /dev/null
+/* 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);
+}
--- /dev/null
+/* 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);
+}
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;
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
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));
}
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)
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;
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);
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;
}
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
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)
{
if (!fntype)
return false;
+ if (TYPE_NO_NAMED_ARGS_STDARG_P (fntype))
+ return true;
+
FOREACH_FUNCTION_ARGS (fntype, t, args_iter)
{
n = t;
gcc_assert (fntype != NULL_TREE);
+ if (TYPE_NO_NAMED_ARGS_STDARG_P (fntype))
+ return true;
+
t = TYPE_ARG_TYPES (fntype);
return (t != NULL_TREE);
}
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
{
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) \
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 *);