diff options
author | Joseph Myers <jsm28@cam.ac.uk> | 2001-09-21 02:27:06 +0100 |
---|---|---|
committer | Joseph Myers <jsm28@gcc.gnu.org> | 2001-09-21 02:27:06 +0100 |
commit | 91d231cb917f53b4cd34dec24227863e95fceb6f (patch) | |
tree | f30b39e86c1e124ae235fd7661bc83c06577bc32 /gcc/c-common.c | |
parent | 3007d592bf05a6f1728f023c46207083cd24ca32 (diff) | |
download | gcc-91d231cb917f53b4cd34dec24227863e95fceb6f.zip gcc-91d231cb917f53b4cd34dec24227863e95fceb6f.tar.gz gcc-91d231cb917f53b4cd34dec24227863e95fceb6f.tar.bz2 |
Table-driven attributes.
* c-decl.c, config/alpha/alpha.c, config/arc/arc.c,
config/arm/arm.c, config/arm/pe.c, config/avr/avr.c,
config/avr/avr.h, config/d30v/d30v.h, config/fr30/fr30.h,
config/h8300/h8300.c, config/i386/cygwin.h, config/i386/winnt.c,
config/m32r/m32r.c, config/mcore/mcore.c, config/sh/sh.c,
config/stormy16/stormy16.h, config/v850/v850.c, doc/c-tree.texi,
doc/tm.texi, ggc-common.c, integrate.c, print-tree.c, tree.c,
tree.h: Rename DECL_MACHINE_ATTRIBUTES to DECL_ATTRIBUTES.
* tree.h (struct tree_decl): Change machine_attributes to
attributes.
* doc/c-tree.texi: Document that all attributes are now attached
to decls and types.
* c-common.c (add_attribute, attrtab, attrtab_idx,
default_valid_lang_attribute, valid_lang_attribute): Remove.
(attribute_tables, attributes_initialized,
c_common_attribute_table, default_lang_attribute_table): New
variables.
(handle_packed_attribute, handle_nocommon_attribute,
handle_common_attribute, handle_noreturn_attribute,
handle_unused_attribute, handle_const_attribute,
handle_transparent_union_attribute, handle_constructor_attribute,
handle_destructor_attribute, handle_mode_attribute,
handle_section_attribute, handle_aligned_attribute,
handle_weak_attribute, handle_alias_attribute,
handle_no_instrument_function_attribute,
handle_no_check_memory_usage_attribute, handle_malloc_attribute,
handle_no_limit_stack_attribute, handle_pure_attribute): New
functions.
(init_attributes, decl_attributes): Rewrite to implement
table-driven attributes.
* c-common.h (enum attribute_flags): Move to tree.h.
* c-format.c (decl_handle_format_attribute,
decl_handle_format_arg_attribute): Rename to
handle_format_attribute and handle_format_arg_attribute. Update
for table-driven attributes.
* c-common.h (decl_handle_format_attribute,
decl_handle_format_arg_attribute): Remove prototypes.
(handle_format_attribute, handle_format_arg_attribute): Add
prototypes.
* c-decl.c (grokdeclarator): Handle attributes nested inside
declarators.
* c-parse.in (setattrs, maybe_setattrs): Remove.
(maybe_type_quals_setattrs): Rename to maybe_type_quals_attrs.
Update to handle nested attributes properly.
(maybe_resetattrs, after_type_declarator,
parm_declarator_nostarttypename, notype_declarator, absdcl1_noea,
absdcl1_ea, direct_absdcl1): Update to handle nested attributes
properly.
(make_pointer_declarator): Update to handle nested attributes
properly.
* doc/extend.texi: Update documentation of limits of attributes
syntax. Warn about problems with attribute semantics in C++.
* target.h (struct target): Remove valid_decl_attribute and
valid_type_attribute. Add attribute_table and
function_attribute_inlinable_p.
* target-def.h (TARGET_VALID_DECL_ATTRIBUTE,
TARGET_VALID_TYPE_ATTRIBUTE): Remove.
(TARGET_ATTRIBUTE_TABLE, TARGET_FUNCTION_ATTRIBUTE_INLINABLE_P):
Add.
(TARGET_INITIALIZER): Update.
* integrate.c (FUNCTION_ATTRIBUTE_INLINABLE_P): Remove default
definition.
(function_attribute_inlinable_p): New function. Check for the
presence of any machine attributes before using
targetm.function_attribute_inlinable_p.
(function_cannot_inline_p): Update.
* Makefile.in (integrate.o): Update dependencies.
* doc/tm.texi: Update documentation of target attributes and
example definition of TARGET_VALID_TYPE_ATTRIBUTE.
* tree.c (default_valid_attribute_p, valid_machine_attribute):
Remove.
(default_target_attribute_table,
default_function_attribute_inlinable_p): New.
(lookup_attribute): Update comment to clarify handling of multiple
attributes with the same name.
(merge_attributes, attribute_list_contained): Allow multiple
attributes with the same name but different arguments to appear in
the same attribute list.
* tree.h (default_valid_attribute_p): Remove prototype.
(struct attribute_spec): New.
(default_target_attribute_table): Declare.
(enum attribute_flags): Move from c-common.h. Add
ATTR_FLAG_TYPE_IN_PLACE.
(default_function_attribute_inlinable_p): Declare.
* config/alpha/alpha.c (vms_valid_decl_attribute_p): Remove.
(TARGET_VALID_DECL_ATTRIBUTE): Don't define.
(TARGET_ATTRIBUTE_TABLE): Define.
(vms_attribute_table): New.
* config/arc/arc.c (arc_valid_decl_attribute): Remove.
(TARGET_VALID_DECL_ATTRIBUTE): Don't define.
(TARGET_ATTRIBUTE_TABLE): Define.
(arc_attribute_table, arc_handle_interrupt_attribute): New.
* config/arm/arm.c (arm_valid_type_attribute_p,
arm_valid_decl_attribute_p, arm_pe_valid_decl_attribute_p):
Remove.
(TARGET_VALID_TYPE_ATTRIBUTE, TARGET_VALID_DECL_ATTRIBUTE): Don't
define.
(TARGET_ATTRIBUTE_TABLE): Define.
(arm_attribute_table, arm_handle_fndecl_attribute,
arm_handle_isr_attribute): New.
* config/avr/avr.c (avr_valid_type_attribute,
avr_valid_decl_attribute): Remove.
(TARGET_VALID_DECL_ATTRIBUTE, TARGET_VALID_TYPE_ATTRIBUTE): Don't
define.
(TARGET_ATTRIBUTE_TABLE): Define.
(avr_attribute_table, avr_handle_progmem_attribute,
avr_handle_fndecl_attribute): New.
* config/c4x/c4x.c (c4x_valid_type_attribute_p): Remove.
(TARGET_VALID_TYPE_ATTRIBUTE): Don't define.
(TARGET_ATTRIBUTE_TABLE): Define.
(c4x_attribute_table, c4x_handle_fntype_attribute): New.
* config/h8300/h8300.c (h8300_valid_decl_attribute): Remove.
(TARGET_VALID_DECL_ATTRIBUTE): Don't define.
(TARGET_ATTRIBUTE_TABLE): Define.
(h8300_attribute_table, h8300_handle_fndecl_attribute,
h8300_handle_eightbit_data_attribute,
h8300_handle_tiny_data_attribute): New.
* config/i386/i386-protos.h (ix86_valid_type_attribute_p,
i386_pe_valid_decl_attribute_p, i386_pe_valid_type_attribute_p):
Remove prototypes.
(ix86_handle_dll_attribute, ix86_handle_shared_attribute): New
declarations.
* config/i386/i386.c (ix86_valid_type_attribute_p: Remove.
(TARGET_VALID_TYPE_ATTRIBUTE, TARGET_VALID_DECL_ATTRIBUTE): Don't
define.
(TARGET_ATTRIBUTE_TABLE): Define.
(ix86_attribute_table, ix86_handle_cdecl_attribute,
ix86_handle_regparm_attribute): New.
* config/i386/winnt.c (i386_pe_valid_decl_attribute_p,
i386_pe_valid_type_attribute_p): Remove.
(ix86_handle_dll_attribute, ix86_handle_shared_attribute): New.
* config/ia64/ia64.c (ia64_valid_type_attribute): Remove.
(TARGET_VALID_TYPE_ATTRIBUTE): Don't define.
(TARGET_ATTRIBUTE_TABLE): Define.
(ia64_attribute_table): New.
* config/m32r/m32r.c (m32r_valid_decl_attribute, interrupt_ident1,
interrupt_ident2, model_ident1, model_ident2): Remove.
(TARGET_VALID_DECL_ATTRIBUTE): Don't define.
(TARGET_ATTRIBUTE_TABLE): Define.
(init_idents): Update.
(m32r_attribute_table, m32r_handle_model_attribute): New.
* config/m68hc11/m68hc11.c (m68hc11_valid_type_attribute_p):
Remove.
(TARGET_VALID_TYPE_ATTRIBUTE): Don't define.
(TARGET_ATTRIBUTE_TABLE): Define.
(m68hc11_attribute_table, m68hc11_handle_fntype_attribute): New.
* config/mcore/mcore.c (mcore_valid_decl_attribute): Remove.
(TARGET_VALID_DECL_ATTRIBUTE): Don't define.
(TARGET_ATTRIBUTE_TABLE): Define.
(mcore_attribute_table, mcore_handle_naked_attribute): New.
* config/ns32k/ns32k.c (ns32k_valid_type_attribute_p): Remove.
(TARGET_VALID_TYPE_ATTRIBUTE): Don't define.
(TARGET_ATTRIBUTE_TABLE): Define.
(ns32k_attribute_table, ns32k_handle_fntype_attribute): New.
* config/rs6000/rs6000.c (rs6000_valid_type_attribute_p): Remove.
(TARGET_VALID_TYPE_ATTRIBUTE): Don't define.
(TARGET_ATTRIBUTE_TABLE): Define.
(rs6000_attribute_table, rs6000_handle_longcall_attribute): New.
* config/sh/sh.c (sh_valid_decl_attribute): Remove.
(TARGET_VALID_DECL_ATTRIBUTE): Don't define.
(TARGET_ATTRIBUTE_TABLE): Define.
(sh_attribute_table, sh_handle_interrupt_handler_attribute,
sh_handle_sp_switch_attribute, sh_handle_trap_exit_attribute):
New.
* config/stormy16/stormy16.c (stormy16_valid_type_attribute):
Remove.
(TARGET_VALID_TYPE_ATTRIBUTE): Don't define
(TARGET_ATTRIBUTE_TABLE): Define.
(stormy16_attribute_table, stormy16_handle_interrupt_attribute):
New.
* config/v850/v850.c (v850_valid_decl_attribute): Remove.
(TARGET_VALID_DECL_ATTRIBUTE): Don't define.
(TARGET_ATTRIBUTE_TABLE): Define.
(v850_attribute_table, v850_handle_interrupt_attribute,
v850_handle_data_area_attribute): New.
* config/v850/v850-c.c (mark_current_function_as_interrupt):
Return void. Call decl_attributes instead of
valid_machine_attribute.
cp:
Table-driven attributes.
* decl.c: Rename DECL_MACHINE_ATTRIBUTES to DECL_ATTRIBUTES.
* decl2.c (cplus_decl_attributes): Only take one attributes
parameter.
* cp-tree.c (cplus_decl_attributes): Update prototype.
* class.c (finish_struct), decl.c (start_decl, start_function),
decl2.c (grokfield), friend.c (do_friend), parse.y
(parse_bitfield): Update calls to cplus_decl_attributes.
* decl.c (grokdeclarator): Take a pointer to a single ordinary
attribute list.
* decl.h (grokdeclarator): Update prototype.
* decl2.c (grokfield): Take a single ordinary attribute list.
* friend.c (do_friend): Likewise.
* decl.c (shadow_tag, groktypename, start_decl,
start_handler_parms, grokdeclarator, grokparms, start_function,
start_method), decl2.c (grokfield, grokbitfield, grokoptypename),
parse.y (parse_field, parse_bitfield, component_decl_1), pt.c
(process_template_parm, do_decl_instantiation): Pass single
ordinary attribute lists around.
* decl.c (grokdeclarator): Correct handling of nested attributes.
Revert the patch
1998-10-18 Jason Merrill <jason@yorick.cygnus.com>
* decl.c (grokdeclarator): Embedded attrs bind to the right,
not the left.
.
* cp-tree.h (cp_valid_lang_attribute): Remove declaration
(cp_attribute_table): Declare.
* decl.c (valid_lang_attribute): Don't define.
(lang_attribute_table): Define.
(init_decl_processing): Initialize lang_attribute_table instead of
valid_lang_attribute.
* tree.c (cp_valid_lang_attribute): Remove.
(handle_java_interface_attribute, handle_com_interface_attribute,
handle_init_priority_attribute): New functions.
(cp_attribute_table): New array.
* decl2.c (import_export_class): Don't use
targetm.valid_type_attribute.
testsuite:
Table-driven attributes.
* g++.dg/ext/attrib1.C: New test.
From-SVN: r45718
Diffstat (limited to 'gcc/c-common.c')
-rw-r--r-- | gcc/c-common.c | 1343 |
1 files changed, 910 insertions, 433 deletions
diff --git a/gcc/c-common.c b/gcc/c-common.c index 1515e45..8d00cfe 100644 --- a/gcc/c-common.c +++ b/gcc/c-common.c @@ -243,10 +243,7 @@ const struct fname_var_t fname_vars[] = {NULL, 0, 0}, }; -static void add_attribute PARAMS ((enum attrs, const char *, - int, int, int)); static void init_attributes PARAMS ((void)); -static int default_valid_lang_attribute PARAMS ((tree, tree, tree, tree)); static int constant_fits_type_p PARAMS ((tree, tree)); /* Keep a stack of if statements. We record the number of compound @@ -640,514 +637,994 @@ combine_strings (strings) return value; } -/* To speed up processing of attributes, we maintain an array of - IDENTIFIER_NODES and the corresponding attribute types. */ - -/* Array to hold attribute information. */ - -static struct {enum attrs id; tree name; int min, max, decl_req;} attrtab[50]; - -static int attrtab_idx = 0; - -/* Add an entry to the attribute table above. */ - -static void -add_attribute (id, string, min_len, max_len, decl_req) - enum attrs id; - const char *string; - int min_len, max_len; - int decl_req; +/* Table of the tables of attributes (common, language, machine) searched. */ +static const struct attribute_spec *attribute_tables[3]; + +static bool attributes_initialized = false; + +static tree handle_packed_attribute PARAMS ((tree *, tree, tree, int, bool *)); +static tree handle_nocommon_attribute PARAMS ((tree *, tree, tree, int, bool *)); +static tree handle_common_attribute PARAMS ((tree *, tree, tree, int, bool *)); +static tree handle_noreturn_attribute PARAMS ((tree *, tree, tree, int, bool *)); +static tree handle_unused_attribute PARAMS ((tree *, tree, tree, int, bool *)); +static tree handle_const_attribute PARAMS ((tree *, tree, tree, int, bool *)); +static tree handle_transparent_union_attribute PARAMS ((tree *, tree, tree, int, bool *)); +static tree handle_constructor_attribute PARAMS ((tree *, tree, tree, int, bool *)); +static tree handle_destructor_attribute PARAMS ((tree *, tree, tree, int, bool *)); +static tree handle_mode_attribute PARAMS ((tree *, tree, tree, int, bool *)); +static tree handle_section_attribute PARAMS ((tree *, tree, tree, int, bool *)); +static tree handle_aligned_attribute PARAMS ((tree *, tree, tree, int, bool *)); +static tree handle_weak_attribute PARAMS ((tree *, tree, tree, int, bool *)); +static tree handle_alias_attribute PARAMS ((tree *, tree, tree, int, bool *)); +static tree handle_no_instrument_function_attribute PARAMS ((tree *, tree, tree, int, bool *)); +static tree handle_no_check_memory_usage_attribute PARAMS ((tree *, tree, tree, int, bool *)); +static tree handle_malloc_attribute PARAMS ((tree *, tree, tree, int, bool *)); +static tree handle_no_limit_stack_attribute PARAMS ((tree *, tree, tree, int, bool *)); +static tree handle_pure_attribute PARAMS ((tree *, tree, tree, int, bool *)); + +/* Table of machine-independent attributes common to all C-like languages. */ +static const struct attribute_spec c_common_attribute_table[] = { - char buf[100]; - - attrtab[attrtab_idx].id = id; - attrtab[attrtab_idx].name = get_identifier (string); - attrtab[attrtab_idx].min = min_len; - attrtab[attrtab_idx].max = max_len; - attrtab[attrtab_idx++].decl_req = decl_req; + /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */ + { "packed", 0, 0, false, false, false, handle_packed_attribute }, + { "nocommon", 0, 0, true, false, false, handle_nocommon_attribute }, + { "common", 0, 0, true, false, false, handle_common_attribute }, + /* FIXME: logically, noreturn attributes should be listed as + "false, true, true" and apply to function types. But implementing this + would require all the places in the compiler that use TREE_THIS_VOLATILE + on a decl to identify non-returning functions to be located and fixed + to check the function type instead. */ + { "noreturn", 0, 0, true, false, false, handle_noreturn_attribute }, + { "volatile", 0, 0, true, false, false, handle_noreturn_attribute }, + { "unused", 0, 0, false, false, false, handle_unused_attribute }, + /* The same comments as for noreturn attributes apply to const ones. */ + { "const", 0, 0, true, false, false, handle_const_attribute }, + { "transparent_union", 0, 0, false, false, false, handle_transparent_union_attribute }, + { "constructor", 0, 0, true, false, false, handle_constructor_attribute }, + { "destructor", 0, 0, true, false, false, handle_destructor_attribute }, + { "mode", 1, 1, true, false, false, handle_mode_attribute }, + { "section", 1, 1, true, false, false, handle_section_attribute }, + { "aligned", 0, 1, false, false, false, handle_aligned_attribute }, + { "format", 3, 3, true, false, false, handle_format_attribute }, + { "format_arg", 1, 1, true, false, false, handle_format_arg_attribute }, + { "weak", 0, 0, true, false, false, handle_weak_attribute }, + { "alias", 1, 1, true, false, false, handle_alias_attribute }, + { "no_instrument_function", 0, 0, true, false, false, handle_no_instrument_function_attribute }, + { "no_check_memory_usage", 0, 0, true, false, false, handle_no_check_memory_usage_attribute }, + { "malloc", 0, 0, true, false, false, handle_malloc_attribute }, + { "no_stack_limit", 0, 0, true, false, false, handle_no_limit_stack_attribute }, + { "pure", 0, 0, true, false, false, handle_pure_attribute }, + { NULL, 0, 0, false, false, false, NULL } +}; - sprintf (buf, "__%s__", string); +/* Default empty table of language attributes. */ +static const struct attribute_spec default_lang_attribute_table[] = +{ + { NULL, 0, 0, false, false, false, NULL } +}; - attrtab[attrtab_idx].id = id; - attrtab[attrtab_idx].name = get_identifier (buf); - attrtab[attrtab_idx].min = min_len; - attrtab[attrtab_idx].max = max_len; - attrtab[attrtab_idx++].decl_req = decl_req; -} +/* Table of machine-independent attributes for a particular language. */ +const struct attribute_spec *lang_attribute_table = default_lang_attribute_table; -/* Initialize attribute table. */ +/* Initialize attribute tables, and make some sanity checks + if --enable-checking. */ static void init_attributes () { - add_attribute (A_PACKED, "packed", 0, 0, 0); - add_attribute (A_NOCOMMON, "nocommon", 0, 0, 1); - add_attribute (A_COMMON, "common", 0, 0, 1); - add_attribute (A_NORETURN, "noreturn", 0, 0, 1); - add_attribute (A_NORETURN, "volatile", 0, 0, 1); - add_attribute (A_UNUSED, "unused", 0, 0, 0); - add_attribute (A_CONST, "const", 0, 0, 1); - add_attribute (A_T_UNION, "transparent_union", 0, 0, 0); - add_attribute (A_CONSTRUCTOR, "constructor", 0, 0, 1); - add_attribute (A_DESTRUCTOR, "destructor", 0, 0, 1); - add_attribute (A_MODE, "mode", 1, 1, 1); - add_attribute (A_SECTION, "section", 1, 1, 1); - add_attribute (A_ALIGNED, "aligned", 0, 1, 0); - add_attribute (A_FORMAT, "format", 3, 3, 1); - add_attribute (A_FORMAT_ARG, "format_arg", 1, 1, 1); - add_attribute (A_WEAK, "weak", 0, 0, 1); - add_attribute (A_ALIAS, "alias", 1, 1, 1); - add_attribute (A_NO_INSTRUMENT_FUNCTION, "no_instrument_function", 0, 0, 1); - add_attribute (A_NO_CHECK_MEMORY_USAGE, "no_check_memory_usage", 0, 0, 1); - add_attribute (A_MALLOC, "malloc", 0, 0, 1); - add_attribute (A_NO_LIMIT_STACK, "no_stack_limit", 0, 0, 1); - add_attribute (A_PURE, "pure", 0, 0, 1); +#ifdef ENABLE_CHECKING + int i; +#endif + attribute_tables[0] = c_common_attribute_table; + attribute_tables[1] = lang_attribute_table; + attribute_tables[2] = targetm.attribute_table; +#ifdef ENABLE_CHECKING + /* Make some sanity checks on the attribute tables. */ + for (i = 0; + i < (int) (sizeof (attribute_tables) / sizeof (attribute_tables[0])); + i++) + { + int j; + for (j = 0; attribute_tables[i][j].name != NULL; j++) + { + /* The name must not begin and end with __. */ + const char *name = attribute_tables[i][j].name; + int len = strlen (name); + if (name[0] == '_' && name[1] == '_' + && name[len - 1] == '_' && name[len - 2] == '_') + abort (); + /* The minimum and maximum lengths must be consistent. */ + 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 (); + /* An attribute cannot require both a DECL and a TYPE. */ + if (attribute_tables[i][j].decl_required + && attribute_tables[i][j].type_required) + abort (); + /* If an attribute requires a function type, in particular + it requires a type. */ + if (attribute_tables[i][j].function_type_required + && !attribute_tables[i][j].type_required) + abort (); + } + } + /* Check that each name occurs just once in each table. */ + for (i = 0; + i < (int) (sizeof (attribute_tables) / sizeof (attribute_tables[0])); + 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 (); + } + /* Check that no name occurs in more than one table. */ + for (i = 0; + i < (int) (sizeof (attribute_tables) / sizeof (attribute_tables[0])); + i++) + { + int j; + for (j = i + 1; + j < (int) (sizeof (attribute_tables) / sizeof (attribute_tables[0])); + j++) + { + int k, l; + 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; } -/* Default implementation of valid_lang_attribute, below. By default, there - are no language-specific attributes. */ - -static int -default_valid_lang_attribute (attr_name, attr_args, decl, type) - tree attr_name ATTRIBUTE_UNUSED; - tree attr_args ATTRIBUTE_UNUSED; - tree decl ATTRIBUTE_UNUSED; - tree type ATTRIBUTE_UNUSED; -{ - return 0; -} - -/* Return a 1 if ATTR_NAME and ATTR_ARGS denote a valid language-specific - attribute for either declaration DECL or type TYPE and 0 otherwise. */ - -int (*valid_lang_attribute) PARAMS ((tree, tree, tree, tree)) - = default_valid_lang_attribute; - /* 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, - it should be modified in place; if a TYPE, a copy should be created. - FLAGS gives further information, in the form of a bitwise OR of flags - in enum attribute_flags from c-common.h. Depending on these flags, - some attributes may be returned to be applied at a later stage (for - example, to apply a decl attribute to the declaration rather than to - its type). */ + it should be modified in place; if a TYPE, a copy should be created + unless ATTR_FLAG_TYPE_IN_PLACE is set in FLAGS. FLAGS gives further + information, in the form of a bitwise OR of flags in enum attribute_flags + from tree.h. Depending on these flags, some attributes may be + returned to be applied at a later stage (for example, to apply + a decl attribute to the declaration rather than to its type). */ tree decl_attributes (node, attributes, flags) tree *node, attributes; - int flags ATTRIBUTE_UNUSED; + int flags; { - tree decl = 0, type = 0; - int is_type = 0; tree a; + tree returned_attrs = NULL_TREE; - if (attrtab_idx == 0) + if (!attributes_initialized) init_attributes (); - if (DECL_P (*node)) - { - decl = *node; - type = TREE_TYPE (decl); - is_type = TREE_CODE (*node) == TYPE_DECL; - } - else if (TYPE_P (*node)) - type = *node, is_type = 1; - (*targetm.insert_attributes) (*node, &attributes); 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; int i; - enum attrs id; - - for (i = 0; i < attrtab_idx; i++) - if (attrtab[i].name == name) - break; - if (i == attrtab_idx) + for (i = 0; + i < (int) (sizeof (attribute_tables) / sizeof (attribute_tables[0])); + i++) { - if (! valid_machine_attribute (name, args, decl, type) - && ! (* valid_lang_attribute) (name, args, decl, type)) - warning ("`%s' attribute directive ignored", - IDENTIFIER_POINTER (name)); - else if (decl != 0) - type = TREE_TYPE (decl); - continue; + 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; } - else if (attrtab[i].decl_req && decl == 0) + + if (spec == NULL) { - warning ("`%s' attribute does not apply to types", + warning ("`%s' attribute directive ignored", IDENTIFIER_POINTER (name)); continue; } - else if (list_length (args) < attrtab[i].min - || list_length (args) > attrtab[i].max) + 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; } - id = attrtab[i].id; - switch (id) + if (spec->decl_required && !DECL_P (*anode)) { - case A_PACKED: - if (is_type) - TYPE_PACKED (type) = 1; - else if (TREE_CODE (decl) == FIELD_DECL) - DECL_PACKED (decl) = 1; - /* We can't set DECL_PACKED for a VAR_DECL, because the bit is - used for DECL_REGISTER. It wouldn't mean anything anyway. */ - else - warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name)); - break; - - case A_NOCOMMON: - if (TREE_CODE (decl) == VAR_DECL) - DECL_COMMON (decl) = 0; - else - warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name)); - break; - - case A_COMMON: - if (TREE_CODE (decl) == VAR_DECL) - DECL_COMMON (decl) = 1; - else - warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name)); - break; - - case A_NORETURN: - if (TREE_CODE (decl) == FUNCTION_DECL) - TREE_THIS_VOLATILE (decl) = 1; - else if (TREE_CODE (type) == POINTER_TYPE - && TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE) - TREE_TYPE (decl) = type - = build_pointer_type - (build_type_variant (TREE_TYPE (type), - TREE_READONLY (TREE_TYPE (type)), 1)); - else - warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name)); - break; - - case A_MALLOC: - if (TREE_CODE (decl) == FUNCTION_DECL) - DECL_IS_MALLOC (decl) = 1; - /* ??? TODO: Support types. */ + if (flags & ((int) ATTR_FLAG_DECL_NEXT + | (int) ATTR_FLAG_FUNCTION_NEXT + | (int) ATTR_FLAG_ARRAY_NEXT)) + { + /* Pass on this attribute to be tried again. */ + returned_attrs = tree_cons (name, args, returned_attrs); + continue; + } else - warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name)); - break; + { + warning ("`%s' attribute does not apply to types", + IDENTIFIER_POINTER (name)); + continue; + } + } - case A_UNUSED: - if (is_type) - if (decl) - TREE_USED (decl) = 1; - else - TREE_USED (type) = 1; - else if (TREE_CODE (decl) == PARM_DECL - || TREE_CODE (decl) == VAR_DECL - || TREE_CODE (decl) == FUNCTION_DECL - || TREE_CODE (decl) == LABEL_DECL) - TREE_USED (decl) = 1; - else - warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name)); - break; + if (spec->type_required && DECL_P (*anode)) + { + anode = &TREE_TYPE (*anode); + } - case A_CONST: - if (TREE_CODE (decl) == FUNCTION_DECL) - TREE_READONLY (decl) = 1; - else if (TREE_CODE (type) == POINTER_TYPE - && TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE) - TREE_TYPE (decl) = type - = build_pointer_type - (build_type_variant (TREE_TYPE (type), 1, - TREE_THIS_VOLATILE (TREE_TYPE (type)))); - else - warning ( "`%s' attribute ignored", IDENTIFIER_POINTER (name)); - break; + 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) + { + /* Pass on this attribute to be tried again. */ + returned_attrs = tree_cons (name, args, returned_attrs); + continue; + } - case A_PURE: - if (TREE_CODE (decl) == FUNCTION_DECL) - DECL_IS_PURE (decl) = 1; - /* ??? TODO: Support types. */ - else - warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name)); - break; + 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 (!no_add_attrs) + { + tree old_attrs; + tree a; - case A_T_UNION: - if (is_type - && TREE_CODE (type) == UNION_TYPE - && (decl == 0 - || (TYPE_FIELDS (type) != 0 - && TYPE_MODE (type) == DECL_MODE (TYPE_FIELDS (type))))) - TYPE_TRANSPARENT_UNION (type) = 1; - else if (decl != 0 && TREE_CODE (decl) == PARM_DECL - && TREE_CODE (type) == UNION_TYPE - && TYPE_MODE (type) == DECL_MODE (TYPE_FIELDS (type))) - DECL_TRANSPARENT_UNION (decl) = 1; + if (DECL_P (*anode)) + old_attrs = DECL_ATTRIBUTES (*anode); else - warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name)); - break; + old_attrs = TYPE_ATTRIBUTES (*anode); - case A_CONSTRUCTOR: - if (TREE_CODE (decl) == FUNCTION_DECL - && TREE_CODE (type) == FUNCTION_TYPE - && decl_function_context (decl) == 0) + for (a = lookup_attribute (spec->name, old_attrs); + a != NULL_TREE; + a = lookup_attribute (spec->name, TREE_CHAIN (a))) { - DECL_STATIC_CONSTRUCTOR (decl) = 1; - TREE_USED (decl) = 1; + if (simple_cst_equal (TREE_VALUE (a), args) == 1) + break; } - else - warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name)); - break; - case A_DESTRUCTOR: - if (TREE_CODE (decl) == FUNCTION_DECL - && TREE_CODE (type) == FUNCTION_TYPE - && decl_function_context (decl) == 0) + if (a == NULL_TREE) { - DECL_STATIC_DESTRUCTOR (decl) = 1; - TREE_USED (decl) = 1; + /* This attribute isn't already in the list. */ + 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)); } - else - warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name)); - break; + } + } - case A_MODE: - if (TREE_CODE (TREE_VALUE (args)) != IDENTIFIER_NODE) - warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name)); - else - { - int j; - const char *p = IDENTIFIER_POINTER (TREE_VALUE (args)); - int len = strlen (p); - enum machine_mode mode = VOIDmode; - tree typefm; - - if (len > 4 && p[0] == '_' && p[1] == '_' - && p[len - 1] == '_' && p[len - 2] == '_') - { - char *newp = (char *) alloca (len - 1); + return returned_attrs; +} - strcpy (newp, &p[2]); - newp[len - 4] = '\0'; - p = newp; - } +/* Handle a "packed" attribute; arguments as in + struct attribute_spec.handler. */ +static tree +handle_packed_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; + if (DECL_P (*node)) + { + if (TREE_CODE (*node) == TYPE_DECL) + type = &TREE_TYPE (*node); + } + else + type = node; + if (type) + { + if (!(flags & (int) ATTR_FLAG_TYPE_IN_PLACE)) + *type = build_type_copy (*type); + TYPE_PACKED (*type) = 1; + } + else if (TREE_CODE (*node) == FIELD_DECL) + DECL_PACKED (*node) = 1; + /* We can't set DECL_PACKED for a VAR_DECL, because the bit is + used for DECL_REGISTER. It wouldn't mean anything anyway. */ + else + { + warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name)); + *no_add_attrs = true; + } - /* Give this decl a type with the specified mode. - First check for the special modes. */ - if (! strcmp (p, "byte")) - mode = byte_mode; - else if (!strcmp (p, "word")) - mode = word_mode; - else if (! strcmp (p, "pointer")) - mode = ptr_mode; - else - for (j = 0; j < NUM_MACHINE_MODES; j++) - if (!strcmp (p, GET_MODE_NAME (j))) - mode = (enum machine_mode) j; - - if (mode == VOIDmode) - error ("unknown machine mode `%s'", p); - else if (0 == (typefm = type_for_mode (mode, - TREE_UNSIGNED (type)))) - error ("no data type for mode `%s'", p); - else - { - if (TYPE_PRECISION (typefm) > (TREE_UNSIGNED (type) - ? TYPE_PRECISION(uintmax_type_node) - : TYPE_PRECISION(intmax_type_node)) - && pedantic) - pedwarn ("type with more precision than %s", - TREE_UNSIGNED (type) ? "uintmax_t" : "intmax_t"); - TREE_TYPE (decl) = type = typefm; - DECL_SIZE (decl) = DECL_SIZE_UNIT (decl) = 0; - if (TREE_CODE (decl) != FIELD_DECL) - layout_decl (decl, 0); - } - } - break; + return NULL_TREE; +} - case A_SECTION: - if (targetm.have_named_sections) - { - if ((TREE_CODE (decl) == FUNCTION_DECL - || TREE_CODE (decl) == VAR_DECL) - && TREE_CODE (TREE_VALUE (args)) == STRING_CST) - { - if (TREE_CODE (decl) == VAR_DECL - && current_function_decl != NULL_TREE - && ! TREE_STATIC (decl)) - error_with_decl (decl, - "section attribute cannot be specified for local variables"); - /* The decl may have already been given a section attribute - from a previous declaration. Ensure they match. */ - else if (DECL_SECTION_NAME (decl) != NULL_TREE - && strcmp (TREE_STRING_POINTER (DECL_SECTION_NAME (decl)), - TREE_STRING_POINTER (TREE_VALUE (args))) != 0) - error_with_decl (*node, - "section of `%s' conflicts with previous declaration"); - else - DECL_SECTION_NAME (decl) = TREE_VALUE (args); - } - else - error_with_decl (*node, - "section attribute not allowed for `%s'"); - } - else - error_with_decl (*node, - "section attributes are not supported for this target"); - break; +/* Handle a "nocommon" attribute; arguments as in + struct attribute_spec.handler. */ +static tree +handle_nocommon_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) == VAR_DECL) + DECL_COMMON (*node) = 0; + else + { + warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name)); + *no_add_attrs = true; + } - case A_ALIGNED: - { - tree align_expr - = (args ? TREE_VALUE (args) - : size_int (BIGGEST_ALIGNMENT / BITS_PER_UNIT)); - int i; - - /* Strip any NOPs of any kind. */ - while (TREE_CODE (align_expr) == NOP_EXPR - || TREE_CODE (align_expr) == CONVERT_EXPR - || TREE_CODE (align_expr) == NON_LVALUE_EXPR) - align_expr = TREE_OPERAND (align_expr, 0); - - if (TREE_CODE (align_expr) != INTEGER_CST) - { - error ("requested alignment is not a constant"); - continue; - } + return NULL_TREE; +} - if ((i = tree_log2 (align_expr)) == -1) - error ("requested alignment is not a power of 2"); - else if (i > HOST_BITS_PER_INT - 2) - error ("requested alignment is too large"); - else if (is_type) - { - /* If we have a TYPE_DECL, then copy the type, so that we - don't accidentally modify a builtin type. See pushdecl. */ - if (decl && TREE_TYPE (decl) != error_mark_node - && DECL_ORIGINAL_TYPE (decl) == NULL_TREE) - { - tree tt = TREE_TYPE (decl); - DECL_ORIGINAL_TYPE (decl) = tt; - tt = build_type_copy (tt); - TYPE_NAME (tt) = decl; - TREE_USED (tt) = TREE_USED (decl); - TREE_TYPE (decl) = tt; - type = tt; - } - - TYPE_ALIGN (type) = (1 << i) * BITS_PER_UNIT; - TYPE_USER_ALIGN (type) = 1; - } - else if (TREE_CODE (decl) != VAR_DECL - && TREE_CODE (decl) != FIELD_DECL) - error_with_decl (decl, - "alignment may not be specified for `%s'"); - else - { - DECL_ALIGN (decl) = (1 << i) * BITS_PER_UNIT; - DECL_USER_ALIGN (decl) = 1; - } - } - break; +/* Handle a "common" attribute; arguments as in + struct attribute_spec.handler. */ +static tree +handle_common_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) == VAR_DECL) + DECL_COMMON (*node) = 1; + else + { + warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name)); + *no_add_attrs = true; + } - case A_FORMAT: - decl_handle_format_attribute (decl, args); - break; + return NULL_TREE; +} - case A_FORMAT_ARG: - decl_handle_format_arg_attribute (decl, args); - break; +/* Handle a "noreturn" attribute; arguments as in + struct attribute_spec.handler. */ +static tree +handle_noreturn_attribute (node, name, args, flags, no_add_attrs) + tree *node; + tree name; + tree args ATTRIBUTE_UNUSED; + int flags ATTRIBUTE_UNUSED; + bool *no_add_attrs; +{ + tree type = TREE_TYPE (*node); + + /* See FIXME comment in c_common_attribute_table. */ + if (TREE_CODE (*node) == FUNCTION_DECL) + TREE_THIS_VOLATILE (*node) = 1; + else if (TREE_CODE (type) == POINTER_TYPE + && TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE) + TREE_TYPE (*node) + = build_pointer_type (build_type_variant (TREE_TYPE (type), + TREE_READONLY (TREE_TYPE (type)), 1)); + else + { + warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name)); + *no_add_attrs = true; + } - case A_WEAK: - declare_weak (decl); - break; + return NULL_TREE; +} - case A_ALIAS: - if ((TREE_CODE (decl) == FUNCTION_DECL && DECL_INITIAL (decl)) - || (TREE_CODE (decl) != FUNCTION_DECL && ! DECL_EXTERNAL (decl))) - error_with_decl (decl, - "`%s' defined both normally and as an alias"); - else if (decl_function_context (decl) == 0) - { - tree id; +/* Handle a "unused" attribute; arguments as in + struct attribute_spec.handler. */ +static tree +handle_unused_attribute (node, name, args, flags, no_add_attrs) + tree *node; + tree name; + tree args ATTRIBUTE_UNUSED; + int flags; + bool *no_add_attrs; +{ + if (DECL_P (*node)) + { + tree decl = *node; + + if (TREE_CODE (decl) == PARM_DECL + || TREE_CODE (decl) == VAR_DECL + || TREE_CODE (decl) == FUNCTION_DECL + || TREE_CODE (decl) == LABEL_DECL + || TREE_CODE (decl) == TYPE_DECL) + TREE_USED (decl) = 1; + else + { + warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name)); + *no_add_attrs = true; + } + } + else + { + if (!(flags & (int) ATTR_FLAG_TYPE_IN_PLACE)) + *node = build_type_copy (*node); + TREE_USED (*node) = 1; + } - id = TREE_VALUE (args); - if (TREE_CODE (id) != STRING_CST) - { - error ("alias arg not a string"); - break; - } - id = get_identifier (TREE_STRING_POINTER (id)); - /* This counts as a use of the object pointed to. */ - TREE_USED (id) = 1; + return NULL_TREE; +} - if (TREE_CODE (decl) == FUNCTION_DECL) - DECL_INITIAL (decl) = error_mark_node; - else - DECL_EXTERNAL (decl) = 0; - assemble_alias (decl, id); - } - else - warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name)); - break; +/* Handle a "const" attribute; arguments as in + struct attribute_spec.handler. */ +static tree +handle_const_attribute (node, name, args, flags, no_add_attrs) + tree *node; + tree name; + tree args ATTRIBUTE_UNUSED; + int flags ATTRIBUTE_UNUSED; + bool *no_add_attrs; +{ + tree type = TREE_TYPE (*node); + + /* See FIXME comment on noreturn in c_common_attribute_table. */ + if (TREE_CODE (*node) == FUNCTION_DECL) + TREE_READONLY (*node) = 1; + else if (TREE_CODE (type) == POINTER_TYPE + && TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE) + TREE_TYPE (*node) + = build_pointer_type (build_type_variant (TREE_TYPE (type), 1, + TREE_THIS_VOLATILE (TREE_TYPE (type)))); + else + { + warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name)); + *no_add_attrs = true; + } - case A_NO_CHECK_MEMORY_USAGE: - if (TREE_CODE (decl) != FUNCTION_DECL) - { - error_with_decl (decl, - "`%s' attribute applies only to functions", - IDENTIFIER_POINTER (name)); - } - else if (DECL_INITIAL (decl)) - { - error_with_decl (decl, - "can't set `%s' attribute after definition", - IDENTIFIER_POINTER (name)); - } - else - DECL_NO_CHECK_MEMORY_USAGE (decl) = 1; - break; + return NULL_TREE; +} - case A_NO_INSTRUMENT_FUNCTION: - if (TREE_CODE (decl) != FUNCTION_DECL) - { - error_with_decl (decl, - "`%s' attribute applies only to functions", - IDENTIFIER_POINTER (name)); - } - else if (DECL_INITIAL (decl)) - { - error_with_decl (decl, - "can't set `%s' attribute after definition", - IDENTIFIER_POINTER (name)); - } - else - DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (decl) = 1; - break; +/* Handle a "transparent_union" attribute; arguments as in + struct attribute_spec.handler. */ +static tree +handle_transparent_union_attribute (node, name, args, flags, no_add_attrs) + tree *node; + tree name; + tree args ATTRIBUTE_UNUSED; + int flags; + bool *no_add_attrs; +{ + tree decl = NULL_TREE; + tree *type = NULL; + int is_type = 0; + + if (DECL_P (*node)) + { + decl = *node; + type = &TREE_TYPE (decl); + is_type = TREE_CODE (*node) == TYPE_DECL; + } + else if (TYPE_P (*node)) + type = node, is_type = 1; + + if (is_type + && TREE_CODE (*type) == UNION_TYPE + && (decl == 0 + || (TYPE_FIELDS (*type) != 0 + && TYPE_MODE (*type) == DECL_MODE (TYPE_FIELDS (*type))))) + { + if (!(flags & (int) ATTR_FLAG_TYPE_IN_PLACE)) + *type = build_type_copy (*type); + TYPE_TRANSPARENT_UNION (*type) = 1; + } + else if (decl != 0 && TREE_CODE (decl) == PARM_DECL + && TREE_CODE (*type) == UNION_TYPE + && TYPE_MODE (*type) == DECL_MODE (TYPE_FIELDS (*type))) + DECL_TRANSPARENT_UNION (decl) = 1; + else + { + warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name)); + *no_add_attrs = true; + } + + return NULL_TREE; +} + +/* Handle a "constructor" attribute; arguments as in + struct attribute_spec.handler. */ +static tree +handle_constructor_attribute (node, name, args, flags, no_add_attrs) + tree *node; + tree name; + tree args ATTRIBUTE_UNUSED; + int flags ATTRIBUTE_UNUSED; + bool *no_add_attrs; +{ + tree decl = *node; + tree type = TREE_TYPE (decl); + + if (TREE_CODE (decl) == FUNCTION_DECL + && TREE_CODE (type) == FUNCTION_TYPE + && decl_function_context (decl) == 0) + { + DECL_STATIC_CONSTRUCTOR (decl) = 1; + TREE_USED (decl) = 1; + } + else + { + warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name)); + *no_add_attrs = true; + } + + return NULL_TREE; +} + +/* Handle a "destructor" attribute; arguments as in + struct attribute_spec.handler. */ +static tree +handle_destructor_attribute (node, name, args, flags, no_add_attrs) + tree *node; + tree name; + tree args ATTRIBUTE_UNUSED; + int flags ATTRIBUTE_UNUSED; + bool *no_add_attrs; +{ + tree decl = *node; + tree type = TREE_TYPE (decl); + + if (TREE_CODE (decl) == FUNCTION_DECL + && TREE_CODE (type) == FUNCTION_TYPE + && decl_function_context (decl) == 0) + { + DECL_STATIC_DESTRUCTOR (decl) = 1; + TREE_USED (decl) = 1; + } + else + { + warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name)); + *no_add_attrs = true; + } + + return NULL_TREE; +} + +/* Handle a "mode" attribute; arguments as in + struct attribute_spec.handler. */ +static tree +handle_mode_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; + tree type = TREE_TYPE (decl); + + *no_add_attrs = true; + + if (TREE_CODE (TREE_VALUE (args)) != IDENTIFIER_NODE) + warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name)); + else + { + int j; + const char *p = IDENTIFIER_POINTER (TREE_VALUE (args)); + int len = strlen (p); + enum machine_mode mode = VOIDmode; + tree typefm; + + if (len > 4 && p[0] == '_' && p[1] == '_' + && p[len - 1] == '_' && p[len - 2] == '_') + { + char *newp = (char *) alloca (len - 1); + + strcpy (newp, &p[2]); + newp[len - 4] = '\0'; + p = newp; + } + + /* Give this decl a type with the specified mode. + First check for the special modes. */ + if (! strcmp (p, "byte")) + mode = byte_mode; + else if (!strcmp (p, "word")) + mode = word_mode; + else if (! strcmp (p, "pointer")) + mode = ptr_mode; + else + for (j = 0; j < NUM_MACHINE_MODES; j++) + if (!strcmp (p, GET_MODE_NAME (j))) + mode = (enum machine_mode) j; + + if (mode == VOIDmode) + error ("unknown machine mode `%s'", p); + else if (0 == (typefm = type_for_mode (mode, + TREE_UNSIGNED (type)))) + error ("no data type for mode `%s'", p); + else + { + if (TYPE_PRECISION (typefm) > (TREE_UNSIGNED (type) + ? TYPE_PRECISION(uintmax_type_node) + : TYPE_PRECISION(intmax_type_node)) + && pedantic) + pedwarn ("type with more precision than %s", + TREE_UNSIGNED (type) ? "uintmax_t" : "intmax_t"); + TREE_TYPE (decl) = type = typefm; + DECL_SIZE (decl) = DECL_SIZE_UNIT (decl) = 0; + if (TREE_CODE (decl) != FIELD_DECL) + layout_decl (decl, 0); + } + } - case A_NO_LIMIT_STACK: - if (TREE_CODE (decl) != FUNCTION_DECL) + return NULL_TREE; +} + +/* Handle a "section" attribute; arguments as in + struct attribute_spec.handler. */ +static tree +handle_section_attribute (node, name, args, flags, no_add_attrs) + tree *node; + tree name ATTRIBUTE_UNUSED; + tree args; + int flags ATTRIBUTE_UNUSED; + bool *no_add_attrs; +{ + tree decl = *node; + + if (targetm.have_named_sections) + { + if ((TREE_CODE (decl) == FUNCTION_DECL + || TREE_CODE (decl) == VAR_DECL) + && TREE_CODE (TREE_VALUE (args)) == STRING_CST) + { + if (TREE_CODE (decl) == VAR_DECL + && current_function_decl != NULL_TREE + && ! TREE_STATIC (decl)) { error_with_decl (decl, - "`%s' attribute applies only to functions", - IDENTIFIER_POINTER (name)); + "section attribute cannot be specified for local variables"); + *no_add_attrs = true; } - else if (DECL_INITIAL (decl)) + /* The decl may have already been given a section attribute + from a previous declaration. Ensure they match. */ + else if (DECL_SECTION_NAME (decl) != NULL_TREE + && strcmp (TREE_STRING_POINTER (DECL_SECTION_NAME (decl)), + TREE_STRING_POINTER (TREE_VALUE (args))) != 0) { - error_with_decl (decl, - "can't set `%s' attribute after definition", - IDENTIFIER_POINTER (name)); + error_with_decl (*node, + "section of `%s' conflicts with previous declaration"); + *no_add_attrs = true; } else - DECL_NO_LIMIT_STACK (decl) = 1; - break; + DECL_SECTION_NAME (decl) = TREE_VALUE (args); + } + else + { + error_with_decl (*node, + "section attribute not allowed for `%s'"); + *no_add_attrs = true; + } + } + else + { + error_with_decl (*node, + "section attributes are not supported for this target"); + *no_add_attrs = true; + } + + return NULL_TREE; +} + +/* Handle a "aligned" attribute; arguments as in + struct attribute_spec.handler. */ +static tree +handle_aligned_attribute (node, name, args, flags, no_add_attrs) + tree *node; + tree name ATTRIBUTE_UNUSED; + tree args; + int flags; + bool *no_add_attrs; +{ + tree decl = NULL_TREE; + tree *type = NULL; + int is_type = 0; + tree align_expr = (args ? TREE_VALUE (args) + : size_int (BIGGEST_ALIGNMENT / BITS_PER_UNIT)); + int i; + + if (DECL_P (*node)) + { + decl = *node; + type = &TREE_TYPE (decl); + is_type = TREE_CODE (*node) == TYPE_DECL; + } + else if (TYPE_P (*node)) + type = node, is_type = 1; + + /* Strip any NOPs of any kind. */ + while (TREE_CODE (align_expr) == NOP_EXPR + || TREE_CODE (align_expr) == CONVERT_EXPR + || TREE_CODE (align_expr) == NON_LVALUE_EXPR) + align_expr = TREE_OPERAND (align_expr, 0); + + if (TREE_CODE (align_expr) != INTEGER_CST) + { + error ("requested alignment is not a constant"); + *no_add_attrs = true; + } + else if ((i = tree_log2 (align_expr)) == -1) + { + error ("requested alignment is not a power of 2"); + *no_add_attrs = true; + } + else if (i > HOST_BITS_PER_INT - 2) + { + error ("requested alignment is too large"); + *no_add_attrs = true; + } + else if (is_type) + { + /* If we have a TYPE_DECL, then copy the type, so that we + don't accidentally modify a builtin type. See pushdecl. */ + if (decl && TREE_TYPE (decl) != error_mark_node + && DECL_ORIGINAL_TYPE (decl) == NULL_TREE) + { + tree tt = TREE_TYPE (decl); + *type = build_type_copy (*type); + DECL_ORIGINAL_TYPE (decl) = tt; + TYPE_NAME (*type) = decl; + TREE_USED (*type) = TREE_USED (decl); + TREE_TYPE (decl) = *type; } + else if (!(flags & (int) ATTR_FLAG_TYPE_IN_PLACE)) + *type = build_type_copy (*type); + + TYPE_ALIGN (*type) = (1 << i) * BITS_PER_UNIT; + TYPE_USER_ALIGN (*type) = 1; + } + else if (TREE_CODE (decl) != VAR_DECL + && TREE_CODE (decl) != FIELD_DECL) + { + error_with_decl (decl, + "alignment may not be specified for `%s'"); + *no_add_attrs = true; + } + else + { + DECL_ALIGN (decl) = (1 << i) * BITS_PER_UNIT; + DECL_USER_ALIGN (decl) = 1; + } + + return NULL_TREE; +} + +/* Handle a "weak" attribute; arguments as in + struct attribute_spec.handler. */ +static tree +handle_weak_attribute (node, name, args, flags, no_add_attrs) + tree *node; + tree name ATTRIBUTE_UNUSED; + tree args ATTRIBUTE_UNUSED; + int flags ATTRIBUTE_UNUSED; + bool *no_add_attrs ATTRIBUTE_UNUSED; +{ + declare_weak (*node); + + return NULL_TREE; +} + +/* Handle an "alias" attribute; arguments as in + struct attribute_spec.handler. */ +static tree +handle_alias_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 ((TREE_CODE (decl) == FUNCTION_DECL && DECL_INITIAL (decl)) + || (TREE_CODE (decl) != FUNCTION_DECL && ! DECL_EXTERNAL (decl))) + { + error_with_decl (decl, + "`%s' defined both normally and as an alias"); + *no_add_attrs = true; + } + else if (decl_function_context (decl) == 0) + { + tree id; + + id = TREE_VALUE (args); + if (TREE_CODE (id) != STRING_CST) + { + error ("alias arg not a string"); + *no_add_attrs = true; + return NULL_TREE; + } + id = get_identifier (TREE_STRING_POINTER (id)); + /* This counts as a use of the object pointed to. */ + TREE_USED (id) = 1; + + if (TREE_CODE (decl) == FUNCTION_DECL) + DECL_INITIAL (decl) = error_mark_node; + else + DECL_EXTERNAL (decl) = 0; + assemble_alias (decl, id); + } + else + { + warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name)); + *no_add_attrs = true; + } + + return NULL_TREE; +} + +/* Handle a "no_instrument_function" attribute; arguments as in + struct attribute_spec.handler. */ +static tree +handle_no_instrument_function_attribute (node, name, args, flags, no_add_attrs) + tree *node; + tree name; + tree args ATTRIBUTE_UNUSED; + int flags ATTRIBUTE_UNUSED; + bool *no_add_attrs; +{ + tree decl = *node; + + if (TREE_CODE (decl) != FUNCTION_DECL) + { + error_with_decl (decl, + "`%s' attribute applies only to functions", + IDENTIFIER_POINTER (name)); + *no_add_attrs = true; + } + else if (DECL_INITIAL (decl)) + { + error_with_decl (decl, + "can't set `%s' attribute after definition", + IDENTIFIER_POINTER (name)); + *no_add_attrs = true; + } + else + DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (decl) = 1; + + return NULL_TREE; +} + +/* Handle a "no_check_memory_usage" attribute; arguments as in + struct attribute_spec.handler. */ +static tree +handle_no_check_memory_usage_attribute (node, name, args, flags, no_add_attrs) + tree *node; + tree name; + tree args ATTRIBUTE_UNUSED; + int flags ATTRIBUTE_UNUSED; + bool *no_add_attrs; +{ + tree decl = *node; + + if (TREE_CODE (decl) != FUNCTION_DECL) + { + error_with_decl (decl, + "`%s' attribute applies only to functions", + IDENTIFIER_POINTER (name)); + *no_add_attrs = true; + } + else if (DECL_INITIAL (decl)) + { + error_with_decl (decl, + "can't set `%s' attribute after definition", + IDENTIFIER_POINTER (name)); + *no_add_attrs = true; } + else + DECL_NO_CHECK_MEMORY_USAGE (decl) = 1; + + return NULL_TREE; +} + +/* Handle a "malloc" attribute; arguments as in + struct attribute_spec.handler. */ +static tree +handle_malloc_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) + DECL_IS_MALLOC (*node) = 1; + /* ??? TODO: Support types. */ + else + { + warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name)); + *no_add_attrs = true; + } + + return NULL_TREE; +} + +/* Handle a "no_limit_stack" attribute; arguments as in + struct attribute_spec.handler. */ +static tree +handle_no_limit_stack_attribute (node, name, args, flags, no_add_attrs) + tree *node; + tree name; + tree args ATTRIBUTE_UNUSED; + int flags ATTRIBUTE_UNUSED; + bool *no_add_attrs; +{ + tree decl = *node; + + if (TREE_CODE (decl) != FUNCTION_DECL) + { + error_with_decl (decl, + "`%s' attribute applies only to functions", + IDENTIFIER_POINTER (name)); + *no_add_attrs = true; + } + else if (DECL_INITIAL (decl)) + { + error_with_decl (decl, + "can't set `%s' attribute after definition", + IDENTIFIER_POINTER (name)); + *no_add_attrs = true; + } + else + DECL_NO_LIMIT_STACK (decl) = 1; + + return NULL_TREE; +} + +/* Handle a "pure" attribute; arguments as in + struct attribute_spec.handler. */ +static tree +handle_pure_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) + DECL_IS_PURE (*node) = 1; + /* ??? TODO: Support types. */ + else + { + warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name)); + *no_add_attrs = true; + } + return NULL_TREE; } |