#include "config.h"
#include "system.h"
#include "tree.h"
#include "flags.h"
#include "toplev.h"
#include "output.h"
#include "rtl.h"
#include "ggc.h"
#include "expr.h"
#include "tm_p.h"
#include "cpplib.h"
#include "target.h"
#include "langhooks.h"
static void init_attributes PARAMS ((void));
static const struct attribute_spec *attribute_tables[4];
static bool attributes_initialized = false;
static const struct attribute_spec empty_attribute_table[] =
{
{ NULL, 0, 0, false, false, false, NULL }
};
static void
init_attributes ()
{
size_t i;
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;
for (i = 0; i < ARRAY_SIZE (attribute_tables); i++)
if (attribute_tables[i] == NULL)
attribute_tables[i] = empty_attribute_table;
#ifdef ENABLE_CHECKING
for (i = 0; i < ARRAY_SIZE (attribute_tables); i++)
{
int j;
for (j = 0; attribute_tables[i][j].name != NULL; j++)
{
const char *name = attribute_tables[i][j].name;
int len = strlen (name);
if (name[0] == '_' && name[1] == '_'
&& name[len - 1] == '_' && name[len - 2] == '_')
abort ();
if (attribute_tables[i][j].min_length < 0)
abort ();
if (attribute_tables[i][j].max_length != -1
&& (attribute_tables[i][j].max_length
< attribute_tables[i][j].min_length))
abort ();
if (attribute_tables[i][j].decl_required
&& attribute_tables[i][j].type_required)
abort ();
if (attribute_tables[i][j].function_type_required
&& !attribute_tables[i][j].type_required)
abort ();
}
}
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++)
if (!strcmp (attribute_tables[i][j].name,
attribute_tables[i][k].name))
abort ();
}
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++)
if (!strcmp (attribute_tables[i][k].name,
attribute_tables[j][l].name))
abort ();
}
#endif
attributes_initialized = true;
}
tree
decl_attributes (node, attributes, flags)
tree *node, attributes;
int flags;
{
tree a;
tree returned_attrs = NULL_TREE;
if (!attributes_initialized)
init_attributes ();
(*targetm.insert_attributes) (*node, &attributes);
if (DECL_P (*node) && TREE_CODE (*node) == FUNCTION_DECL
&& !(flags & (int) ATTR_FLAG_BUILT_IN))
(*lang_hooks.insert_default_attributes) (*node);
for (a = attributes; a; a = TREE_CHAIN (a))
{
tree name = TREE_PURPOSE (a);
tree args = TREE_VALUE (a);
tree *anode = node;
const struct attribute_spec *spec = NULL;
bool no_add_attrs = 0;
size_t i;
for (i = 0; i < ARRAY_SIZE (attribute_tables); i++)
{
int j;
for (j = 0; attribute_tables[i][j].name != NULL; j++)
{
if (is_attribute_p (attribute_tables[i][j].name, name))
{
spec = &attribute_tables[i][j];
break;
}
}
if (spec != NULL)
break;
}
if (spec == NULL)
{
warning ("`%s' attribute directive ignored",
IDENTIFIER_POINTER (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 `%s' attribute",
IDENTIFIER_POINTER (name));
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))
{
returned_attrs = tree_cons (name, args, returned_attrs);
continue;
}
else
{
warning ("`%s' attribute does not apply to types",
IDENTIFIER_POINTER (name));
continue;
}
}
if (spec->type_required && DECL_P (*anode))
{
anode = &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))
{
if (!(flags & (int) ATTR_FLAG_TYPE_IN_PLACE))
*anode = build_type_copy (*anode);
anode = &TREE_TYPE (*anode);
}
else if (flags & (int) ATTR_FLAG_FUNCTION_NEXT)
{
returned_attrs = tree_cons (name, args, returned_attrs);
continue;
}
if (TREE_CODE (*anode) != FUNCTION_TYPE
&& TREE_CODE (*anode) != METHOD_TYPE)
{
warning ("`%s' attribute only applies to function types",
IDENTIFIER_POINTER (name));
continue;
}
}
if (spec->handler != NULL)
returned_attrs = chainon ((*spec->handler) (anode, name, args,
flags, &no_add_attrs),
returned_attrs);
if (spec->type_required && DECL_P (*node)
&& (TREE_CODE (*node) == VAR_DECL
|| TREE_CODE (*node) == PARM_DECL
|| TREE_CODE (*node) == RESULT_DECL))
{
DECL_MODE (*node) = VOIDmode;
DECL_SIZE (*node) = 0;
layout_decl (*node, 0);
}
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)
{
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);
else
*anode = build_type_attribute_variant (*anode,
tree_cons (name, args,
old_attrs));
}
}
}
return returned_attrs;
}
void
split_specs_attrs (specs_attrs, declspecs, prefix_attributes)
tree specs_attrs;
tree *declspecs, *prefix_attributes;
{
tree t, s, a, next, specs, attrs;
if (specs_attrs != NULL_TREE
&& TREE_CODE (specs_attrs) == INTEGER_CST)
{
*declspecs = NULL_TREE;
*prefix_attributes = NULL_TREE;
return;
}
if (specs_attrs != NULL_TREE
&& TREE_CODE (specs_attrs) != TREE_LIST)
{
*declspecs = specs_attrs;
*prefix_attributes = NULL_TREE;
return;
}
specs = s = NULL_TREE;
attrs = a = NULL_TREE;
for (t = specs_attrs; t; t = next)
{
next = TREE_CHAIN (t);
if (TREE_VALUE (t) != NULL_TREE)
{
if (specs == NULL_TREE)
specs = s = t;
else
{
TREE_CHAIN (s) = t;
s = t;
}
}
else if (TREE_PURPOSE (t) != NULL_TREE)
{
if (attrs == NULL_TREE)
attrs = a = TREE_PURPOSE (t);
else
{
TREE_CHAIN (a) = TREE_PURPOSE (t);
a = TREE_PURPOSE (t);
}
while (TREE_CHAIN (a) != NULL_TREE)
a = TREE_CHAIN (a);
}
}
if (s != NULL_TREE)
TREE_CHAIN (s) = NULL_TREE;
if (a != NULL_TREE)
TREE_CHAIN (a) = NULL_TREE;
*declspecs = specs;
*prefix_attributes = attrs;
}
tree
strip_attrs (specs_attrs)
tree specs_attrs;
{
tree specs, attrs;
split_specs_attrs (specs_attrs, &specs, &attrs);
while (attrs)
{
warning ("`%s' attribute ignored",
IDENTIFIER_POINTER (TREE_PURPOSE (attrs)));
attrs = TREE_CHAIN (attrs);
}
return specs;
}