{ "__builtin_tgmath", RID_BUILTIN_TGMATH, D_CONLY },
{ "__builtin_offsetof", RID_OFFSETOF, 0 },
{ "__builtin_types_compatible_p", RID_TYPES_COMPATIBLE_P, D_CONLY },
+ { "__builtin_c23_va_start", RID_C23_VA_START, D_C23 },
{ "__builtin_va_arg", RID_VA_ARG, 0 },
{ "__complex", RID_COMPLEX, 0 },
{ "__complex__", RID_COMPLEX, 0 },
/* C extensions */
RID_ASM, RID_TYPEOF, RID_TYPEOF_UNQUAL, RID_ALIGNOF, RID_ATTRIBUTE,
- RID_VA_ARG,
+ RID_C23_VA_START, RID_VA_ARG,
RID_EXTENSION, RID_IMAGPART, RID_REALPART, RID_LABEL, RID_CHOOSE_EXPR,
RID_TYPES_COMPATIBLE_P, RID_BUILTIN_COMPLEX, RID_BUILTIN_SHUFFLE,
RID_BUILTIN_SHUFFLEVECTOR, RID_BUILTIN_CONVERTVECTOR, RID_BUILTIN_TGMATH,
}
}
break;
+ case RID_C23_VA_START:
+ {
+ c_parser_consume_token (parser);
+ matching_parens parens;
+ if (!parens.require_open (parser))
+ {
+ expr.set_error ();
+ break;
+ }
+ e1 = c_parser_expr_no_commas (parser, NULL);
+ e1 = convert_lvalue_to_rvalue (e1.get_location (), e1, true, true);
+ if (!c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
+ {
+ location_t cloc = c_parser_peek_token (parser)->location;
+ if (!c_parser_require (parser, CPP_COMMA, "expected %<,%>"))
+ {
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
+ expr.set_error ();
+ break;
+ }
+ if (c_parser_next_token_is (parser, CPP_NAME)
+ && c_parser_peek_token (parser)->id_kind == C_ID_ID
+ && (c_parser_peek_2nd_token (parser)->type
+ == CPP_CLOSE_PAREN))
+ {
+ tree name = c_parser_peek_token (parser)->value;
+ location_t nloc = c_parser_peek_token (parser)->location;
+ tree decl = lookup_name (name);
+ tree last_parm
+ = tree_last (DECL_ARGUMENTS (current_function_decl));
+ if (!last_parm || decl != last_parm)
+ warning_at (nloc, OPT_Wvarargs,
+ "optional second parameter of %<va_start%> "
+ "not last named argument");
+ else if (DECL_REGISTER (decl))
+ warning_at (nloc, OPT_Wvarargs,
+ "undefined behavior when second parameter "
+ "of %<va_start%> is declared with "
+ "%<register%> storage");
+ c_parser_consume_token (parser);
+ }
+ else
+ {
+ unsigned nesting_depth = 0;
+ location_t sloc = c_parser_peek_token (parser)->location;
+ location_t eloc = sloc;
+
+ /* For va_start (ap,) the ) comes from stdarg.h.
+ Use location of , in that case, otherwise without
+ -Wsystem-headers nothing is reported. After all,
+ the problematic token is the comma in that case. */
+ if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
+ sloc = eloc = cloc;
+ while (true)
+ {
+ c_token *token = c_parser_peek_token (parser);
+ if (token->type == CPP_CLOSE_PAREN && !nesting_depth)
+ break;
+
+ if (token->type == CPP_EOF)
+ break;
+ if (token->type == CPP_OPEN_PAREN)
+ ++nesting_depth;
+ else if (token->type == CPP_CLOSE_PAREN)
+ --nesting_depth;
+ eloc = token->location;
+ c_parser_consume_token (parser);
+ }
+ if (sloc != eloc)
+ sloc = make_location (sloc, sloc, eloc);
+ warning_at (sloc, OPT_Wvarargs,
+ "%<va_start%> macro used with additional "
+ "arguments other than identifier of the "
+ "last named argument");
+ }
+ }
+ parens.skip_until_found_close (parser);
+ tree fndecl = builtin_decl_explicit (BUILT_IN_VA_START);
+ vec<tree, va_gc> *params;
+ vec_alloc (params, 2);
+ params->quick_push (e1.value);
+ params->quick_push (integer_zero_node);
+ auto_vec<location_t> arg_loc (2);
+ arg_loc.quick_push (e1.get_location ());
+ arg_loc.quick_push (UNKNOWN_LOCATION);
+ expr.value = c_build_function_call_vec (loc, arg_loc, fndecl,
+ params, NULL);
+ set_c_expr_source_range (&expr, loc,
+ parser->tokens_buf[0].get_finish ());
+ expr.m_decimal = 0;
+ expr.original_code = ERROR_MARK;
+ expr.original_type = NULL;
+ release_tree_vector (params);
+ break;
+ }
case RID_OFFSETOF:
{
c_parser_consume_token (parser);
#ifdef _STDARG_H
#if defined __STDC_VERSION__ && __STDC_VERSION__ > 201710L
-#define va_start(v, ...) __builtin_va_start(v, 0)
+#define va_start(...) __builtin_c23_va_start(__VA_ARGS__)
#else
#define va_start(v,l) __builtin_va_start(v,l)
#endif
--- /dev/null
+/* PR c/107980 */
+/* { dg-do compile } */
+/* { dg-options "-std=c23 -pedantic-errors" } */
+
+#include <stdarg.h>
+
+int i;
+
+void
+f0 (...)
+{
+ va_list ap;
+ va_start (ap);
+ va_end (ap);
+}
+
+void
+f1 (...)
+{
+ va_list ap;
+ va_start (ap, i); /* { dg-warning "optional second parameter of 'va_start' not last named argument" } */
+ va_end (ap);
+}
+
+void
+f2 (...)
+{
+ int j = 0;
+ va_list ap;
+ va_start (ap, j); /* { dg-warning "optional second parameter of 'va_start' not last named argument" } */
+ va_end (ap);
+}
+
+void
+f3 (int k, int l, ...)
+{
+ va_list ap;
+ va_start (ap, k); /* { dg-warning "optional second parameter of 'va_start' not last named argument" } */
+ va_end (ap);
+}
+
+void
+f4 (int k, int l, ...)
+{
+ va_list ap;
+ va_start (ap, l);
+ va_end (ap);
+}
+
+void
+f5 (int k, int l, ...)
+{
+ va_list ap;
+ va_start (ap, (int) l); /* { dg-warning "'va_start' macro used with additional arguments other than identifier of the last named argument" } */
+ va_end (ap);
+}
+
+void
+f6 (int k, int l, ...)
+{
+ va_list ap;
+ va_start (ap, l + 0); /* { dg-warning "'va_start' macro used with additional arguments other than identifier of the last named argument" } */
+ va_end (ap);
+}
+
+void
+f7 (int k, int l, ...)
+{
+ va_list ap;
+ va_start (ap, ()()(), [][][], {}{}{}, *+-/1({[_*_]})%&&!?!?); /* { dg-warning "'va_start' macro used with additional arguments other than identifier of the last named argument" } */
+ va_end (ap);
+}
+
+void
+f8 (...)
+{
+ va_list ap;
+ va_start (ap,); /* { dg-warning "'va_start' macro used with additional arguments other than identifier of the last named argument" } */
+ va_end (ap);
+}
+
+void
+f9 (int k, int l, ...)
+{
+ va_list ap;
+ va_start (ap, k+l+****2); /* { dg-warning "'va_start' macro used with additional arguments other than identifier of the last named argument" } */
+ va_end (ap);
+}
+
+void
+f10 (register int m, ...)
+{
+ va_list ap;
+ va_start (ap, m); /* { dg-warning "undefined behavior when second parameter of 'va_start' is declared with 'register' storage" } */
+ va_end (ap);
+}
+
+void
+f11 (int k, int l, ...)
+{
+ va_list ap;
+ va_start (ap, ()()()[[[}}}); /* { dg-warning "'va_start' macro used with additional arguments other than identifier of the last named argument" } */
+ va_end (ap);
+}
+
+void
+f12 (int k, int l, ...)
+{
+ va_list ap;
+ va_start (ap, ]]]]]]{{{{{{); /* { dg-warning "'va_start' macro used with additional arguments other than identifier of the last named argument" } */
+ va_end (ap);
+}
--- /dev/null
+/* PR c/107980 */
+/* { dg-do compile } */
+/* { dg-options "-std=c23 -pedantic-errors" } */
+
+#include <stdarg.h>
+
+void
+f (...)
+{
+ va_start (); /* { dg-error "expected expression before '\\\)' token" } */
+}
g (...)
{
va_list ap;
- va_start (ap, random ! ignored, ignored ** text);
+ va_start (ap, random ! ignored, ignored ** text); /* { dg-warning "'va_start' macro used with additional arguments other than identifier of the last named argument" } */
for (int i = 0; i < 10; i++)
if (va_arg (ap, double) != i)
abort ();
g (...)
{
va_list ap;
- va_start (ap, random ! ignored, ignored ** text);
+ va_start (ap, random ! ignored, ignored ** text); /* { dg-warning "'va_start' macro used with additional arguments other than identifier of the last named argument" } */
for (int i = 0; i < 10; i++)
if (va_arg (ap, double) != i)
abort ();
/* { dg-options "-O2 -std=c23 -pedantic-errors" } */
#include "c23-stdarg-4.c"
+
+/* { dg-warning "'va_start' macro used with additional arguments other than identifier of the last named argument" "" { target *-*-* } 0 } */
/* { dg-options "-O2 -std=c23 -pedantic-errors" } */
#include "c23-stdarg-6.c"
+
+/* { dg-warning "'va_start' macro used with additional arguments other than identifier of the last named argument" "" { target *-*-* } 0 } */
h7 ((struct s) {}, 0.0, 1, 2.0, 3, 4.0, 5, 6.0, 7, 8.0, 9);
exit (0);
}
+
+/* { dg-warning "'va_start' macro used with additional arguments other than identifier of the last named argument" "" { target *-*-* } 0 } */
g (...)
{
va_list ap;
- va_start (ap, random ! ignored, ignored ** text);
+ va_start (ap, random ! ignored, ignored ** text); /* { dg-warning "'va_start' macro used with additional arguments other than identifier of the last named argument" } */
for (int i = 0; i < 10; i++)
if (va_arg (ap, double) != i)
abort ();