OSDN Git Service

2012-02-01 Richard Guenther <rguenther@suse.de>
[pf3gnuchains/gcc-fork.git] / gcc / attribs.c
index 3c60e8b..0e94fd2 100644 (file)
@@ -1,6 +1,7 @@
 /* Functions dealing with attribute handling, used by most front ends.
    Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
-   2002, 2003, 2004, 2005, 2007 Free Software Foundation, Inc.
+   2002, 2003, 2004, 2005, 2007, 2008, 2009, 2010
+   Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -24,17 +25,14 @@ along with GCC; see the file COPYING3.  If not see
 #include "tm.h"
 #include "tree.h"
 #include "flags.h"
-#include "toplev.h"
-#include "output.h"
-#include "rtl.h"
+#include "diagnostic-core.h"
 #include "ggc.h"
 #include "tm_p.h"
 #include "cpplib.h"
 #include "target.h"
 #include "langhooks.h"
 #include "hashtab.h"
-
-static void init_attributes (void);
+#include "plugin.h"
 
 /* Table of the tables of attributes (common, language, format, machine)
    searched.  */
@@ -57,7 +55,7 @@ static bool attributes_initialized = false;
 
 static const struct attribute_spec empty_attribute_table[] =
 {
-  { NULL, 0, 0, false, false, false, NULL }
+  { NULL, 0, 0, false, false, false, NULL, false }
 };
 
 /* Return base name of the attribute.  Ie '__attr__' is turned into 'attr'.
@@ -107,12 +105,15 @@ eq_attr (const void *p, const void *q)
 /* Initialize attribute tables, and make some sanity checks
    if --enable-checking.  */
 
-static void
+void
 init_attributes (void)
 {
   size_t i;
   int k;
 
+  if (attributes_initialized)
+    return;
+
   attribute_tables[0] = lang_hooks.common_attribute_table;
   attribute_tables[1] = lang_hooks.attribute_table;
   attribute_tables[2] = lang_hooks.format_attribute_table;
@@ -165,7 +166,8 @@ init_attributes (void)
          gcc_assert (strcmp (attribute_tables[i][j].name,
                              attribute_tables[i][k].name));
     }
-  /* Check that no name occurs in more than one table.  */
+  /* Check that no name occurs in more than one table.  Names that
+     begin with '*' are exempt, and may be overridden.  */
   for (i = 0; i < ARRAY_SIZE (attribute_tables); i++)
     {
       size_t j, k, l;
@@ -173,8 +175,9 @@ init_attributes (void)
       for (j = i + 1; j < ARRAY_SIZE (attribute_tables); j++)
        for (k = 0; attribute_tables[i][k].name != NULL; k++)
          for (l = 0; attribute_tables[j][l].name != NULL; l++)
-           gcc_assert (strcmp (attribute_tables[i][k].name,
-                               attribute_tables[j][l].name));
+           gcc_assert (attribute_tables[i][k].name[0] == '*'
+                       || strcmp (attribute_tables[i][k].name,
+                                  attribute_tables[j][l].name));
     }
 #endif
 
@@ -182,24 +185,38 @@ init_attributes (void)
   for (i = 0; i < ARRAY_SIZE (attribute_tables); i++)
     for (k = 0; attribute_tables[i][k].name != NULL; k++)
       {
-       struct substring str;
-       const void **slot;
-
-       str.str = attribute_tables[i][k].name;
-       str.length = strlen (attribute_tables[i][k].name);
-       slot = (const void **)htab_find_slot_with_hash (attribute_hash, &str,
-                                        substring_hash (str.str, str.length),
-                                        INSERT);
-       gcc_assert (!*slot);
-       *slot = &attribute_tables[i][k];
+        register_attribute (&attribute_tables[i][k]);
       }
+  invoke_plugin_callbacks (PLUGIN_ATTRIBUTES, NULL);
   attributes_initialized = true;
 }
 
+/* Insert a single ATTR into the attribute table.  */
+
+void
+register_attribute (const struct attribute_spec *attr)
+{
+  struct substring str;
+  void **slot;
+
+  str.str = attr->name;
+  str.length = strlen (str.str);
+
+  /* Attribute names in the table must be in the form 'text' and not
+     in the form '__text__'.  */
+  gcc_assert (str.length > 0 && str.str[0] != '_');
+
+  slot = htab_find_slot_with_hash (attribute_hash, &str,
+                                  substring_hash (str.str, str.length),
+                                  INSERT);
+  gcc_assert (!*slot || attr->name[0] == '*');
+  *slot = (void *) CONST_CAST (struct attribute_spec *, attr);
+}
+
 /* Return the spec for the attribute named NAME.  */
 
 const struct attribute_spec *
