OSDN Git Service

2009-08-28 Jan Beulich <jbeulich@novell.com>
[pf3gnuchains/gcc-fork.git] / gcc / attribs.c
index 8174f39..5ae462e 100644 (file)
@@ -1,12 +1,12 @@
 /* Functions dealing with attribute handling, used by most front ends.
    Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
 /* 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 Free Software Foundation, Inc.
+   2002, 2003, 2004, 2005, 2007, 2008, 2009 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
 GCC is free software; you can redistribute it and/or modify it under
 the terms of the GNU General Public License as published by the Free
 
 This file is part of GCC.
 
 GCC is free software; you can redistribute it and/or modify it under
 the terms of the GNU General Public License as published by the Free
-Software Foundation; either version 2, or (at your option) any later
+Software Foundation; either version 3, or (at your option) any later
 version.
 
 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
 version.
 
 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
@@ -15,9 +15,8 @@ FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 for more details.
 
 You should have received a copy of the GNU General Public License
 for more details.
 
 You should have received a copy of the GNU General Public License
-along with GCC; see the file COPYING.  If not, write to the Free
-Software Foundation, 59 Temple Place - Suite 330, Boston, MA
-02111-1307, USA.  */
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
 
 #include "config.h"
 #include "system.h"
 
 #include "config.h"
 #include "system.h"
@@ -33,6 +32,8 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #include "cpplib.h"
 #include "target.h"
 #include "langhooks.h"
 #include "cpplib.h"
 #include "target.h"
 #include "langhooks.h"
+#include "hashtab.h"
+#include "plugin.h"
 
 static void init_attributes (void);
 
 
 static void init_attributes (void);
 
@@ -40,14 +41,70 @@ static void init_attributes (void);
    searched.  */
 static const struct attribute_spec *attribute_tables[4];
 
    searched.  */
 static const struct attribute_spec *attribute_tables[4];
 
+/* Hashtable mapping names (represented as substrings) to attribute specs. */
+static htab_t attribute_hash;
+
+/* Substring representation.  */
+
+struct substring
+{
+  const char *str;
+  int length;
+};
+
 static bool attributes_initialized = false;
 
 /* Default empty table of attributes.  */
 static bool attributes_initialized = false;
 
 /* Default empty table of attributes.  */
+
 static const struct attribute_spec empty_attribute_table[] =
 {
   { NULL, 0, 0, false, false, false, NULL }
 };
 
 static const struct attribute_spec empty_attribute_table[] =
 {
   { NULL, 0, 0, false, false, false, NULL }
 };
 
+/* Return base name of the attribute.  Ie '__attr__' is turned into 'attr'.
+   To avoid need for copying, we simply return length of the string.  */
+
+static void
+extract_attribute_substring (struct substring *str)
+{
+  if (str->length > 4 && str->str[0] == '_' && str->str[1] == '_'
+      && str->str[str->length - 1] == '_' && str->str[str->length - 2] == '_')
+    {
+      str->length -= 4;
+      str->str += 2;
+    }
+}
+
+/* Simple hash function to avoid need to scan whole string.  */
+
+static inline hashval_t
+substring_hash (const char *str, int l)
+{
+  return str[0] + str[l - 1] * 256 + l * 65536;
+}
+
+/* Used for attribute_hash.  */
+
+static hashval_t
+hash_attr (const void *p)
+{
+  const struct attribute_spec *const spec = (const struct attribute_spec *) p;
+  const int l = strlen (spec->name);
+
+  return substring_hash (spec->name, l);
+}
+
+/* Used for attribute_hash.  */
+
+static int
+eq_attr (const void *p, const void *q)
+{
+  const struct attribute_spec *const spec = (const struct attribute_spec *) p;
+  const struct substring *const str = (const struct substring *) q;
+
+  return (!strncmp (spec->name, str->str, str->length) && !spec->name[str->length]);
+}
+
 /* Initialize attribute tables, and make some sanity checks
    if --enable-checking.  */
 
 /* Initialize attribute tables, and make some sanity checks
    if --enable-checking.  */
 
