bool *);
static tree handle_sentinel_attribute (tree *, tree, tree, int, bool *);
-static void check_function_nonnull (tree, tree);
+static void check_function_nonnull (tree, int, tree *);
static void check_nonnull_arg (void *, tree, unsigned HOST_WIDE_INT);
static bool nonnull_check_p (tree, unsigned HOST_WIDE_INT);
static bool get_nonnull_operand (tree, unsigned HOST_WIDE_INT *);
{ NULL, 0, 0, false, false, false, NULL }
};
+/* Functions called automatically at the beginning and end of execution. */
+
+tree static_ctors;
+tree static_dtors;
+
/* Push current bindings for the function name VAR_DECLS. */
void
if (!args)
return DEFAULT_INIT_PRIORITY;
+ if (!SUPPORTS_INIT_PRIORITY)
+ {
+ if (is_destructor)
+ error ("destructor priorities are not supported");
+ else
+ error ("constructor priorities are not supported");
+ return DEFAULT_INIT_PRIORITY;
+ }
+
arg = TREE_VALUE (args);
if (!host_integerp (arg, /*pos=*/0)
|| !INTEGRAL_TYPE_P (TREE_TYPE (arg)))
}
/* Check the argument list of a function call for null in argument slots
- that are marked as requiring a non-null pointer argument. */
+ that are marked as requiring a non-null pointer argument. The NARGS
+ arguments are passed in the array ARGARRAY.
+*/
static void
-check_function_nonnull (tree attrs, tree params)
+check_function_nonnull (tree attrs, int nargs, tree *argarray)
{
- tree a, args, param;
- int param_num;
+ tree a, args;
+ int i;
for (a = attrs; a; a = TREE_CHAIN (a))
{
should check for non-null, do it. If the attribute has no args,
then every pointer argument is checked (in which case the check
for pointer type is done in check_nonnull_arg). */
- for (param = params, param_num = 1; ;
- param_num++, param = TREE_CHAIN (param))
+ for (i = 0; i < nargs; i++)
{
- if (!param)
- break;
- if (!args || nonnull_check_p (args, param_num))
+ if (!args || nonnull_check_p (args, i + 1))
check_function_arguments_recurse (check_nonnull_arg, NULL,
- TREE_VALUE (param),
- param_num);
+ argarray[i],
+ i + 1);
}
}
}
}
/* Check that the Nth argument of a function call (counting backwards
- from the end) is a (pointer)0. */
+ from the end) is a (pointer)0. The NARGS arguments are passed in the
+ array ARGARRAY. */
static void
-check_function_sentinel (tree attrs, tree params, tree typelist)
+check_function_sentinel (tree attrs, int nargs, tree *argarray, tree typelist)
{
tree attr = lookup_attribute ("sentinel", attrs);
if (attr)
{
- /* Skip over the named arguments. */
- while (typelist && params)
- {
- typelist = TREE_CHAIN (typelist);
- params = TREE_CHAIN (params);
- }
+ int len = 0;
+ int pos = 0;
+ tree sentinel;
- if (typelist || !params)
- warning (OPT_Wformat,
- "not enough variable arguments to fit a sentinel");
- else
+ /* Skip over the named arguments. */
+ while (typelist && len < nargs)
{
- tree sentinel, end;
- unsigned pos = 0;
-
- if (TREE_VALUE (attr))
- {
- tree p = TREE_VALUE (TREE_VALUE (attr));
- pos = TREE_INT_CST_LOW (p);
- }
-
- sentinel = end = params;
-
- /* Advance `end' ahead of `sentinel' by `pos' positions. */
- while (pos > 0 && TREE_CHAIN (end))
- {
- pos--;
- end = TREE_CHAIN (end);
- }
- if (pos > 0)
- {
- warning (OPT_Wformat,
- "not enough variable arguments to fit a sentinel");
- return;
- }
+ typelist = TREE_CHAIN (typelist);
+ len++;
+ }
- /* Now advance both until we find the last parameter. */
- while (TREE_CHAIN (end))
- {
- end = TREE_CHAIN (end);
- sentinel = TREE_CHAIN (sentinel);
- }
+ if (TREE_VALUE (attr))
+ {
+ tree p = TREE_VALUE (TREE_VALUE (attr));
+ pos = TREE_INT_CST_LOW (p);
+ }
- /* Validate the sentinel. */
- if ((!POINTER_TYPE_P (TREE_TYPE (TREE_VALUE (sentinel)))
- || !integer_zerop (TREE_VALUE (sentinel)))
- /* Although __null (in C++) is only an integer we allow it
- nevertheless, as we are guaranteed that it's exactly
- as wide as a pointer, and we don't want to force
- users to cast the NULL they have written there.
- We warn with -Wstrict-null-sentinel, though. */
- && (warn_strict_null_sentinel
- || null_node != TREE_VALUE (sentinel)))
- warning (OPT_Wformat, "missing sentinel in function call");
+ /* The sentinel must be one of the varargs, i.e.
+ in position >= the number of fixed arguments. */
+ if ((nargs - 1 - pos) < len)
+ {
+ warning (OPT_Wformat,
+ "not enough variable arguments to fit a sentinel");
+ return;
}
+
+ /* Validate the sentinel. */
+ sentinel = argarray[nargs - 1 - pos];
+ if ((!POINTER_TYPE_P (TREE_TYPE (sentinel))
+ || !integer_zerop (sentinel))
+ /* Although __null (in C++) is only an integer we allow it
+ nevertheless, as we are guaranteed that it's exactly
+ as wide as a pointer, and we don't want to force
+ users to cast the NULL they have written there.
+ We warn with -Wstrict-null-sentinel, though. */
+ && (warn_strict_null_sentinel || null_node != sentinel))
+ warning (OPT_Wformat, "missing sentinel in function call");
}
}
return NULL_TREE;
}
\f
-/* Check for valid arguments being passed to a function. */
+/* Check for valid arguments being passed to a function.
+ ATTRS is a list of attributes. There are NARGS arguments in the array
+ ARGARRAY. TYPELIST is the list of argument types for the function.
+ */
void
-check_function_arguments (tree attrs, tree params, tree typelist)
+check_function_arguments (tree attrs, int nargs, tree *argarray, tree typelist)
{
/* Check for null being passed in a pointer argument that must be
non-null. We also need to do this if format checking is enabled. */
if (warn_nonnull)
- check_function_nonnull (attrs, params);
+ check_function_nonnull (attrs, nargs, argarray);
/* Check for errors in format strings. */
if (warn_format || warn_missing_format_attribute)
- check_function_format (attrs, params);
+ check_function_format (attrs, nargs, argarray);
if (warn_format)
- check_function_sentinel (attrs, params, typelist);
+ check_function_sentinel (attrs, nargs, argarray, typelist);
}
/* Generic argument checking recursion routine. PARAM is the argument to
}
}
+/* If FNDECL is a static constructor or destructor, add it to the list
+ of functions to be called by the file scope initialization
+ function. */
+
+void
+c_record_cdtor_fn (tree fndecl)
+{
+ if (targetm.have_ctors_dtors)
+ return;
+
+ if (DECL_STATIC_CONSTRUCTOR (fndecl))
+ static_ctors = tree_cons (NULL_TREE, fndecl, static_ctors);
+ if (DECL_STATIC_DESTRUCTOR (fndecl))
+ static_dtors = tree_cons (NULL_TREE, fndecl, static_dtors);
+}
+
+/* Synthesize a function which calls all the global ctors or global
+ dtors in this file. This is only used for targets which do not
+ support .ctors/.dtors sections. FIXME: Migrate into cgraph. */
+static void
+build_cdtor (int method_type, tree cdtors)
+{
+ tree body = 0;
+
+ if (!cdtors)
+ return;
+
+ for (; cdtors; cdtors = TREE_CHAIN (cdtors))
+ append_to_statement_list (build_function_call (TREE_VALUE (cdtors), 0),
+ &body);
+
+ cgraph_build_static_cdtor (method_type, body, DEFAULT_INIT_PRIORITY);
+}
+
+/* Generate functions to call static constructors and destructors
+ for targets that do not support .ctors/.dtors sections. These
+ functions have magic names which are detected by collect2. */
+
+void
+c_build_cdtor_fns (void)
+{
+ if (!targetm.have_ctors_dtors)
+ {
+ build_cdtor ('I', static_ctors);
+ static_ctors = NULL_TREE;
+ build_cdtor ('D', static_dtors);
+ static_dtors = NULL_TREE;
+ }
+ else
+ {
+ gcc_assert (!static_ctors);
+ gcc_assert (!static_dtors);
+ }
+}
+
#include "gt-c-common.h"