/* 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 Free Software Foundation, Inc.
This file is part of GCC.
#include "cpplib.h"
#include "target.h"
#include "langhooks.h"
+#include "hashtab.h"
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. */
init_attributes (void)
{
size_t i;
+ int k;
attribute_tables[0] = lang_hooks.common_attribute_table;
attribute_tables[1] = lang_hooks.attribute_table;
}
#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,
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))
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)
{
IDENTIFIER_POINTER (name));
continue;
}
+ gcc_assert (is_attribute_p (spec->name, name));
if (spec->decl_required && !DECL_P (*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