/* Functions dealing with attribute handling, used by most front ends.
- Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001
- Free Software Foundation, Inc.
+ Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
+ 2002 Free Software Foundation, Inc.
This file is part of GCC.
#include "obstack.h"
#include "cpplib.h"
#include "target.h"
+#include "langhooks.h"
static void init_attributes PARAMS ((void));
bool *));
static tree handle_noinline_attribute PARAMS ((tree *, tree, tree, int,
bool *));
+static tree handle_always_inline_attribute PARAMS ((tree *, tree, tree, int,
+ bool *));
static tree handle_used_attribute PARAMS ((tree *, tree, tree, int,
bool *));
static tree handle_unused_attribute PARAMS ((tree *, tree, tree, int,
bool *));
static tree handle_alias_attribute PARAMS ((tree *, tree, tree, int,
bool *));
+static tree handle_visibility_attribute PARAMS ((tree *, tree, tree, int,
+ bool *));
static tree handle_no_instrument_function_attribute PARAMS ((tree *, tree,
tree, int,
bool *));
bool *));
static tree handle_pure_attribute PARAMS ((tree *, tree, tree, int,
bool *));
+static tree handle_deprecated_attribute PARAMS ((tree *, tree, tree, int,
+ bool *));
static tree handle_vector_size_attribute PARAMS ((tree *, tree, tree, int,
bool *));
static tree vector_size_helper PARAMS ((tree, tree));
handle_noreturn_attribute },
{ "noinline", 0, 0, true, false, false,
handle_noinline_attribute },
+ { "always_inline", 0, 0, true, false, false,
+ handle_always_inline_attribute },
{ "used", 0, 0, true, false, false,
handle_used_attribute },
{ "unused", 0, 0, false, false, false,
handle_no_limit_stack_attribute },
{ "pure", 0, 0, true, false, false,
handle_pure_attribute },
+ { "deprecated", 0, 0, false, false, false,
+ handle_deprecated_attribute },
{ "vector_size", 1, 1, false, true, false,
handle_vector_size_attribute },
+ { "visibility", 1, 1, true, false, false,
+ handle_visibility_attribute },
{ NULL, 0, 0, false, false, false, NULL }
};
init_attributes ()
{
#ifdef ENABLE_CHECKING
- int i;
+ size_t i;
#endif
attribute_tables[0]
#ifdef ENABLE_CHECKING
/* Make some sanity checks on the attribute tables. */
- for (i = 0;
- i < (int) (sizeof (attribute_tables) / sizeof (attribute_tables[0]));
- i++)
+ for (i = 0; i < ARRAY_SIZE (attribute_tables); i++)
{
int j;
}
/* Check that each name occurs just once in each table. */
- for (i = 0;
- i < (int) (sizeof (attribute_tables) / sizeof (attribute_tables[0]));
- i++)
+ for (i = 0; i < ARRAY_SIZE (attribute_tables); i++)
{
int j, k;
for (j = 0; attribute_tables[i][j].name != NULL; j++)
abort ();
}
/* Check that no name occurs in more than one table. */
- for (i = 0;
- i < (int) (sizeof (attribute_tables) / sizeof (attribute_tables[0]));
- i++)
+ for (i = 0; i < ARRAY_SIZE (attribute_tables); i++)
{
- int j, k, l;
+ size_t j, k, l;
- for (j = i + 1;
- j < ((int) (sizeof (attribute_tables)
- / sizeof (attribute_tables[0])));
- j++)
+ 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,
if (DECL_P (*node) && TREE_CODE (*node) == FUNCTION_DECL
&& !(flags & (int) ATTR_FLAG_BUILT_IN))
- insert_default_attributes (*node);
+ (*lang_hooks.insert_default_attributes) (*node);
for (a = attributes; a; a = TREE_CHAIN (a))
{
tree *anode = node;
const struct attribute_spec *spec = NULL;
bool no_add_attrs = 0;
- int i;
+ size_t i;
- for (i = 0;
- i < ((int) (sizeof (attribute_tables)
- / sizeof (attribute_tables[0])));
- i++)
+ for (i = 0; i < ARRAY_SIZE (attribute_tables); i++)
{
int j;
}
}
+ /* 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);
+ {
+ 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)
/* Layout the decl in case anything changed. */
if (spec->type_required && DECL_P (*node)
- && TREE_CODE (*node) == VAR_DECL)
+ && (TREE_CODE (*node) == VAR_DECL
+ || TREE_CODE (*node) == PARM_DECL
+ || TREE_CODE (*node) == RESULT_DECL))
{
/* Force a recalculation of mode and size. */
DECL_MODE (*node) = VOIDmode;
return NULL_TREE;
}
+/* Handle a "always_inline" attribute; arguments as in
+ struct attribute_spec.handler. */
+
+static tree
+handle_always_inline_attribute (node, name, args, flags, no_add_attrs)
+ tree *node;
+ tree name;
+ tree args ATTRIBUTE_UNUSED;
+ int flags ATTRIBUTE_UNUSED;
+ bool *no_add_attrs;
+{
+ if (TREE_CODE (*node) == FUNCTION_DECL)
+ {
+ /* Do nothing else, just set the attribute. We'll get at
+ it later with lookup_attribute. */
+ }
+ else
+ {
+ warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
+ *no_add_attrs = true;
+ }
+
+ return NULL_TREE;
+}
+
/* Handle a "used" attribute; arguments as in
struct attribute_spec.handler. */
if (mode == VOIDmode)
error ("unknown machine mode `%s'", p);
- else if (0 == (typefm = type_for_mode (mode,
- TREE_UNSIGNED (type))))
+ else if (0 == (typefm = (*lang_hooks.types.type_for_mode)
+ (mode, TREE_UNSIGNED (type))))
error ("no data type for mode `%s'", p);
else
*node = typefm;
DECL_INITIAL (decl) = error_mark_node;
else
DECL_EXTERNAL (decl) = 0;
- assemble_alias (decl, id);
}
else
{
return NULL_TREE;
}
+/* Handle an "visibility" attribute; arguments as in
+ struct attribute_spec.handler. */
+
+static tree
+handle_visibility_attribute (node, name, args, flags, no_add_attrs)
+ tree *node;
+ tree name;
+ tree args;
+ int flags ATTRIBUTE_UNUSED;
+ bool *no_add_attrs;
+{
+ tree decl = *node;
+
+ if (decl_function_context (decl) != 0 || ! TREE_PUBLIC (decl))
+ {
+ warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
+ *no_add_attrs = true;
+ }
+ else
+ {
+ tree id;
+
+ id = TREE_VALUE (args);
+ if (TREE_CODE (id) != STRING_CST)
+ {
+ error ("visibility arg not a string");
+ *no_add_attrs = true;
+ return NULL_TREE;
+ }
+ if (strcmp (TREE_STRING_POINTER (id), "hidden")
+ && strcmp (TREE_STRING_POINTER (id), "protected")
+ && strcmp (TREE_STRING_POINTER (id), "internal"))
+ {
+ error ("visibility arg must be one of \"hidden\", \"protected\" or \"internal\"");
+ *no_add_attrs = true;
+ return NULL_TREE;
+ }
+ }
+
+ return NULL_TREE;
+}
+
/* Handle a "no_instrument_function" attribute; arguments as in
struct attribute_spec.handler. */
return NULL_TREE;
}
+/* Handle a "deprecated" attribute; arguments as in
+ struct attribute_spec.handler. */
+
+static tree
+handle_deprecated_attribute (node, name, args, flags, no_add_attrs)
+ tree *node;
+ tree name;
+ tree args ATTRIBUTE_UNUSED;
+ int flags;
+ bool *no_add_attrs;
+{
+ tree type = NULL_TREE;
+ int warn = 0;
+ const char *what = NULL;
+
+ if (DECL_P (*node))
+ {
+ tree decl = *node;
+ type = TREE_TYPE (decl);
+
+ if (TREE_CODE (decl) == TYPE_DECL
+ || TREE_CODE (decl) == PARM_DECL
+ || TREE_CODE (decl) == VAR_DECL
+ || TREE_CODE (decl) == FUNCTION_DECL
+ || TREE_CODE (decl) == FIELD_DECL)
+ TREE_DEPRECATED (decl) = 1;
+ else
+ warn = 1;
+ }
+ else if (TYPE_P (*node))
+ {
+ if (!(flags & (int) ATTR_FLAG_TYPE_IN_PLACE))
+ *node = build_type_copy (*node);
+ TREE_DEPRECATED (*node) = 1;
+ type = *node;
+ }
+ else
+ warn = 1;
+
+ if (warn)
+ {
+ *no_add_attrs = true;
+ if (type && TYPE_NAME (type))
+ {
+ if (TREE_CODE (TYPE_NAME (type)) == IDENTIFIER_NODE)
+ what = IDENTIFIER_POINTER (TYPE_NAME (*node));
+ else if (TREE_CODE (TYPE_NAME (type)) == TYPE_DECL
+ && DECL_NAME (TYPE_NAME (type)))
+ what = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (type)));
+ }
+ if (what)
+ warning ("`%s' attribute ignored for `%s'",
+ IDENTIFIER_POINTER (name), what);
+ else
+ warning ("`%s' attribute ignored",
+ IDENTIFIER_POINTER (name));
+ }
+
+ return NULL_TREE;
+}
+
/* Handle a "vector_size" attribute; arguments as in
struct attribute_spec.handler. */
int flags ATTRIBUTE_UNUSED;
bool *no_add_attrs;
{
- unsigned int vecsize, nunits;
+ unsigned HOST_WIDE_INT vecsize, nunits;
enum machine_mode mode, orig_mode, new_mode;
tree type = *node, new_type;
*no_add_attrs = true;
- if (TREE_CODE (TREE_VALUE (args)) != INTEGER_CST)
+ if (! host_integerp (TREE_VALUE (args), 1))
{
warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
return NULL_TREE;
}
/* Get the vector size (in bytes). */
- vecsize = TREE_INT_CST_LOW (TREE_VALUE (args));
+ vecsize = tree_low_cst (TREE_VALUE (args), 1);
/* We need to provide for vector pointers, vector arrays, and
functions returning vectors. For example:
/* Get the mode of the type being modified. */
orig_mode = TYPE_MODE (type);
- if (TREE_CODE (type) == RECORD_TYPE ||
- (GET_MODE_CLASS (orig_mode) != MODE_FLOAT
- && GET_MODE_CLASS (orig_mode) != MODE_INT))
+ if (TREE_CODE (type) == RECORD_TYPE
+ || (GET_MODE_CLASS (orig_mode) != MODE_FLOAT
+ && GET_MODE_CLASS (orig_mode) != MODE_INT)
+ || ! host_integerp (TYPE_SIZE_UNIT (type), 1))
{
error ("invalid vector type for attribute `%s'",
IDENTIFIER_POINTER (name));
}
/* Calculate how many units fit in the vector. */
- nunits = vecsize / TREE_INT_CST_LOW (TYPE_SIZE_UNIT (type));
+ nunits = vecsize / tree_low_cst (TYPE_SIZE_UNIT (type), 1);
/* Find a suitably sized vector. */
new_mode = VOIDmode;
: MODE_VECTOR_FLOAT);
mode != VOIDmode;
mode = GET_MODE_WIDER_MODE (mode))
- if (vecsize == GET_MODE_SIZE (mode) && nunits == GET_MODE_NUNITS (mode))
+ if (vecsize == GET_MODE_SIZE (mode)
+ && nunits == (unsigned HOST_WIDE_INT) GET_MODE_NUNITS (mode))
{
new_mode = mode;
break;
error ("no vector mode with the size and type specified could be found");
else
{
- new_type = type_for_mode (new_mode, TREE_UNSIGNED (type));
+ tree index, array, rt;
+
+ new_type = (*lang_hooks.types.type_for_mode) (new_mode,
+ TREE_UNSIGNED (type));
+
if (!new_type)
- error ("no vector mode with the size and type specified could be found");
- else
- /* Build back pointers if needed. */
- *node = vector_size_helper (*node, new_type);
+ {
+ error ("no vector mode with the size and type specified could be found");
+ return NULL_TREE;
+ }
+
+ new_type = build_type_copy (new_type);
+
+ /* Set the debug information here, because this is the only
+ place where we know the underlying type for a vector made
+ with vector_size. For debugging purposes we pretend a vector
+ is an array within a structure. */
+ index = build_int_2 (TYPE_VECTOR_SUBPARTS (new_type) - 1, 0);
+ array = build_array_type (type, build_index_type (index));
+ rt = make_node (RECORD_TYPE);
+
+ TYPE_FIELDS (rt) = build_decl (FIELD_DECL, get_identifier ("f"), array);
+ DECL_CONTEXT (TYPE_FIELDS (rt)) = rt;
+ layout_type (rt);
+ TYPE_DEBUG_REPRESENTATION_TYPE (new_type) = rt;
+
+ /* Build back pointers if needed. */
+ *node = vector_size_helper (*node, new_type);
}
return NULL_TREE;
return specs;
}
+