@@ -55,6 +112,7 @@ static void
 init_attributes (void)
 {
   size_t i;
 init_attributes (void)
 {
   size_t i;
+  int k;
 
   attribute_tables[0] = lang_hooks.common_attribute_table;
   attribute_tables[1] = lang_hooks.attribute_table;
 
   attribute_tables[0] = lang_hooks.common_attribute_table;
   attribute_tables[1] = lang_hooks.attribute_table;
@@ -77,21 +135,21 @@ init_attributes (void)
          /* The name must not begin and end with __.  */
          const char *name = attribute_tables[i][j].name;
          int len = strlen (name);
          /* The name must not begin and end with __.  */
          const char *name = attribute_tables[i][j].name;
          int len = strlen (name);
-         
+
          gcc_assert (!(name[0] == '_' && name[1] == '_'
                        && name[len - 1] == '_' && name[len - 2] == '_'));
          gcc_assert (!(name[0] == '_' && name[1] == '_'
                        && name[len - 1] == '_' && name[len - 2] == '_'));
-         
+
          /* The minimum and maximum lengths must be consistent.  */
          gcc_assert (attribute_tables[i][j].min_length >= 0);
          /* The minimum and maximum lengths must be consistent.  */
          gcc_assert (attribute_tables[i][j].min_length >= 0);
-         
+
          gcc_assert (attribute_tables[i][j].max_length == -1
                      || (attribute_tables[i][j].max_length
                          >= attribute_tables[i][j].min_length));
          gcc_assert (attribute_tables[i][j].max_length == -1
                      || (attribute_tables[i][j].max_length
                          >= attribute_tables[i][j].min_length));
-         
+
          /* An attribute cannot require both a DECL and a TYPE.  */
          gcc_assert (!attribute_tables[i][j].decl_required
                      || !attribute_tables[i][j].type_required);
          /* An attribute cannot require both a DECL and a TYPE.  */
          gcc_assert (!attribute_tables[i][j].decl_required
                      || !attribute_tables[i][j].type_required);
-         
+
          /* If an attribute requires a function type, in particular
             it requires a type.  */
          gcc_assert (!attribute_tables[i][j].function_type_required
          /* If an attribute requires a function type, in particular
             it requires a type.  */
          gcc_assert (!attribute_tables[i][j].function_type_required
@@ -121,8 +179,47 @@ init_attributes (void)
     }
 #endif
 
     }
 #endif
 
+  attribute_hash = htab_create (200, hash_attr, eq_attr, NULL);
+  for (i = 0; i < ARRAY_SIZE (attribute_tables); i++)
+    for (k = 0; attribute_tables[i][k].name != NULL; k++)
+      {
+        register_attribute (&attribute_tables[i][k]);
+      }
+  invoke_plugin_callbacks (PLUGIN_ATTRIBUTES, NULL);
   attributes_initialized = true;
 }
   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);
