OSDN Git Service

* varasm.c: Do not include c-pragma.h
[pf3gnuchains/gcc-fork.git] / gcc / attribs.c
index fd11a96..a020f46 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,
-   2002, 2003, 2004 Free Software Foundation, Inc.
+   2002, 2003, 2004, 2005, 2007, 2008 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
-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
@@ -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
-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"
@@ -33,6 +32,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #include "cpplib.h"
 #include "target.h"
 #include "langhooks.h"
+#include "hashtab.h"
 
 static void init_attributes (void);
 
@@ -40,14 +40,70 @@ static void init_attributes (void);
    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 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.  */
 
@@ -55,6 +111,7 @@ static void
 init_attributes (void)
 {
   size_t i;
+  int k;
 
   attribute_tables[0] = lang_hooks.common_attribute_table;
   attribute_tables[1] = lang_hooks.attribute_table;
@@ -77,21 +134,21 @@ init_attributes (void)
          /* 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] == '_'));
-         
+
          /* 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));
-         
+
          /* 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
@@ -121,8 +178,38 @@ init_attributes (void)
     }
 #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++)
+      {
+       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];
+      }
   attributes_initialized = true;
 }
+
+/* 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,
@@ -139,9 +226,47 @@ decl_attributes (tree *node, tree attributes, int flags)
   tree a;
   tree returned_attrs = NULL_TREE;
 
+  if (TREE_TYPE (*node) == error_mark_node)
+    return NULL_TREE;
+
   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))
@@ -149,30 +274,13 @@ decl_attributes (tree *node, tree attributes, int flags)
       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;
-      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)
        {
-         warning ("%qs attribute directive ignored",
+         warning (OPT_Wattributes, "%qs attribute directive ignored",
                   IDENTIFIER_POINTER (name));
          continue;
        }
@@ -184,6 +292,7 @@ decl_attributes (tree *node, tree attributes, int flags)
                 IDENTIFIER_POINTER (name));
          continue;
        }
+      gcc_assert (is_attribute_p (spec->name, name));
 
       if (spec->decl_required && !DECL_P (*anode))
        {
@@ -197,7 +306,7 @@ decl_attributes (tree *node, tree attributes, int flags)
            }
          else
            {
-             warning ("%qs attribute does not apply to types",
+             warning (OPT_Wattributes, "%qs attribute does not apply to types",
                       IDENTIFIER_POINTER (name));
              continue;
            }
@@ -210,7 +319,11 @@ decl_attributes (tree *node, tree attributes, int flags)
       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
@@ -227,8 +340,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.
 
-                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;
@@ -243,12 +356,21 @@ decl_attributes (tree *node, tree attributes, int flags)
          if (TREE_CODE (*anode) != FUNCTION_TYPE
              && TREE_CODE (*anode) != METHOD_TYPE)
            {
-             warning ("%qs attribute only applies to function types",
+             warning (OPT_Wattributes,
+                      "%qs attribute only applies to function types",
                       IDENTIFIER_POINTER (name));
              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),