aboutsummaryrefslogtreecommitdiff
path: root/gcc/attribs.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/attribs.c')
-rw-r--r--gcc/attribs.c229
1 files changed, 207 insertions, 22 deletions
diff --git a/gcc/attribs.c b/gcc/attribs.c
index d3af414..b330f27 100644
--- a/gcc/attribs.c
+++ b/gcc/attribs.c
@@ -38,9 +38,6 @@ along with GCC; see the file COPYING3. If not see
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
@@ -49,6 +46,28 @@ struct substring
int length;
};
+DEF_VEC_O (attribute_spec);
+DEF_VEC_ALLOC_O (attribute_spec, heap);
+
+/* Scoped attribute name representation. */
+
+struct scoped_attributes
+{
+ const char *ns;
+ VEC (attribute_spec, heap) *attributes;
+ htab_t attribute_hash;
+};
+
+DEF_VEC_O (scoped_attributes);
+DEF_VEC_ALLOC_O (scoped_attributes, heap);
+
+/* The table of scope attributes. */
+static VEC(scoped_attributes, heap) *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. */
@@ -102,6 +121,64 @@ eq_attr (const void *p, const void *q)
return (!strncmp (spec->name, str->str, str->length) && !spec->name[str->length]);
}
+/* 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 == NULL)
+ attributes_table = VEC_alloc (scoped_attributes, heap, 64);
+
+ memset (&sa, 0, sizeof (sa));
+ sa.ns = ns;
+ sa.attributes = VEC_alloc (attribute_spec, heap, 64);
+ result = VEC_safe_push (scoped_attributes, heap, attributes_table, sa);
+ }
+
+ /* Really add the attributes to their namespace now. */
+ for (unsigned i = 0; attributes[i].name != NULL; ++i)
+ {
+ VEC_safe_push (attribute_spec, heap,
+ result->attributes, 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 (scoped_attributes, 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. */
@@ -109,7 +186,6 @@ void
init_attributes (void)
{
size_t i;
- int k;
if (attributes_initialized)
return;
@@ -181,12 +257,10 @@ 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++)
- {
- register_attribute (&attribute_tables[i][k]);
- }
+ 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;
}
@@ -196,9 +270,23 @@ init_attributes (void)
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;
void **slot;
+ gcc_assert (attr != NULL && name_space != NULL);
+
+ if (name_space->attribute_hash == NULL)
+ name_space->attribute_hash = htab_create (200, hash_attr, eq_attr, NULL);
+
str.str = attr->name;
str.length = strlen (str.str);
@@ -206,27 +294,45 @@ register_attribute (const struct attribute_spec *attr)
in the form '__text__'. */
gcc_assert (str.length > 0 && str.str[0] != '_');
- slot = htab_find_slot_with_hash (attribute_hash, &str,
+ slot = htab_find_slot_with_hash (name_space->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. */
+/* Return the spec for the scoped attribute with namespace NS and
+ name NAME. */
const struct attribute_spec *
-lookup_attribute_spec (const_tree name)
+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 (const struct attribute_spec *)
- htab_find_with_hash (attribute_hash, &attr,
+ htab_find_with_hash (attrs->attribute_hash, &attr,
substring_hash (attr.str, attr.length));
}
+
+/* Return the spec for the attribute named NAME. */
+
+const struct attribute_spec *
+lookup_attribute_spec (const_tree name)
+{
+ return lookup_scoped_attribute_spec (get_identifier ("gnu"), name);
+}
+
/* 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,
@@ -243,7 +349,7 @@ decl_attributes (tree *node, tree attributes, int flags)
tree a;
tree returned_attrs = NULL_TREE;
- if (TREE_TYPE (*node) == error_mark_node)
+ if (TREE_TYPE (*node) == error_mark_node || attributes == error_mark_node)
return NULL_TREE;
if (!attributes_initialized)
@@ -302,10 +408,12 @@ decl_attributes (tree *node, tree attributes, int flags)
for (a = attributes; a; a = TREE_CHAIN (a))
{
- tree name = TREE_PURPOSE (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_attribute_spec (name);
+ 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;
@@ -313,8 +421,15 @@ decl_attributes (tree *node, tree attributes, int flags)
if (spec == NULL)
{
if (!(flags & (int) ATTR_FLAG_BUILT_IN))
- warning (OPT_Wattributes, "%qE attribute directive ignored",
- name);
+ {
+ 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
@@ -327,6 +442,20 @@ decl_attributes (tree *node, tree attributes, int flags)
}
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
@@ -406,9 +535,15 @@ decl_attributes (tree *node, tree attributes, int flags)
}
if (spec->handler != NULL)
- returned_attrs = chainon ((*spec->handler) (anode, name, args,
- flags, &no_add_attrs),
- returned_attrs);
+ {
+ 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)
@@ -488,6 +623,56 @@ decl_attributes (tree *node, tree attributes, int flags)
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);
+}
+
+/* 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. */
+
+tree
+get_attribute_namespace (const_tree attr)
+{
+ if (cxx11_attribute_p (attr))
+ return TREE_PURPOSE (TREE_PURPOSE (attr));
+ return get_identifier ("gnu");
+}
+
/* Subroutine of set_method_tm_attributes. Apply TM attribute ATTR
to the method FNDECL. */