+  slot = htab_find_slot_with_hash (attribute_hash, &str,
+                                  substring_hash (str.str, str.length),
+                                  INSERT);
+  gcc_assert (!*slot);
+  *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)
+{
+  struct substring attr;
+
+  attr.str = IDENTIFIER_POINTER (name);
+  attr.length = IDENTIFIER_LENGTH (name);
+  extract_attribute_substring (&attr);
+  return (const struct attribute_spec *)
+    htab_find_with_hash (attribute_hash, &attr,
+                        substring_hash (attr.str, attr.length));
+}
 \f
 /* Process the attributes listed in ATTRIBUTES and install them in *NODE,
    which is either a DECL (including a TYPE_DECL) or a TYPE.  If a DECL,
 \f
 /* Process the attributes listed in ATTRIBUTES and install them in *NODE,
    which is either a DECL (including a TYPE_DECL) or a TYPE.  If a DECL,
@@ -139,9 +236,47 @@ decl_attributes (tree *node, tree attributes, int flags)
   tree a;
   tree returned_attrs = NULL_TREE;
 
   tree a;
   tree returned_attrs = NULL_TREE;
 
+  if (TREE_TYPE (*node) == error_mark_node)
+    return NULL_TREE;
+
   if (!attributes_initialized)
     init_attributes ();
 
   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));
+    }
+
   targetm.insert_attributes (*node, &attributes);
 
   for (a = attributes; a; a = TREE_CHAIN (a))
   targetm.insert_attributes (*node, &attributes);
 
   for (a = attributes; a; a = TREE_CHAIN (a))
@@ -149,41 +284,25 @@ decl_attributes (tree *node, tree attributes, int flags)
       tree name = TREE_PURPOSE (a);
       tree args = TREE_VALUE (a);
       tree *anode = node;
       tree name = TREE_PURPOSE (a);
       tree args = TREE_VALUE (a);
       tree *anode = node;
-      const struct attribute_spec *spec = NULL;
+      const struct attribute_spec *spec = lookup_attribute_spec (name);
       bool no_add_attrs = 0;
       tree fn_ptr_tmp = NULL_TREE;
       bool no_add_attrs = 0;
       tree fn_ptr_tmp = NULL_TREE;
-      size_t i;
-
-      for (i = 0; i < ARRAY_SIZE (attribute_tables); i++)
-       {
-         int j;
-
-         for (j = 0; attribute_tables[i][j].name != NULL; j++)
-           {
-             if (is_attribute_p (attribute_tables[i][j].name, name))
-               {
-                 spec = &attribute_tables[i][j];
-                 break;
-               }
-           }
-         if (spec != NULL)
-           break;
-       }
 
       if (spec == NULL)
        {
 
       if (spec == NULL)
        {
-         warning ("`%s' 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))
        {
          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 `%s' attribute",
-                IDENTIFIER_POINTER (name));
+         error ("wrong number of arguments specified for %qE attribute",
+                name);
          continue;
        }
          continue;
        }
+      gcc_assert (is_attribute_p (spec->name, name));
 
       if (spec->decl_required && !DECL_P (*anode))
        {
 
       if (spec->decl_required && !DECL_P (*anode))
        {
@@ -197,8 +316,8 @@ decl_attributes (tree *node, tree attributes, int flags)
            }
          else
            {
            }
          else
            {
-             warning ("`%s' attribute does not apply to types",
-                      IDENTIFIER_POINTER (name));
+             warning (OPT_Wattributes, "%qE attribute does not apply to types",
+                      name);
              continue;
            }
        }
              continue;
            }
        }
@@ -210,7 +329,11 @@ decl_attributes (tree *node, tree attributes, int flags)
       if (spec->type_required && DECL_P (*anode))
        {
          anode = &TREE_TYPE (*anode);
       if (spec->type_required && DECL_P (*anode))
        {
          anode = &TREE_TYPE (*anode);
-         flags &= ~(int) ATTR_FLAG_TYPE_IN_PLACE;
+         /* Allow ATTR_FLAG_TYPE_IN_PLACE for the type's naming decl.  */
+         if (!(TREE_CODE (*anode) == TYPE_DECL
+               && *anode == TYPE_NAME (TYPE_MAIN_VARIANT
+                                       (TREE_TYPE (*anode)))))
+           flags &= ~(int) ATTR_FLAG_TYPE_IN_PLACE;
        }
 
       if (spec->function_type_required && TREE_CODE (*anode) != FUNCTION_TYPE
        }
 
       if (spec->function_type_required && TREE_CODE (*anode) != FUNCTION_TYPE
@@ -227,8 +350,8 @@ decl_attributes (tree *node, tree attributes, int flags)
                 pull out the target type now, frob it as appropriate, and
                 rebuild the pointer type later.
 
                 pull out the target type now, frob it as appropriate, and
                 rebuild the pointer type later.
 
-                This would all be simpler if attributes were part of the
-                declarator, grumble grumble.  */
+                This would all be simpler if attributes were part of the
+                declarator, grumble grumble.  */
              fn_ptr_tmp = TREE_TYPE (*anode);
              anode = &fn_ptr_tmp;
              flags &= ~(int) ATTR_FLAG_TYPE_IN_PLACE;
              fn_ptr_tmp = TREE_TYPE (*anode);
              anode = &fn_ptr_tmp;
              flags &= ~(int) ATTR_FLAG_TYPE_IN_PLACE;
@@ -243,12 +366,21 @@ decl_attributes (tree *node, tree attributes, int flags)
          if (TREE_CODE (*anode) != FUNCTION_TYPE
              && TREE_CODE (*anode) != METHOD_TYPE)
            {
          if (TREE_CODE (*anode) != FUNCTION_TYPE
              && TREE_CODE (*anode) != METHOD_TYPE)
            {
-             warning ("`%s' attribute only applies to function types",
-                      IDENTIFIER_POINTER (name));
+             warning (OPT_Wattributes,
+                      "%qE attribute only applies to function types",
+                      name);
              continue;
            }
        }
 
              continue;
            }
        }
 
+      if (TYPE_P (*anode)
+         && (flags & (int) ATTR_FLAG_TYPE_IN_PLACE)
+         && TYPE_SIZE (*anode) != NULL_TREE)
+       {
+         warning (OPT_Wattributes, "type attributes ignored after type is already defined");
+         continue;
+       }
+
       if (spec->handler != NULL)
        returned_attrs = chainon ((*spec->handler) (anode, name, args,
                                                    flags, &no_add_attrs),
       if (spec->handler != NULL)
        returned_attrs = chainon ((*spec->handler) (anode, name, args,
                                                    flags, &no_add_attrs),
@@ -259,13 +391,7 @@ decl_attributes (tree *node, tree attributes, int flags)
          && (TREE_CODE (*node) == VAR_DECL
              || TREE_CODE (*node) == PARM_DECL
              || TREE_CODE (*node) == RESULT_DECL))
          && (TREE_CODE (*node) == VAR_DECL
              || TREE_CODE (*node) == PARM_DECL
              || TREE_CODE (*node) == RESULT_DECL))
