OSDN Git Service

2007-03-04 Simon Martin <simartin@users.sourceforge.net>
[pf3gnuchains/gcc-fork.git] / gcc / c-common.c
index 6d1606c..6ea3800 100644 (file)
@@ -554,7 +554,7 @@ static tree handle_warn_unused_result_attribute (tree *, tree, tree, int,
                                                 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 *);
@@ -663,6 +663,11 @@ const struct attribute_spec c_common_format_attribute_table[] =
   { 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
@@ -4692,6 +4697,15 @@ get_priority (tree args, bool is_destructor)
   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)))
@@ -5696,13 +5710,15 @@ handle_nonnull_attribute (tree *node, tree ARG_UNUSED (name),
 }
 
 /* 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))
     {
@@ -5714,85 +5730,65 @@ check_function_nonnull (tree attrs, tree params)
             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");
     }
 }
 
@@ -5982,23 +5978,26 @@ handle_sentinel_attribute (tree *node, tree name, tree args,
   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
@@ -6875,4 +6874,59 @@ warn_for_unused_label (tree label)
     }
 }
 
+/* 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"