/* 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.
#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. */
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'.
/* 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;
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;
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
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;
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))
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));
}
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;
}
}
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;
}
&& 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;
}
}
/* 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
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);
+}