-       {
-         /* Force a recalculation of mode and size.  */
-         DECL_MODE (*node) = VOIDmode;
-         DECL_SIZE (*node) = 0;
-
-         layout_decl (*node, 0);
-       }
+       relayout_decl (*node);
 
       if (!no_add_attrs)
        {
 
       if (!no_add_attrs)
        {
@@ -335,105 +461,3 @@ decl_attributes (tree *node, tree attributes, int flags)
 
   return returned_attrs;
 }
 
   return returned_attrs;
 }
-
-/* Split SPECS_ATTRS, a list of declspecs and prefix attributes, into two
-   lists.  SPECS_ATTRS may also be just a typespec (eg: RECORD_TYPE).
-
-   The head of the declspec list is stored in DECLSPECS.
-   The head of the attribute list is stored in PREFIX_ATTRIBUTES.
-
-   Note that attributes in SPECS_ATTRS are stored in the TREE_PURPOSE of
-   the list elements.  We drop the containing TREE_LIST nodes and link the
-   resulting attributes together the way decl_attributes expects them.  */
-
-void
-split_specs_attrs (tree specs_attrs, tree *declspecs, tree *prefix_attributes)
-{
-  tree t, s, a, next, specs, attrs;
-
-  /* This can happen after an __extension__ in pedantic mode.  */
-  if (specs_attrs != NULL_TREE
-      && TREE_CODE (specs_attrs) == INTEGER_CST)
-    {
-      *declspecs = NULL_TREE;
-      *prefix_attributes = NULL_TREE;
-      return;
-    }
-
-  /* This can happen in c++ (eg: decl: typespec initdecls ';').  */
-  if (specs_attrs != NULL_TREE
-      && TREE_CODE (specs_attrs) != TREE_LIST)
-    {
-      *declspecs = specs_attrs;
-      *prefix_attributes = NULL_TREE;
-      return;
-    }
-
-  /* Remember to keep the lists in the same order, element-wise.  */
-
-  specs = s = NULL_TREE;
-  attrs = a = NULL_TREE;
-  for (t = specs_attrs; t; t = next)
-    {
-      next = TREE_CHAIN (t);
-      /* Declspecs have a non-NULL TREE_VALUE.  */
-      if (TREE_VALUE (t) != NULL_TREE)
-       {
-         if (specs == NULL_TREE)
-           specs = s = t;
-         else
-           {
-             TREE_CHAIN (s) = t;
-             s = t;
-           }
-       }
-      /* The TREE_PURPOSE may also be empty in the case of
-        __attribute__(()).  */
-      else if (TREE_PURPOSE (t) != NULL_TREE)
-       {
-         if (attrs == NULL_TREE)
-           attrs = a = TREE_PURPOSE (t);
-         else
-           {
-             TREE_CHAIN (a) = TREE_PURPOSE (t);
-             a = TREE_PURPOSE (t);
-           }
-         /* More attrs can be linked here, move A to the end.  */
-         while (TREE_CHAIN (a) != NULL_TREE)
-           a = TREE_CHAIN (a);
-       }
-    }
-
-  /* Terminate the lists.  */
-  if (s != NULL_TREE)
-    TREE_CHAIN (s) = NULL_TREE;
-  if (a != NULL_TREE)
-    TREE_CHAIN (a) = NULL_TREE;
-
-  /* All done.  */
-  *declspecs = specs;
-  *prefix_attributes = attrs;
-}
-
-/* Strip attributes from SPECS_ATTRS, a list of declspecs and attributes.
-   This function is used by the parser when a rule will accept attributes
-   in a particular position, but we don't want to support that just yet.
-
-   A warning is issued for every ignored attribute.  */
-
-tree
-strip_attrs (tree specs_attrs)
-{
-  tree specs, attrs;
-
-  split_specs_attrs (specs_attrs, &specs, &attrs);
-
-  while (attrs)
-    {
-      warning ("`%s' attribute ignored",
-              IDENTIFIER_POINTER (TREE_PURPOSE (attrs)));
-      attrs = TREE_CHAIN (attrs);
-    }
-
-  return specs;
-}