static rtx expand_builtin_mathfn_2 (tree, rtx, rtx);
static rtx expand_builtin_mathfn_3 (tree, rtx, rtx);
static rtx expand_builtin_args_info (tree);
-static rtx expand_builtin_next_arg (tree);
+static rtx expand_builtin_next_arg (void);
static rtx expand_builtin_va_start (tree);
static rtx expand_builtin_va_end (tree);
static rtx expand_builtin_va_copy (tree);
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);
times to get the address of either a higher stack frame, or a return
address located within it (depending on FNDECL_CODE). */
-rtx
+static rtx
expand_builtin_return_addr (enum built_in_function fndecl_code, int count,
rtx tem)
{
scheme in the compiler and will only work in the method used by
them. */
-void
+static void
expand_builtin_longjmp (rtx buf_addr, rtx value)
{
rtx fp, lab, stack, insn, last;
longer copying around a value that we don't care about. */
gcc_assert (value == const1_rtx);
- current_function_calls_longjmp = 1;
-
last = get_last_insn ();
#ifdef HAVE_builtin_longjmp
if (HAVE_builtin_longjmp)
/* Argument 1 (read/write flag) must be a compile-time constant int. */
if (TREE_CODE (arg1) != INTEGER_CST)
{
- error ("second arg to %<__builtin_prefetch%> must be a constant");
+ error ("second argument to %<__builtin_prefetch%> must be a constant");
arg1 = integer_zero_node;
}
op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);
/* Argument 1 must be either zero or one. */
if (INTVAL (op1) != 0 && INTVAL (op1) != 1)
{
- warning ("invalid second arg to __builtin_prefetch; using zero");
+ warning ("invalid second argument to %<__builtin_prefetch%>;"
+ " using zero");
op1 = const0_rtx;
}
/* Argument 2 (locality) must be a compile-time constant int. */
if (TREE_CODE (arg2) != INTEGER_CST)
{
- error ("third arg to %<__builtin_prefetch%> must be a constant");
+ error ("third argument to %<__builtin_prefetch%> must be a constant");
arg2 = integer_zero_node;
}
op2 = expand_expr (arg2, NULL_RTX, VOIDmode, 0);
/* Argument 2 must be 0, 1, 2, or 3. */
if (INTVAL (op2) < 0 || INTVAL (op2) > 3)
{
- warning ("invalid third arg to __builtin_prefetch; using zero");
+ warning ("invalid third argument to %<__builtin_prefetch%>; using zero");
op2 = const0_rtx;
}
case QUAL_UNION_TYPE: return union_type_class;
case ARRAY_TYPE: return (TYPE_STRING_FLAG (type)
? string_type_class : array_type_class);
- case SET_TYPE: return set_type_class;
case FILE_TYPE: return file_type_class;
case LANG_TYPE: return lang_type_class;
default: return no_type_class;
narg = builtin_save_expr (arg);
if (narg != arg)
{
+ arg = narg;
arglist = build_tree_list (NULL_TREE, arg);
exp = build_function_call_expr (fndecl, arglist);
}
narg = builtin_save_expr (arg1);
if (narg != arg1)
{
+ arg1 = narg;
temp = build_tree_list (NULL_TREE, narg);
stable = false;
}
narg = builtin_save_expr (arg0);
if (narg != arg0)
{
+ arg0 = narg;
arglist = tree_cons (NULL_TREE, narg, temp);
stable = false;
}
narg = save_expr (arg);
if (narg != arg)
{
+ arg = narg;
arglist = build_tree_list (NULL_TREE, arg);
exp = build_function_call_expr (fndecl, arglist);
}
tree result = fold_builtin_memmove (arglist, type);
if (result)
- expand_expr (result, target, mode, EXPAND_NORMAL);
+ return expand_expr (result, target, mode, EXPAND_NORMAL);
/* If DEST is not a pointer type, call the normal function. */
if (dest_align == 0)
return const0_rtx;
}
-/* Expand ARGLIST, from a call to __builtin_next_arg. */
+/* Expand a call to __builtin_next_arg. */
static rtx
-expand_builtin_next_arg (tree arglist)
+expand_builtin_next_arg (void)
{
- 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");
- return const0_rtx;
- }
-
- if (arglist)
- {
- tree last_parm = tree_last (DECL_ARGUMENTS (current_function_decl));
- tree arg = TREE_VALUE (arglist);
-
- /* Strip off all nops for the sake of the comparison. This
- is not quite the same as STRIP_NOPS. It does more.
- We must also strip off INDIRECT_EXPR for C++ reference
- parameters. */
- while (TREE_CODE (arg) == NOP_EXPR
- || TREE_CODE (arg) == CONVERT_EXPR
- || TREE_CODE (arg) == NON_LVALUE_EXPR
- || TREE_CODE (arg) == INDIRECT_REF)
- arg = TREE_OPERAND (arg, 0);
- if (arg != last_parm)
- warning ("second parameter of %<va_start%> not last named argument");
- }
- 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");
-
+ /* Checking arguments is already done in fold_builtin_next_arg
+ that must be called before this function. */
return expand_binop (Pmode, add_optab,
current_function_internal_arg_pointer,
current_function_arg_offset_rtx,
chain = TREE_CHAIN (arglist);
- if (TREE_CHAIN (chain))
- error ("too many arguments to function %<va_start%>");
+ if (!chain)
+ {
+ error ("too few arguments to function %<va_start%>");
+ return const0_rtx;
+ }
- fold_builtin_next_arg (chain);
+ if (fold_builtin_next_arg (chain))
+ return const0_rtx;
- nextarg = expand_builtin_next_arg (chain);
+ nextarg = expand_builtin_next_arg ();
valist = stabilize_va_list (TREE_VALUE (arglist), 1);
#ifdef EXPAND_BUILTIN_VA_START
else if (! host_integerp (TREE_VALUE (arglist), 1))
{
if (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_FRAME_ADDRESS)
- error ("invalid arg to %<__builtin_frame_address%>");
+ error ("invalid argument to %<__builtin_frame_address%>");
else
- error ("invalid arg to %<__builtin_return_address%>");
+ error ("invalid argument to %<__builtin_return_address%>");
return const0_rtx;
}
else
if (tem == NULL)
{
if (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_FRAME_ADDRESS)
- warning ("unsupported arg to %<__builtin_frame_address%>");
+ warning ("unsupported argument to %<__builtin_frame_address%>");
else
- warning ("unsupported arg to %<__builtin_return_address%>");
+ warning ("unsupported argument to %<__builtin_return_address%>");
return const0_rtx;
}
if (TREE_CODE (c) != INTEGER_CST)
{
- error ("second arg to %<__builtin_expect%> must be a constant");
+ error ("second argument to %<__builtin_expect%> must be a constant");
c = integer_zero_node;
}
return ret;
}
-void
+static void
expand_builtin_trap (void)
{
#ifdef HAVE_trap
/* Return the address of the first anonymous stack arg. */
case BUILT_IN_NEXT_ARG:
- fold_builtin_next_arg (arglist);
- return expand_builtin_next_arg (arglist);
+ if (fold_builtin_next_arg (arglist))
+ return const0_rtx;
+ return expand_builtin_next_arg ();
case BUILT_IN_CLASSIFY_TYPE:
return expand_builtin_classify_type (arglist);
if (value != const1_rtx)
{
- error ("__builtin_longjmp second argument must be 1");
+ error ("%<__builtin_longjmp%> second argument must be 1");
return const0_rtx;
}
{
REAL_VALUE_TYPE real;
+ /* __builtin_inff is intended to be usable to define INFINITY on all
+ targets. If an infinity is not available, INFINITY expands "to a
+ positive constant of type float that overflows at translation
+ time", footnote "In this case, using INFINITY will violate the
+ constraint in 6.4.4 and thus require a diagnostic." (C99 7.12#4).
+ Thus we pedwarn to ensure this constraint violation is
+ diagnosed. */
if (!MODE_HAS_INFINITIES (TYPE_MODE (type)) && warn)
- warning ("target format does not support infinity");
+ pedwarn ("target format does not support infinity");
real_inf (&real);
return build_real (type, real);
tree type = TREE_TYPE (TREE_TYPE (fndecl));
enum tree_code code;
tree arg0, arg1;
+ tree type0, type1;
+ enum tree_code code0, code1;
+ tree cmp_type = NULL_TREE;
if (!validate_arglist (arglist, REAL_TYPE, REAL_TYPE, VOID_TYPE))
{
- enum tree_code code0, code1;
- tree type0, type1;
- tree cmp_type = 0;
-
/* Check that we have exactly two arguments. */
if (arglist == 0 || TREE_CHAIN (arglist) == 0)
{
IDENTIFIER_POINTER (DECL_NAME (fndecl)));
return error_mark_node;
}
-
- arg0 = TREE_VALUE (arglist);
- arg1 = TREE_VALUE (TREE_CHAIN (arglist));
-
- type0 = TREE_TYPE (arg0);
- type1 = TREE_TYPE (arg1);
-
- code0 = TREE_CODE (type0);
- code1 = TREE_CODE (type1);
-
- if (code0 == REAL_TYPE && code1 == REAL_TYPE)
- /* Choose the wider of two real types. */
- cmp_type = TYPE_PRECISION (type0) >= TYPE_PRECISION (type1)
- ? type0 : type1;
- else if (code0 == REAL_TYPE && code1 == INTEGER_TYPE)
- cmp_type = type0;
- else if (code0 == INTEGER_TYPE && code1 == REAL_TYPE)
- cmp_type = type1;
- else
- {
- error ("non-floating-point argument to function %qs",
- IDENTIFIER_POINTER (DECL_NAME (fndecl)));
- return error_mark_node;
- }
-
- arg0 = fold_convert (cmp_type, arg0);
- arg1 = fold_convert (cmp_type, arg1);
}
+
+ arg0 = TREE_VALUE (arglist);
+ arg1 = TREE_VALUE (TREE_CHAIN (arglist));
+
+ type0 = TREE_TYPE (arg0);
+ type1 = TREE_TYPE (arg1);
+
+ code0 = TREE_CODE (type0);
+ code1 = TREE_CODE (type1);
+
+ if (code0 == REAL_TYPE && code1 == REAL_TYPE)
+ /* Choose the wider of two real types. */
+ cmp_type = TYPE_PRECISION (type0) >= TYPE_PRECISION (type1)
+ ? type0 : type1;
+ else if (code0 == REAL_TYPE && code1 == INTEGER_TYPE)
+ cmp_type = type0;
+ else if (code0 == INTEGER_TYPE && code1 == REAL_TYPE)
+ cmp_type = type1;
else
{
- arg0 = TREE_VALUE (arglist);
- arg1 = TREE_VALUE (TREE_CHAIN (arglist));
+ error ("non-floating-point argument to function %qs",
+ IDENTIFIER_POINTER (DECL_NAME (fndecl)));
+ return error_mark_node;
}
+
+ arg0 = fold_convert (cmp_type, arg0);
+ arg1 = fold_convert (cmp_type, arg1);
if (unordered_code == UNORDERED_EXPR)
{
return build_function_call_expr (fn, arglist);
}
-static void
+/* Fold the new_arg's arguments (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");
- else if (arglist)
+ {
+ error ("%<va_start%> used in function with fixed args");
+ return true;
+ }
+ else if (!arglist)
+ {
+ /* 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;
+ }
+ /* We use __builtin_va_start (ap, 0, 0) or __builtin_next_arg (0, 0)
+ when we checked the arguments and if needed issued a warning. */
+ else if (!TREE_CHAIN (arglist)
+ || !integer_zerop (TREE_VALUE (arglist))
+ || !integer_zerop (TREE_VALUE (TREE_CHAIN (arglist)))
+ || TREE_CHAIN (TREE_CHAIN (arglist)))
{
tree last_parm = tree_last (DECL_ARGUMENTS (current_function_decl));
tree arg = TREE_VALUE (arglist);
+ if (TREE_CHAIN (arglist))
+ {
+ error ("%<va_start%> used with too many arguments");
+ return true;
+ }
+
/* Strip off all nops for the sake of the comparison. This
is not quite the same as STRIP_NOPS. It does more.
We must also strip off INDIRECT_EXPR for C++ reference
|| TREE_CODE (arg) == INDIRECT_REF)
arg = TREE_OPERAND (arg, 0);
if (arg != last_parm)
- warning ("second parameter of %<va_start%> not last named argument");
- TREE_VALUE (arglist) = arg;
+ {
+ /* FIXME: Sometimes with the tree optimizers 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. */
+ warning ("second parameter of %<va_start%> not last named argument");
+ }
+ /* We want to verify the second parameter just once before the tree
+ optimizers are run and then avoid keeping it in the tree,
+ as otherwise we could warn even for correct code like:
+ void foo (int i, ...)
+ { va_list ap; i++; va_start (ap, i); va_end (ap); } */
+ TREE_VALUE (arglist) = integer_zero_node;
+ TREE_CHAIN (arglist) = build_tree_list (NULL, integer_zero_node);
}
- 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");
+ return false;
}