-lookup_attribute_spec (tree name)
+lookup_attribute_spec (const_tree name)
 {
   struct substring attr;
 
@@ -232,6 +249,55 @@ decl_attributes (tree *node, tree attributes, int flags)
   if (!attributes_initialized)
     init_attributes ();
 
+  /* If this is a function and the user used #pragma GCC optimize, add the
+     options to the attribute((optimize(...))) list.  */
+  if (TREE_CODE (*node) == FUNCTION_DECL && current_optimize_pragma)
+    {
+      tree cur_attr = lookup_attribute ("optimize", attributes);
+      tree opts = copy_list (current_optimize_pragma);
+
+      if (! cur_attr)
+       attributes
+         = tree_cons (get_identifier ("optimize"), opts, attributes);
+      else
+       TREE_VALUE (cur_attr) = chainon (opts, TREE_VALUE (cur_attr));
+    }
+
+  if (TREE_CODE (*node) == FUNCTION_DECL
+      && optimization_current_node != optimization_default_node
+      && !DECL_FUNCTION_SPECIFIC_OPTIMIZATION (*node))
+    DECL_FUNCTION_SPECIFIC_OPTIMIZATION (*node) = optimization_current_node;
+
+  /* If this is a function and the user used #pragma GCC target, add the
+     options to the attribute((target(...))) list.  */
+  if (TREE_CODE (*node) == FUNCTION_DECL
+      && current_target_pragma
+      && targetm.target_option.valid_attribute_p (*node, NULL_TREE,
+                                                 current_target_pragma, 0))
+    {
+      tree cur_attr = lookup_attribute ("target", attributes);
+      tree opts = copy_list (current_target_pragma);
+
+      if (! cur_attr)
+       attributes = tree_cons (get_identifier ("target"), opts, attributes);
+      else
+       TREE_VALUE (cur_attr) = chainon (opts, TREE_VALUE (cur_attr));
+    }
+
+  /* A "naked" function attribute implies "noinline" and "noclone" for
+     those targets that support it.  */
+  if (TREE_CODE (*node) == FUNCTION_DECL
+      && attributes
+      && lookup_attribute_spec (get_identifier ("naked"))
+      && lookup_attribute ("naked", attributes) != NULL)
+    {
+      if (lookup_attribute ("noinline", attributes) == NULL)
+       attributes = tree_cons (get_identifier ("noinline"), NULL, attributes);
+
+      if (lookup_attribute ("noclone", attributes) == NULL)
+       attributes = tree_cons (get_identifier ("noclone"),  NULL, attributes);
+    }
+
   targetm.insert_attributes (*node, &attributes);
 
   for (a = attributes; a; a = TREE_CHAIN (a))
@@ -241,20 +307,21 @@ decl_attributes (tree *node, tree attributes, int flags)
       tree *anode = node;
       const struct attribute_spec *spec = lookup_attribute_spec (name);
       bool no_add_attrs = 0;
+      int fn_ptr_quals = 0;
       tree fn_ptr_tmp = NULL_TREE;
 
       if (spec == NULL)
        {
-         warning (OPT_Wattributes, "%qs attribute directive ignored",
-                  IDENTIFIER_POINTER (name));
+         warning (OPT_Wattributes, "%qE attribute directive ignored",
+                  name);
          continue;
        }
       else if (list_length (args) < spec->min_length
               || (spec->max_length >= 0
                   && list_length (args) > spec->max_length))
        {
-         error ("wrong number of arguments specified for %qs attribute",
-                IDENTIFIER_POINTER (name));
+         error ("wrong number of arguments specified for %qE attribute",
+                name);
          continue;
        }
       gcc_assert (is_attribute_p (spec->name, name));
@@ -271,8 +338,8 @@ decl_attributes (tree *node, tree attributes, int flags)
            }
          else
            {
-             warning (OPT_Wattributes, "%qs attribute does not apply to types",
-                      IDENTIFIER_POINTER (name));
+             warning (OPT_Wattributes, "%qE attribute does not apply to types",
+                      name);
              continue;
            }
        }
@@ -308,6 +375,7 @@ decl_attributes (tree *node, tree attributes, int flags)
                 This would all be simpler if attributes were part of the
                 declarator, grumble grumble.  */
              fn_ptr_tmp = TREE_TYPE (*anode);
+             fn_ptr_quals = TYPE_QUALS (*anode);
              anode = &fn_ptr_tmp;
              flags &= ~(int) ATTR_FLAG_TYPE_IN_PLACE;
            }
@@ -322,8 +390,8 @@ decl_attributes (tree *node, tree attributes, int flags)
              && TREE_CODE (*anode) != METHOD_TYPE)
            {
              warning (OPT_Wattributes,
-                      "%qs attribute only applies to function types",
-                      IDENTIFIER_POINTER (name));
+                      "%qE attribute only applies to function types",
+                      name);
              continue;
            }
        }
@@ -404,6 +472,8 @@ decl_attributes (tree *node, tree attributes, int flags)
          /* Rebuild the function pointer type and put it in the
             appropriate place.  */
          fn_ptr_tmp = build_pointer_type (fn_ptr_tmp);
+         if (fn_ptr_quals)
+           fn_ptr_tmp = build_qualified_type (fn_ptr_tmp, fn_ptr_quals);
          if (DECL_P (*node))
            TREE_TYPE (*node) = fn_ptr_tmp;
          else
@@ -416,3 +486,12 @@ decl_attributes (tree *node, tree attributes, int flags)
 
   return returned_attrs;
 }
+
+/* Subroutine of set_method_tm_attributes.  Apply TM attribute ATTR
+   to the method FNDECL.  */
+
+void
+apply_tm_attr (tree fndecl, tree attr)
+{
+  decl_attributes (&TREE_TYPE (fndecl), tree_cons (attr, NULL, NULL), 0);
+}