static tree fold_builtin_strncat (tree);
static tree fold_builtin_strspn (tree);
static tree fold_builtin_strcspn (tree);
-static void fold_builtin_next_arg (tree);
static tree fold_builtin_sprintf (tree, int);
if (TREE_CHAIN (chain))
error ("too many arguments to function %<va_start%>");
- fold_builtin_next_arg (chain);
+ if (fold_builtin_next_arg (chain))
+ {
+ return const0_rtx;
+ }
nextarg = expand_builtin_next_arg (chain);
valist = stabilize_va_list (TREE_VALUE (arglist), 1);
/* Return the address of the first anonymous stack arg. */
case BUILT_IN_NEXT_ARG:
- fold_builtin_next_arg (arglist);
+ if (fold_builtin_next_arg (arglist))
+ return const0_rtx;
return expand_builtin_next_arg (arglist);
case BUILT_IN_CLASSIFY_TYPE:
return build_function_call_expr (fn, arglist);
}
-static void
+/* Fold the new_arg's agruments (ARGLIST). Returns true if there was an error
+ produced. False otherwise. This is done so that we don't output the error
+ or warning twice or three times. */
+bool
fold_builtin_next_arg (tree arglist)
{
tree fntype = TREE_TYPE (current_function_decl);
if (TYPE_ARG_TYPES (fntype) == 0
|| (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype)))
== void_type_node))
- error ("%<va_start%> used in function with fixed args");
+ {
+ error ("%<va_start%> used in function with fixed args");
+ return true;
+ }
else if (arglist)
{
tree last_parm = tree_last (DECL_ARGUMENTS (current_function_decl));
|| TREE_CODE (arg) == INDIRECT_REF)
arg = TREE_OPERAND (arg, 0);
if (arg != last_parm)
- warning ("second parameter of %<va_start%> not last named argument");
+ {
+ /* FIXME: Sometimes with the tree optimizaters we can get the not the last argument
+ even though the user used the last argument. We just warn and set the arg to be
+ the last argument so that we will get wrong-code because of it. */
+ arg = last_parm;
+ warning ("second parameter of %<va_start%> not last named argument");
+ }
TREE_VALUE (arglist) = arg;
}
else
- /* Evidently an out of date version of <stdarg.h>; can't validate
- va_start's second argument, but can still work as intended. */
- warning ("%<__builtin_next_arg%> called without an argument");
+ {
+ /* Evidently an out of date version of <stdarg.h>; can't validate
+ va_start's second argument, but can still work as intended. */
+ warning ("%<__builtin_next_arg%> called without an argument");
+ return true;
+ }
+ return false;
}
}
if (DECL_FUNCTION_CODE (decl) == BUILT_IN_VA_START)
- /* Avoid gimplifying the second argument to va_start, which needs
- to be the plain PARM_DECL. */
- return gimplify_arg (&TREE_VALUE (TREE_OPERAND (*expr_p, 1)), pre_p);
+ {
+ tree arglist = TREE_OPERAND (*expr_p, 1);
+
+ if (!arglist || !TREE_CHAIN (arglist))
+ {
+ error ("too few arguments to function %<va_start%>");
+ *expr_p = build_empty_stmt ();
+ return GS_OK;
+ }
+
+ if (fold_builtin_next_arg (TREE_CHAIN (arglist)))
+ {
+ *expr_p = build_empty_stmt ();
+ return GS_OK;
+ }
+ /* Avoid gimplifying the second argument to va_start, which needs
+ to be the plain PARM_DECL. */
+ return gimplify_arg (&TREE_VALUE (TREE_OPERAND (*expr_p, 1)), pre_p);
+ }
}
/* There is a sequence point before the call, so any side effects in
extern tree fold_builtin_fputs (tree, bool, bool, tree);
extern tree fold_builtin_strcpy (tree, tree);
extern tree fold_builtin_strncpy (tree, tree);
+extern bool fold_builtin_next_arg (tree);
extern enum built_in_function builtin_mathfn_code (tree);
extern tree build_function_call_expr (tree, tree);
extern tree mathfn_built_in (tree, enum built_in_function fn);