}
};
-/* Return nonzero if IDENT is a valid name for attribute ATTR,
- or zero if not.
-
- We try both `text' and `__text__', ATTR may be either one. */
-/* ??? It might be a reasonable simplification to require ATTR to be only
- `text'. One might then also require attribute lists to be stored in
- their canonicalized form. */
-
-static int
-is_attribute_with_length_p (const char *attr, int attr_len, const_tree ident)
+/* The backbone of is_attribute_p(). ATTR_LEN is the string length of
+ ATTR_NAME. Also used internally by remove_attribute(). */
+bool
+private_is_attribute_p (const char *attr_name, size_t attr_len, const_tree ident)
{
- int ident_len;
- const char *p;
+ size_t ident_len = IDENTIFIER_LENGTH (ident);
- if (TREE_CODE (ident) != IDENTIFIER_NODE)
- return 0;
-
- p = IDENTIFIER_POINTER (ident);
- ident_len = IDENTIFIER_LENGTH (ident);
-
- if (ident_len == attr_len
- && strcmp (attr, p) == 0)
- return 1;
-
- /* If ATTR is `__text__', IDENT must be `text'; and vice versa. */
- if (attr[0] == '_')
+ if (ident_len == attr_len)
{
- gcc_assert (attr[1] == '_');
- gcc_assert (attr[attr_len - 2] == '_');
- gcc_assert (attr[attr_len - 1] == '_');
- if (ident_len == attr_len - 4
- && strncmp (attr + 2, p, attr_len - 4) == 0)
- return 1;
+ if (strcmp (attr_name, IDENTIFIER_POINTER (ident)) == 0)
+ return true;
}
- else
+ else if (ident_len == attr_len + 4)
{
- if (ident_len == attr_len + 4
- && p[0] == '_' && p[1] == '_'
+ /* There is the possibility that ATTR is 'text' and IDENT is
+ '__text__'. */
+ const char *p = IDENTIFIER_POINTER (ident);
+ if (p[0] == '_' && p[1] == '_'
&& p[ident_len - 2] == '_' && p[ident_len - 1] == '_'
- && strncmp (attr, p + 2, attr_len) == 0)
- return 1;
+ && strncmp (attr_name, p + 2, attr_len) == 0)
+ return true;
}
- return 0;
+ return false;
}
-/* Return nonzero if IDENT is a valid name for attribute ATTR,
- or zero if not.
+/* The backbone of lookup_attribute(). ATTR_LEN is the string length
+ of ATTR_NAME, and LIST is not NULL_TREE. */
+tree
+private_lookup_attribute (const char *attr_name, size_t attr_len, tree list)
+{
+ while (list)
+ {
+ size_t ident_len = IDENTIFIER_LENGTH (TREE_PURPOSE (list));
- We try both `text' and `__text__', ATTR may be either one. */
+ if (ident_len == attr_len)
+ {
+ if (strcmp (attr_name, IDENTIFIER_POINTER (TREE_PURPOSE (list))) == 0)
+ break;
+ }
+ /* TODO: If we made sure that attributes were stored in the
+ canonical form without '__...__' (ie, as in 'text' as opposed
+ to '__text__') then we could avoid the following case. */
+ else if (ident_len == attr_len + 4)
+ {
+ const char *p = IDENTIFIER_POINTER (TREE_PURPOSE (list));
+ if (p[0] == '_' && p[1] == '_'
+ && p[ident_len - 2] == '_' && p[ident_len - 1] == '_'
+ && strncmp (attr_name, p + 2, attr_len) == 0)
+ break;
+ }
+ list = TREE_CHAIN (list);
+ }
-int
-is_attribute_p (const char *attr, const_tree ident)
-{
- return is_attribute_with_length_p (attr, strlen (attr), ident);
+ return list;
}
-/* Given an attribute name and a list of attributes, return a pointer to the
- attribute's list element if the attribute is part of the list, or NULL_TREE
- if not found. If the attribute appears more than once, this only
- returns the first occurrence; the TREE_CHAIN of the return value should
- be passed back in if further occurrences are wanted. */
+/* A variant of lookup_attribute() that can be used with an identifier
+ as the first argument, and where the identifier can be either
+ 'text' or '__text__'.
-tree
-lookup_attribute (const char *attr_name, tree list)
+ Given an attribute ATTR_IDENTIFIER, and a list of attributes LIST,
+ return a pointer to the attribute's list element if the attribute
+ is part of the list, or NULL_TREE if not found. If the attribute
+ appears more than once, this only returns the first occurrence; the
+ TREE_CHAIN of the return value should be passed back in if further
+ occurrences are wanted. ATTR_IDENTIFIER must be an identifier but
+ can be in the form 'text' or '__text__'. */
+static tree
+lookup_ident_attribute (tree attr_identifier, tree list)
{
- tree l;
- size_t attr_len = strlen (attr_name);
+ gcc_checking_assert (TREE_CODE (attr_identifier) == IDENTIFIER_NODE);
- for (l = list; l; l = TREE_CHAIN (l))
+ while (list)
{
- gcc_assert (TREE_CODE (TREE_PURPOSE (l)) == IDENTIFIER_NODE);
- if (is_attribute_with_length_p (attr_name, attr_len, TREE_PURPOSE (l)))
- return l;
+ gcc_checking_assert (TREE_CODE (TREE_PURPOSE (list)) == IDENTIFIER_NODE);
+
+ /* Identifiers can be compared directly for equality. */
+ if (attr_identifier == TREE_PURPOSE (list))
+ break;
+
+ /* If they are not equal, they may still be one in the form
+ 'text' while the other one is in the form '__text__'. TODO:
+ If we were storing attributes in normalized 'text' form, then
+ this could all go away and we could take full advantage of
+ the fact that we're comparing identifiers. :-) */
+ {
+ size_t attr_len = IDENTIFIER_LENGTH (attr_identifier);
+ size_t ident_len = IDENTIFIER_LENGTH (TREE_PURPOSE (list));
+
+ if (ident_len == attr_len + 4)
+ {
+ const char *p = IDENTIFIER_POINTER (TREE_PURPOSE (list));
+ const char *q = IDENTIFIER_POINTER (attr_identifier);
+ if (p[0] == '_' && p[1] == '_'
+ && p[ident_len - 2] == '_' && p[ident_len - 1] == '_'
+ && strncmp (q, p + 2, attr_len) == 0)
+ break;
+ }
+ else if (ident_len + 4 == attr_len)
+ {
+ const char *p = IDENTIFIER_POINTER (TREE_PURPOSE (list));
+ const char *q = IDENTIFIER_POINTER (attr_identifier);
+ if (q[0] == '_' && q[1] == '_'
+ && q[attr_len - 2] == '_' && q[attr_len - 1] == '_'
+ && strncmp (q + 2, p, ident_len) == 0)
+ break;
+ }
+ }
+ list = TREE_CHAIN (list);
}
- return NULL_TREE;
+
+ return list;
}
/* Remove any instances of attribute ATTR_NAME in LIST and return the
tree *p;
size_t attr_len = strlen (attr_name);
+ gcc_checking_assert (attr_name[0] != '_');
+
for (p = &list; *p; )
{
tree l = *p;
- gcc_assert (TREE_CODE (TREE_PURPOSE (l)) == IDENTIFIER_NODE);
- if (is_attribute_with_length_p (attr_name, attr_len, TREE_PURPOSE (l)))
+ /* TODO: If we were storing attributes in normalized form, here
+ we could use a simple strcmp(). */
+ if (private_is_attribute_p (attr_name, attr_len, TREE_PURPOSE (l)))
*p = TREE_CHAIN (l);
else
p = &TREE_CHAIN (l);
for (; a2 != 0; a2 = TREE_CHAIN (a2))
{
tree a;
- for (a = lookup_attribute (IDENTIFIER_POINTER (TREE_PURPOSE (a2)),
- attributes);
+ for (a = lookup_ident_attribute (TREE_PURPOSE (a2), attributes);
a != NULL_TREE && !attribute_value_equal (a, a2);
- a = lookup_attribute (IDENTIFIER_POINTER (TREE_PURPOSE (a2)),
- TREE_CHAIN (a)))
+ a = lookup_ident_attribute (TREE_PURPOSE (a2), TREE_CHAIN (a)))
;
if (a == NULL_TREE)
{
a = merge_attributes (DECL_ATTRIBUTES (old), DECL_ATTRIBUTES (new_tree));
if (delete_dllimport_p)
- {
- tree prev, t;
- const size_t attr_len = strlen ("dllimport");
-
- /* Scan the list for dllimport and delete it. */
- for (prev = NULL_TREE, t = a; t; prev = t, t = TREE_CHAIN (t))
- {
- if (is_attribute_with_length_p ("dllimport", attr_len,
- TREE_PURPOSE (t)))
- {
- if (prev == NULL_TREE)
- a = TREE_CHAIN (a);
- else
- TREE_CHAIN (prev) = TREE_CHAIN (t);
- break;
- }
- }
- }
+ a = remove_attribute ("dllimport", a);
return a;
}
int
attribute_list_equal (const_tree l1, const_tree l2)
{
+ if (l1 == l2)
+ return 1;
+
return attribute_list_contained (l1, l2)
&& attribute_list_contained (l2, l1);
}
/* This CONST_CAST is okay because lookup_attribute does not
modify its argument and the return value is assigned to a
const_tree. */
- for (attr = lookup_attribute (IDENTIFIER_POINTER (TREE_PURPOSE (t2)),
- CONST_CAST_TREE(l1));
+ for (attr = lookup_ident_attribute (TREE_PURPOSE (t2), CONST_CAST_TREE(l1));
attr != NULL_TREE && !attribute_value_equal (t2, attr);
- attr = lookup_attribute (IDENTIFIER_POINTER (TREE_PURPOSE (t2)),
- TREE_CHAIN (attr)))
+ attr = lookup_ident_attribute (TREE_PURPOSE (t2), TREE_CHAIN (attr)))
;
if (attr == NULL_TREE)
extern tree merge_decl_attributes (tree, tree);
extern tree merge_type_attributes (tree, tree);
-/* Given a tree node and a string, return nonzero if the tree node is
- a valid attribute name for the string. */
+/* This function is a private implementation detail of lookup_attribute()
+ and you should never call it directly. */
+extern tree private_lookup_attribute (const char *, size_t, tree);
+
+/* Given an attribute name ATTR_NAME and a list of attributes LIST,
+ return a pointer to the attribute's list element if the attribute
+ is part of the list, or NULL_TREE if not found. If the attribute
+ appears more than once, this only returns the first occurrence; the
+ TREE_CHAIN of the return value should be passed back in if further
+ occurrences are wanted. ATTR_NAME must be in the form 'text' (not
+ '__text__'). */
-extern int is_attribute_p (const char *, const_tree);
+static inline tree
+lookup_attribute (const char *attr_name, tree list)
+{
+ gcc_checking_assert (attr_name[0] != '_');
+ /* In most cases, list is NULL_TREE. */
+ if (list == NULL_TREE)
+ return NULL_TREE;
+ else
+ /* Do the strlen() before calling the out-of-line implementation.
+ In most cases attr_name is a string constant, and the compiler
+ will optimize the strlen() away. */
+ return private_lookup_attribute (attr_name, strlen (attr_name), list);
+}
-/* Given an attribute name and a list of attributes, return the list element
- of the attribute or NULL_TREE if not found. */
+/* This function is a private implementation detail of
+ is_attribute_p() and you should never call it directly. */
+extern bool private_is_attribute_p (const char *, size_t, const_tree);
-extern tree lookup_attribute (const char *, tree);
+/* Given an identifier node IDENT and a string ATTR_NAME, return true
+ if the identifier node is a valid attribute name for the string.
+ ATTR_NAME must be in the form 'text' (not '__text__'). IDENT could
+ be the identifier for 'text' or for '__text__'. */
+
+static inline bool
+is_attribute_p (const char *attr_name, const_tree ident)
+{
+ gcc_checking_assert (attr_name[0] != '_');
+ /* Do the strlen() before calling the out-of-line implementation.
+ In most cases attr_name is a string constant, and the compiler
+ will optimize the strlen() away. */
+ return private_is_attribute_p (attr_name, strlen (attr_name), ident);
+}
/* Remove any instances of attribute ATTR_NAME in LIST and return the
- modified list. */
+ modified list. ATTR_NAME must be in the form 'text' (not
+ '__text__'). */
extern tree remove_attribute (const char *, tree);