}
\f
/* Return first list element whose TREE_VALUE is ELEM.
- Return 0 if ELEM is not it LIST. */
+ Return 0 if ELEM is not in LIST. */
tree
value_member (elem, list)
}
/* Return first list element whose TREE_PURPOSE is ELEM.
- Return 0 if ELEM is not it LIST. */
+ Return 0 if ELEM is not in LIST. */
tree
purpose_member (elem, list)
}
/* Return first list element whose BINFO_TYPE is ELEM.
- Return 0 if ELEM is not it LIST. */
+ Return 0 if ELEM is not in LIST. */
tree
binfo_member (elem, list)
/* Return nonzero if ELEM is equal to TREE_VALUE (CHAIN) for any piece of
chain CHAIN. */
+/* ??? This function was added for machine specific attributes but is no
+ longer used. It could be deleted if we could confirm all front ends
+ don't use it. */
int
chain_member_value (elem, chain)
/* Return nonzero if ELEM is equal to TREE_PURPOSE (CHAIN)
for any piece of chain CHAIN. */
+/* ??? This function was added for machine specific attributes but is no
+ longer used. It could be deleted if we could confirm all front ends
+ don't use it. */
int
chain_member_purpose (elem, chain)
tree elem, chain;
{
-
while (chain)
{
if (elem == TREE_PURPOSE (chain))
hashcode = TYPE_HASH (TREE_CODE (ntype))
+ TYPE_HASH (TREE_TYPE (ntype))
- + type_hash_list (attribute);
+ + attribute_hash_list (attribute);
switch (TREE_CODE (ntype))
{
tree decl_attr_list = decl != 0 ? DECL_MACHINE_ATTRIBUTES (decl) : 0;
tree type_attr_list = TYPE_ATTRIBUTES (type);
- /* For now, we don't support args. */
- if (attr_args != 0)
- return 0;
+ if (TREE_CODE (attr_name) != IDENTIFIER_NODE)
+ abort ();
#ifdef VALID_MACHINE_DECL_ATTRIBUTE
if (decl != 0
- && VALID_MACHINE_DECL_ATTRIBUTE (decl, decl_attr_list, attr_name))
+ && VALID_MACHINE_DECL_ATTRIBUTE (decl, decl_attr_list, attr_name, attr_args))
{
- if (! attribute_in_list (attr_name, decl_attr_list))
- {
- decl_attr_list = tree_cons (NULL_TREE, attr_name, decl_attr_list);
+ tree attr = lookup_attribute (IDENTIFIER_POINTER (attr_name),
+ decl_attr_list);
- /* Declarations are unique, build_decl_attribute_variant modifies
- the existing decl in situ. */
+ if (attr != NULL_TREE)
+ {
+ /* Override existing arguments. Declarations are unique so we can
+ modify this in place. */
+ TREE_VALUE (attr) = attr_args;
+ }
+ else
+ {
+ decl_attr_list = tree_cons (attr_name, attr_args, decl_attr_list);
decl = build_decl_attribute_variant (decl, decl_attr_list);
}
#endif
#ifdef VALID_MACHINE_TYPE_ATTRIBUTE
- if (VALID_MACHINE_TYPE_ATTRIBUTE (type, type_attr_list, attr_name))
+ if (VALID_MACHINE_TYPE_ATTRIBUTE (type, type_attr_list, attr_name, attr_args))
{
- if (! attribute_in_list (attr_name, type_attr_list))
+ tree attr = lookup_attribute (IDENTIFIER_POINTER (attr_name),
+ type_attr_list);
+
+ if (attr != NULL_TREE)
{
- type_attr_list = tree_cons (NULL_TREE, attr_name, type_attr_list);
+ /* Override existing arguments.
+ ??? This currently works since attribute arguments are not
+ included in `attribute_hash_list'. Something more complicated
+ may be needed in the future. */
+ TREE_VALUE (attr) = attr_args;
+ }
+ else
+ {
+ type_attr_list = tree_cons (attr_name, attr_args, type_attr_list);
type = build_type_attribute_variant (type, type_attr_list);
}
if (decl != 0)
return valid;
}
+
+/* Return non-zero 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. */
+
+int
+is_attribute_p (attr, ident)
+ char *attr;
+ tree ident;
+{
+ int ident_len, attr_len;
+ char *p;
+
+ if (TREE_CODE (ident) != IDENTIFIER_NODE)
+ return 0;
+
+ if (strcmp (attr, IDENTIFIER_POINTER (ident)) == 0)
+ return 1;
+
+ p = IDENTIFIER_POINTER (ident);
+ ident_len = strlen (p);
+ attr_len = strlen (attr);
+
+ /* If ATTR is `__text__', IDENT must be `text'; and vice versa. */
+ if (attr[0] == '_')
+ {
+ if (attr[1] != '_'
+ || attr[attr_len - 2] != '_'
+ || attr[attr_len - 1] != '_')
+ abort ();
+ if (ident_len == attr_len - 4
+ && strncmp (attr + 2, p, attr_len - 4) == 0)
+ return 1;
+ }
+ else
+ {
+ if (ident_len == attr_len + 4
+ && p[0] == '_' && p[1] == '_'
+ && p[ident_len - 2] == '_' && p[ident_len - 1] == '_'
+ && strncmp (attr, p + 2, attr_len) == 0)
+ return 1;
+ }
+
+ return 0;
+}
+
+/* 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. */
+
+tree
+lookup_attribute (attr_name, list)
+ char *attr_name;
+ tree list;
+{
+ tree l;
+
+ for (l = list; l; l = TREE_CHAIN (l))
+ {
+ if (TREE_CODE (TREE_PURPOSE (l)) != IDENTIFIER_NODE)
+ abort ();
+ if (is_attribute_p (attr_name, TREE_PURPOSE (l)))
+ return l;
+ }
+
+ return NULL_TREE;
+}
\f
/* Return a type like TYPE except that its TYPE_READONLY is CONSTP
and its TYPE_VOLATILE is VOLATILEP.
return type;
}
-/* Given an attribute and a list of attributes, return true if the attribute
- is part of the list. */
+/* Compute a hash code for a list of attributes (chain of TREE_LIST nodes
+ with names in the TREE_PURPOSE slots and args in the TREE_VALUE slots),
+ by adding the hash codes of the individual attributes. */
int
-attribute_in_list (attribute, list)
- tree attribute, list;
+attribute_hash_list (list)
+ tree list;
{
- register tree purpose, chain;
-
- /* Perform a quick check. */
- if (value_member (attribute, list))
- return 1;
-
- /* If it's not a TREE_LIST, we should have had a match by now. */
- if (TREE_CODE (attribute) != TREE_LIST)
- return 0;
-
- purpose = TREE_PURPOSE (attribute);
- chain = TREE_CHAIN (attribute);
-
- for (; list; list = TREE_CHAIN (list))
- {
- register tree value;
-
- value = TREE_VALUE (list);
-
- if (TREE_CODE (value) == TREE_LIST
- && TREE_PURPOSE (value) == purpose
- && simple_cst_equal (TREE_CHAIN (value), chain) == 1)
- return 1;
- }
-
- return 0;
+ register int hashcode;
+ register tree tail;
+ for (hashcode = 0, tail = list; tail; tail = TREE_CHAIN (tail))
+ /* ??? Do we want to add in TREE_VALUE too? */
+ hashcode += TYPE_HASH (TREE_PURPOSE (tail));
+ return hashcode;
}
/* Given two lists of attributes, return true if list l2 is
&& attribute_list_contained (l2, l1);
}
-/* Given two lists of attributes, return true if list l2 is
- completely contained within l1. */
+/* Given two lists of attributes, return true if list L2 is
+ completely contained within L1. */
+/* ??? This would be faster if attribute names were stored in a canonicalized
+ form. Otherwise, if L1 uses `foo' and L2 uses `__foo__', the long method
+ must be used to show these elements are equivalent (which they are). */
+/* ??? It's not clear that attributes with arguments will always be handled
+ correctly. */
int
attribute_list_contained (l1, l2)
if (l1 == l2)
return 1;
- /* Then check the obvious, maybe the lists are similar. */
+ /* Maybe the lists are similar. */
for (t1 = l1, t2 = l2;
t1 && t2
+ && TREE_PURPOSE (t1) == TREE_PURPOSE (t2)
&& TREE_VALUE (t1) == TREE_VALUE (t2);
t1 = TREE_CHAIN (t1), t2 = TREE_CHAIN (t2));
return 1;
for (; t2; t2 = TREE_CHAIN (t2))
- if (! attribute_in_list (TREE_VALUE (t2), l1))
+ {
+ tree attr = lookup_attribute (IDENTIFIER_POINTER (TREE_PURPOSE (t2)), l1);
+
+ if (attr == NULL_TREE)
return 0;
+ if (simple_cst_equal (TREE_VALUE (t2), TREE_VALUE (attr)) != 1)
+ return 0;
+ }
return 1;
}