aboutsummaryrefslogtreecommitdiffstats
path: root/gcc-4.9/gcc/attribs.c
diff options
context:
space:
mode:
authorBen Cheng <bccheng@google.com>2014-03-25 22:37:19 -0700
committerBen Cheng <bccheng@google.com>2014-03-25 22:37:19 -0700
commit1bc5aee63eb72b341f506ad058502cd0361f0d10 (patch)
treec607e8252f3405424ff15bc2d00aa38dadbb2518 /gcc-4.9/gcc/attribs.c
parent283a0bf58fcf333c58a2a92c3ebbc41fb9eb1fdb (diff)
downloadtoolchain_gcc-1bc5aee63eb72b341f506ad058502cd0361f0d10.tar.gz
toolchain_gcc-1bc5aee63eb72b341f506ad058502cd0361f0d10.tar.bz2
toolchain_gcc-1bc5aee63eb72b341f506ad058502cd0361f0d10.zip
Initial checkin of GCC 4.9.0 from trunk (r208799).
Change-Id: I48a3c08bb98542aa215912a75f03c0890e497dba
Diffstat (limited to 'gcc-4.9/gcc/attribs.c')
-rw-r--r--gcc-4.9/gcc/attribs.c688
1 files changed, 688 insertions, 0 deletions
diff --git a/gcc-4.9/gcc/attribs.c b/gcc-4.9/gcc/attribs.c
new file mode 100644
index 000000000..54373eb52
--- /dev/null
+++ b/gcc-4.9/gcc/attribs.c
@@ -0,0 +1,688 @@
+/* Functions dealing with attribute handling, used by most front ends.
+ Copyright (C) 1992-2014 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 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+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 COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "tree.h"
+#include "stringpool.h"
+#include "attribs.h"
+#include "stor-layout.h"
+#include "flags.h"
+#include "diagnostic-core.h"
+#include "ggc.h"
+#include "tm_p.h"
+#include "cpplib.h"
+#include "target.h"
+#include "langhooks.h"
+#include "hash-table.h"
+#include "plugin.h"
+
+/* Table of the tables of attributes (common, language, format, machine)
+ searched. */
+static const struct attribute_spec *attribute_tables[4];
+
+/* Substring representation. */
+
+struct substring
+{
+ const char *str;
+ int length;
+};
+
+/* 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. */
+
+struct attribute_hasher : typed_noop_remove <attribute_spec>
+{
+ typedef attribute_spec value_type;
+ typedef substring compare_type;
+ static inline hashval_t hash (const value_type *);
+ static inline bool equal (const value_type *, const compare_type *);
+};
+
+inline hashval_t
+attribute_hasher::hash (const value_type *spec)
+{
+ const int l = strlen (spec->name);
+ return substring_hash (spec->name, l);
+}
+
+inline bool
+attribute_hasher::equal (const value_type *spec, const compare_type *str)
+{
+ return (strncmp (spec->name, str->str, str->length) == 0
+ && !spec->name[str->length]);
+}
+
+/* Scoped attribute name representation. */
+
+struct scoped_attributes
+{
+ const char *ns;
+ vec<attribute_spec> attributes;
+ hash_table <attribute_hasher> attribute_hash;
+};
+
+/* The table of scope attributes. */
+static vec<scoped_attributes> attributes_table;
+
+static scoped_attributes* find_attribute_namespace (const char*);
+static void register_scoped_attribute (const struct attribute_spec *,
+ scoped_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, false }
+};
+
+/* 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;
+ }
+}
+
+/* Insert an array of attributes ATTRIBUTES into a namespace. This
+ array must be NULL terminated. NS is the name of attribute
+ namespace. The function returns the namespace into which the
+ attributes have been registered. */
+
+scoped_attributes*
+register_scoped_attributes (const struct attribute_spec * attributes,
+ const char* ns)
+{
+ scoped_attributes *result = NULL;
+
+ /* See if we already have attributes in the namespace NS. */
+ result = find_attribute_namespace (ns);
+
+ if (result == NULL)
+ {
+ /* We don't have any namespace NS yet. Create one. */
+ scoped_attributes sa;
+
+ if (!attributes_table.is_empty ())
+ attributes_table.create (64);
+
+ memset (&sa, 0, sizeof (sa));
+ sa.ns = ns;
+ sa.attributes.create (64);
+ result = attributes_table.safe_push (sa);
+ result->attribute_hash.create (200);
+ }
+
+ /* Really add the attributes to their namespace now. */
+ for (unsigned i = 0; attributes[i].name != NULL; ++i)
+ {
+ result->attributes.safe_push (attributes[i]);
+ register_scoped_attribute (&attributes[i], result);
+ }
+
+ gcc_assert (result != NULL);
+
+ return result;
+}
+
+/* Return the namespace which name is NS, NULL if none exist. */
+
+static scoped_attributes*
+find_attribute_namespace (const char* ns)
+{
+ unsigned ix;
+ scoped_attributes *iter;
+
+ FOR_EACH_VEC_ELT (attributes_table, ix, iter)
+ if (ns == iter->ns
+ || (iter->ns != NULL
+ && ns != NULL
+ && !strcmp (iter->ns, ns)))
+ return iter;
+ return NULL;
+}
+
+/* Initialize attribute tables, and make some sanity checks
+ if --enable-checking. */
+
+void
+init_attributes (void)
+{
+ size_t i;
+
+ 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;
+ attribute_tables[3] = targetm.attribute_table;
+
+ /* Translate NULL pointers to pointers to the empty table. */
+ for (i = 0; i < ARRAY_SIZE (attribute_tables); i++)
+ if (attribute_tables[i] == NULL)
+ attribute_tables[i] = empty_attribute_table;
+
+#ifdef ENABLE_CHECKING
+ /* Make some sanity checks on the attribute tables. */
+ for (i = 0; i < ARRAY_SIZE (attribute_tables); i++)
+ {
+ int j;
+
+ for (j = 0; attribute_tables[i][j].name != NULL; j++)
+ {
+ /* 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
+ || attribute_tables[i][j].type_required);
+ }
+ }
+
+ /* Check that each name occurs just once in each table. */
+ for (i = 0; i < ARRAY_SIZE (attribute_tables); i++)
+ {
+ int j, k;
+ for (j = 0; attribute_tables[i][j].name != NULL; j++)
+ for (k = j + 1; attribute_tables[i][k].name != NULL; k++)
+ gcc_assert (strcmp (attribute_tables[i][j].name,
+ attribute_tables[i][k].name));
+ }
+ /* 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 (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)
+ /* Put all the GNU attributes into the "gnu" namespace. */
+ register_scoped_attributes (attribute_tables[i], "gnu");
+
+ 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)
+{
+ register_scoped_attribute (attr, find_attribute_namespace ("gnu"));
+}
+
+/* Insert a single attribute ATTR into a namespace of attributes. */
+
+static void
+register_scoped_attribute (const struct attribute_spec *attr,
+ scoped_attributes *name_space)
+{
+ struct substring str;
+ attribute_spec **slot;
+
+ gcc_assert (attr != NULL && name_space != NULL);
+
+ gcc_assert (name_space->attribute_hash.is_created ());
+
+ 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 = name_space->attribute_hash
+ .find_slot_with_hash (&str, substring_hash (str.str, str.length),
+ INSERT);
+ gcc_assert (!*slot || attr->name[0] == '*');
+ *slot = CONST_CAST (struct attribute_spec *, attr);
+}
+
+/* Return the spec for the scoped attribute with namespace NS and
+ name NAME. */
+
+static const struct attribute_spec *
+lookup_scoped_attribute_spec (const_tree ns, const_tree name)
+{
+ struct substring attr;
+ scoped_attributes *attrs;
+
+ const char *ns_str = (ns != NULL_TREE) ? IDENTIFIER_POINTER (ns): NULL;
+
+ attrs = find_attribute_namespace (ns_str);
+
+ if (attrs == NULL)
+ return NULL;
+
+ attr.str = IDENTIFIER_POINTER (name);
+ attr.length = IDENTIFIER_LENGTH (name);
+ extract_attribute_substring (&attr);
+ return attrs->attribute_hash.find_with_hash (&attr,
+ substring_hash (attr.str, attr.length));
+}
+
+/* Return the spec for the attribute named NAME. If NAME is a TREE_LIST,
+ it also specifies the attribute namespace. */
+
+const struct attribute_spec *
+lookup_attribute_spec (const_tree name)
+{
+ tree ns;
+ if (TREE_CODE (name) == TREE_LIST)
+ {
+ ns = TREE_PURPOSE (name);
+ name = TREE_VALUE (name);
+ }
+ else
+ ns = get_identifier ("gnu");
+ return lookup_scoped_attribute_spec (ns, name);
+}
+
+
+/* Return the namespace of the attribute ATTR. This accessor works on
+ GNU and C++11 (scoped) attributes. On GNU attributes,
+ it returns an identifier tree for the string "gnu".
+
+ Please read the comments of cxx11_attribute_p to understand the
+ format of attributes. */
+
+static tree
+get_attribute_namespace (const_tree attr)
+{
+ if (cxx11_attribute_p (attr))
+ return TREE_PURPOSE (TREE_PURPOSE (attr));
+ return get_identifier ("gnu");
+}
+
+
+/* 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,
+ it should be modified in place; if a TYPE, a copy should be created
+ unless ATTR_FLAG_TYPE_IN_PLACE is set in FLAGS. FLAGS gives further
+ information, in the form of a bitwise OR of flags in enum attribute_flags
+ from tree.h. Depending on these flags, some attributes may be
+ returned to be applied at a later stage (for example, to apply
+ a decl attribute to the declaration rather than to its type). */
+
+tree
+decl_attributes (tree *node, tree attributes, int flags)
+{
+ tree a;
+ tree returned_attrs = NULL_TREE;
+
+ if (TREE_TYPE (*node) == error_mark_node || attributes == 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));
+ }
+
+ /* 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 ns = get_attribute_namespace (a);
+ tree name = get_attribute_name (a);
+ tree args = TREE_VALUE (a);
+ tree *anode = node;
+ const struct attribute_spec *spec =
+ lookup_scoped_attribute_spec (ns, name);
+ bool no_add_attrs = 0;
+ int fn_ptr_quals = 0;
+ tree fn_ptr_tmp = NULL_TREE;
+
+ if (spec == NULL)
+ {
+ if (!(flags & (int) ATTR_FLAG_BUILT_IN))
+ {
+ if (ns == NULL_TREE || !cxx11_attribute_p (a))
+ warning (OPT_Wattributes, "%qE attribute directive ignored",
+ name);
+ else
+ warning (OPT_Wattributes,
+ "%<%E::%E%> scoped attribute directive ignored",
+ ns, 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 %qE attribute",
+ name);
+ continue;
+ }
+ gcc_assert (is_attribute_p (spec->name, name));
+
+ if (TYPE_P (*node)
+ && cxx11_attribute_p (a)
+ && !(flags & ATTR_FLAG_TYPE_IN_PLACE))
+ {
+ /* This is a c++11 attribute that appertains to a
+ type-specifier, outside of the definition of, a class
+ type. Ignore it. */
+ warning (OPT_Wattributes, "attribute ignored");
+ inform (input_location,
+ "an attribute that appertains to a type-specifier "
+ "is ignored");
+ continue;
+ }
+
+ if (spec->decl_required && !DECL_P (*anode))
+ {
+ if (flags & ((int) ATTR_FLAG_DECL_NEXT
+ | (int) ATTR_FLAG_FUNCTION_NEXT
+ | (int) ATTR_FLAG_ARRAY_NEXT))
+ {
+ /* Pass on this attribute to be tried again. */
+ returned_attrs = tree_cons (name, args, returned_attrs);
+ continue;
+ }
+ else
+ {
+ warning (OPT_Wattributes, "%qE attribute does not apply to types",
+ name);
+ continue;
+ }
+ }
+
+ /* If we require a type, but were passed a decl, set up to make a
+ new type and update the one in the decl. ATTR_FLAG_TYPE_IN_PLACE
+ would have applied if we'd been passed a type, but we cannot modify
+ the decl's type in place here. */
+ if (spec->type_required && DECL_P (*anode))
+ {
+ anode = &TREE_TYPE (*anode);
+ /* 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
+ && TREE_CODE (*anode) != METHOD_TYPE)
+ {
+ if (TREE_CODE (*anode) == POINTER_TYPE
+ && (TREE_CODE (TREE_TYPE (*anode)) == FUNCTION_TYPE
+ || TREE_CODE (TREE_TYPE (*anode)) == METHOD_TYPE))
+ {
+ /* OK, this is a bit convoluted. We can't just make a copy
+ of the pointer type and modify its TREE_TYPE, because if
+ we change the attributes of the target type the pointer
+ type needs to have a different TYPE_MAIN_VARIANT. So we
+ 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. */
+ fn_ptr_tmp = TREE_TYPE (*anode);
+ fn_ptr_quals = TYPE_QUALS (*anode);
+ anode = &fn_ptr_tmp;
+ flags &= ~(int) ATTR_FLAG_TYPE_IN_PLACE;
+ }
+ else if (flags & (int) ATTR_FLAG_FUNCTION_NEXT)
+ {
+ /* Pass on this attribute to be tried again. */
+ returned_attrs = tree_cons (name, args, returned_attrs);
+ continue;
+ }
+
+ if (TREE_CODE (*anode) != FUNCTION_TYPE
+ && TREE_CODE (*anode) != METHOD_TYPE)
+ {
+ warning (OPT_Wattributes,
+ "%qE attribute only applies to function types",
+ 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)
+ {
+ int cxx11_flag =
+ cxx11_attribute_p (a) ? ATTR_FLAG_CXX11 : 0;
+
+ returned_attrs = chainon ((*spec->handler) (anode, name, args,
+ flags|cxx11_flag,
+ &no_add_attrs),
+ returned_attrs);
+ }
+
+ /* Layout the decl in case anything changed. */
+ if (spec->type_required && DECL_P (*node)
+ && (TREE_CODE (*node) == VAR_DECL
+ || TREE_CODE (*node) == PARM_DECL
+ || TREE_CODE (*node) == RESULT_DECL))
+ relayout_decl (*node);
+
+ if (!no_add_attrs)
+ {
+ tree old_attrs;
+ tree a;
+
+ if (DECL_P (*anode))
+ old_attrs = DECL_ATTRIBUTES (*anode);
+ else
+ old_attrs = TYPE_ATTRIBUTES (*anode);
+
+ for (a = lookup_attribute (spec->name, old_attrs);
+ a != NULL_TREE;
+ a = lookup_attribute (spec->name, TREE_CHAIN (a)))
+ {
+ if (simple_cst_equal (TREE_VALUE (a), args) == 1)
+ break;
+ }
+
+ if (a == NULL_TREE)
+ {
+ /* This attribute isn't already in the list. */
+ if (DECL_P (*anode))
+ DECL_ATTRIBUTES (*anode) = tree_cons (name, args, old_attrs);
+ else if (flags & (int) ATTR_FLAG_TYPE_IN_PLACE)
+ {
+ TYPE_ATTRIBUTES (*anode) = tree_cons (name, args, old_attrs);
+ /* If this is the main variant, also push the attributes
+ out to the other variants. */
+ if (*anode == TYPE_MAIN_VARIANT (*anode))
+ {
+ tree variant;
+ for (variant = *anode; variant;
+ variant = TYPE_NEXT_VARIANT (variant))
+ {
+ if (TYPE_ATTRIBUTES (variant) == old_attrs)
+ TYPE_ATTRIBUTES (variant)
+ = TYPE_ATTRIBUTES (*anode);
+ else if (!lookup_attribute
+ (spec->name, TYPE_ATTRIBUTES (variant)))
+ TYPE_ATTRIBUTES (variant) = tree_cons
+ (name, args, TYPE_ATTRIBUTES (variant));
+ }
+ }
+ }
+ else
+ *anode = build_type_attribute_variant (*anode,
+ tree_cons (name, args,
+ old_attrs));
+ }
+ }
+
+ if (fn_ptr_tmp)
+ {
+ /* 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
+ {
+ gcc_assert (TREE_CODE (*node) == POINTER_TYPE);
+ *node = fn_ptr_tmp;
+ }
+ }
+ }
+
+ return returned_attrs;
+}
+
+/* Return TRUE iff ATTR has been parsed by the front-end as a C++-11
+ attribute.
+
+ When G++ parses a C++11 attribute, it is represented as
+ a TREE_LIST which TREE_PURPOSE is itself a TREE_LIST. TREE_PURPOSE
+ (TREE_PURPOSE (ATTR)) is the namespace of the attribute, and the
+ TREE_VALUE (TREE_PURPOSE (ATTR)) is its non-qualified name. Please
+ use get_attribute_namespace and get_attribute_name to retrieve the
+ namespace and name of the attribute, as these accessors work with
+ GNU attributes as well. */
+
+bool
+cxx11_attribute_p (const_tree attr)
+{
+ if (attr == NULL_TREE
+ || TREE_CODE (attr) != TREE_LIST)
+ return false;
+
+ return (TREE_CODE (TREE_PURPOSE (attr)) == TREE_LIST);
+}
+
+/* Return the name of the attribute ATTR. This accessor works on GNU
+ and C++11 (scoped) attributes.
+
+ Please read the comments of cxx11_attribute_p to understand the
+ format of attributes. */
+
+tree
+get_attribute_name (const_tree attr)
+{
+ if (cxx11_attribute_p (attr))
+ return TREE_VALUE (TREE_PURPOSE (attr));
+ return TREE_PURPOSE (attr);
+}
+
+/* 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);
+}