diff options
Diffstat (limited to 'gcc')
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 { @@ -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 *); |