diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 6ebf1c6508f..00a52178849 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,185 @@ +2001-09-21 Joseph S. Myers + + 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. + Fri Sep 21 01:49:41 2001 J"orn Rennecke * sh-protos.h (sh_pr_n_sets): Declare. diff --git a/gcc/Makefile.in b/gcc/Makefile.in index db4dfcdcafb..ddde078f723 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -1436,7 +1436,7 @@ real.o : real.c $(CONFIG_H) $(SYSTEM_H) $(TREE_H) toplev.h $(TM_P_H) integrate.o : integrate.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) $(TREE_H) flags.h \ debug.h $(INTEGRATE_H) insn-config.h $(EXPR_H) real.h $(REGS_H) \ intl.h function.h output.h $(RECOG_H) except.h toplev.h $(LOOP_H) \ - $(PARAMS_H) $(TM_P_H) + $(PARAMS_H) $(TM_P_H) $(TARGET_H) jump.o : jump.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) flags.h hard-reg-set.h $(REGS_H) \ insn-config.h $(RECOG_H) $(EXPR_H) real.h except.h function.h \ toplev.h $(INSN_ATTR_H) $(TM_P_H) reload.h $(PREDICT_H) diff --git a/gcc/c-common.c b/gcc/c-common.c index 1515e45c34f..8d00cfed7c5 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. */ +/* Table of the tables of attributes (common, language, machine) searched. */ +static const struct attribute_spec *attribute_tables[3]; -/* Array to hold attribute information. */ +static bool attributes_initialized = false; -static struct {enum attrs id; tree name; int min, max, decl_req;} attrtab[50]; +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 *)); -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 machine-independent attributes common to all C-like languages. */ +static const struct attribute_spec c_common_attribute_table[] = { - char buf[100]; + /* { 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 } +}; - 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; +/* Default empty table of language attributes. */ +static const struct attribute_spec default_lang_attribute_table[] = +{ + { NULL, 0, 0, false, false, false, NULL } +}; - sprintf (buf, "__%s__", string); +/* Table of machine-independent attributes for a particular language. */ +const struct attribute_spec *lang_attribute_table = default_lang_attribute_table; - 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; -} - -/* 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. */ - else - warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name)); - break; - - 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; - - 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; - - 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; - - - 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; - else - warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name)); - break; - - case A_CONSTRUCTOR: - if (TREE_CODE (decl) == FUNCTION_DECL - && TREE_CODE (type) == FUNCTION_TYPE - && decl_function_context (decl) == 0) + if (flags & ((int) ATTR_FLAG_DECL_NEXT + | (int) ATTR_FLAG_FUNCTION_NEXT + | (int) ATTR_FLAG_ARRAY_NEXT)) { - DECL_STATIC_CONSTRUCTOR (decl) = 1; - TREE_USED (decl) = 1; + /* 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; - - case A_DESTRUCTOR: - 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; + warning ("`%s' attribute does not apply to types", + IDENTIFIER_POINTER (name)); + continue; } - 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 + if (spec->type_required && DECL_P (*anode)) + { + anode = &TREE_TYPE (*anode); + } + + 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)) { - int j; - const char *p = IDENTIFIER_POINTER (TREE_VALUE (args)); - int len = strlen (p); - enum machine_mode mode = VOIDmode; - tree typefm; + 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; + } - if (len > 4 && p[0] == '_' && p[1] == '_' - && p[len - 1] == '_' && p[len - 2] == '_') - { - char *newp = (char *) alloca (len - 1); + if (TREE_CODE (*anode) != FUNCTION_TYPE + && TREE_CODE (*anode) != METHOD_TYPE) + { + warning ("`%s' attribute only applies to function types", + IDENTIFIER_POINTER (name)); + continue; + } + } - strcpy (newp, &p[2]); - newp[len - 4] = '\0'; - p = newp; - } + 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; - /* 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; + 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) + { + /* 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 - 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); - } + *anode = build_type_attribute_variant (*anode, + tree_cons (name, args, + old_attrs)); } - break; - - 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; - - 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; - } - - 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; - - case A_FORMAT: - decl_handle_format_attribute (decl, args); - break; - - case A_FORMAT_ARG: - decl_handle_format_arg_attribute (decl, args); - break; - - case A_WEAK: - declare_weak (decl); - break; - - 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; - - 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; - - 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; - - 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; - - 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; - - case A_NO_LIMIT_STACK: - 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_LIMIT_STACK (decl) = 1; - break; } } + + return returned_attrs; +} + +/* 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; + } + + return NULL_TREE; +} + +/* 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; + } + + return NULL_TREE; +} + +/* 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; + } + + return NULL_TREE; +} + +/* 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; + } + + return NULL_TREE; +} + +/* 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; + } + + return NULL_TREE; +} + +/* 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; + } + + return NULL_TREE; +} + +/* 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); + } + } + + 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, + "section attribute cannot be specified for local variables"); + *no_add_attrs = true; + } + /* 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"); + *no_add_attrs = true; + } + else + 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; } diff --git a/gcc/c-common.h b/gcc/c-common.h index 26933b74f63..6ab2c06bef3 100644 --- a/gcc/c-common.h +++ b/gcc/c-common.h @@ -503,29 +503,14 @@ extern const char *fname_as_string PARAMS ((int)); extern tree fname_decl PARAMS ((unsigned, tree)); extern const char *fname_string PARAMS ((unsigned)); -/* Flags that may be passed in the third argument of decl_attributes. */ -enum attribute_flags -{ - /* The type passed in is the type of a DECL, and any attributes that - should be passed in again to be applied to the DECL rather than the - type should be returned. */ - ATTR_FLAG_DECL_NEXT = 1, - /* The type passed in is a function return type, and any attributes that - should be passed in again to be applied to the function type rather - than the return type should be returned. */ - ATTR_FLAG_FUNCTION_NEXT = 2, - /* The type passed in is an array element type, and any attributes that - should be passed in again to be applied to the array type rather - than the element type should be returned. */ - ATTR_FLAG_ARRAY_NEXT = 4 -}; - extern tree decl_attributes PARAMS ((tree *, tree, int)); extern void init_function_format_info PARAMS ((void)); extern void check_function_format PARAMS ((int *, tree, tree, tree)); extern void set_Wformat PARAMS ((int)); -extern void decl_handle_format_attribute PARAMS ((tree, tree)); -extern void decl_handle_format_arg_attribute PARAMS ((tree, tree)); +extern tree handle_format_attribute PARAMS ((tree *, tree, tree, + int, bool *)); +extern tree handle_format_arg_attribute PARAMS ((tree *, tree, tree, + int, bool *)); extern void c_apply_type_quals_to_decl PARAMS ((int, tree)); extern tree c_sizeof PARAMS ((tree)); extern tree c_alignof PARAMS ((tree)); diff --git a/gcc/c-decl.c b/gcc/c-decl.c index d0beb0f6926..4652267c667 100644 --- a/gcc/c-decl.c +++ b/gcc/c-decl.c @@ -1404,7 +1404,7 @@ duplicate_decls (newdecl, olddecl, different_binding_level) int errmsg = 0; if (DECL_P (olddecl)) - DECL_MACHINE_ATTRIBUTES (newdecl) + DECL_ATTRIBUTES (newdecl) = (*targetm.merge_decl_attributes) (olddecl, newdecl); if (TREE_CODE (newtype) == ERROR_MARK @@ -2030,7 +2030,7 @@ duplicate_decls (newdecl, olddecl, different_binding_level) /* NEWDECL contains the merged attribute lists. Update OLDDECL to be the same. */ - DECL_MACHINE_ATTRIBUTES (olddecl) = DECL_MACHINE_ATTRIBUTES (newdecl); + DECL_ATTRIBUTES (olddecl) = DECL_ATTRIBUTES (newdecl); return 1; } @@ -3872,9 +3872,10 @@ grokdeclarator (declarator, declspecs, decl_context, initialized) enum tree_code innermost_code = ERROR_MARK; int bitfield = 0; int size_varies = 0; - tree decl_machine_attr = NULL_TREE; + tree decl_attr = NULL_TREE; tree array_ptr_quals = NULL_TREE; int array_parm_static = 0; + tree returned_attrs = NULL_TREE; if (decl_context == BITFIELD) bitfield = 1, decl_context = FIELD; @@ -3898,6 +3899,10 @@ grokdeclarator (declarator, declspecs, decl_context, initialized) decl = TREE_OPERAND (decl, 0); break; + case TREE_LIST: + decl = TREE_VALUE (decl); + break; + case IDENTIFIER_NODE: name = IDENTIFIER_POINTER (decl); decl = 0; @@ -3979,7 +3984,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized) else if (TREE_CODE (id) == TYPE_DECL) { type = TREE_TYPE (id); - decl_machine_attr = DECL_MACHINE_ATTRIBUTES (id); + decl_attr = DECL_ATTRIBUTES (id); typedef_decl = id; } /* Built-in types come as identifiers. */ @@ -4292,6 +4297,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized) /* Each level of DECLARATOR is either an ARRAY_REF (for ...[..]), an INDIRECT_REF (for *...), a CALL_EXPR (for ...(...)), + a TREE_LIST (for nested attributes), an identifier (for the name being declared) or a null pointer (for the place in an absolute declarator where the name was omitted). @@ -4313,7 +4319,30 @@ grokdeclarator (declarator, declspecs, decl_context, initialized) array_parm_static = 0; } - if (TREE_CODE (declarator) == ARRAY_REF) + if (TREE_CODE (declarator) == TREE_LIST) + { + /* We encode a declarator with embedded attributes using + a TREE_LIST. */ + tree attrs = TREE_PURPOSE (declarator); + tree inner_decl; + int attr_flags = 0; + declarator = TREE_VALUE (declarator); + inner_decl = declarator; + while (inner_decl != NULL_TREE + && TREE_CODE (inner_decl) == TREE_LIST) + inner_decl = TREE_VALUE (inner_decl); + if (inner_decl == NULL_TREE + || TREE_CODE (inner_decl) == IDENTIFIER_NODE) + attr_flags |= (int) ATTR_FLAG_DECL_NEXT; + if (TREE_CODE (inner_decl) == CALL_EXPR) + attr_flags |= (int) ATTR_FLAG_FUNCTION_NEXT; + if (TREE_CODE (inner_decl) == ARRAY_REF) + attr_flags |= (int) ATTR_FLAG_ARRAY_NEXT; + returned_attrs = decl_attributes (&type, + chainon (returned_attrs, attrs), + attr_flags); + } + else if (TREE_CODE (declarator) == ARRAY_REF) { register tree itype = NULL_TREE; register tree size = TREE_OPERAND (declarator, 1); @@ -4657,6 +4686,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized) if ((specbits & (1 << (int) RID_SIGNED)) || (typedef_decl && C_TYPEDEF_EXPLICITLY_SIGNED (typedef_decl))) C_TYPEDEF_EXPLICITLY_SIGNED (decl) = 1; + decl_attributes (&decl, returned_attrs, 0); return decl; } @@ -4687,6 +4717,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized) pedwarn ("ISO C forbids const or volatile function types"); if (type_quals) type = c_build_qualified_type (type, type_quals); + decl_attributes (&type, returned_attrs, 0); return type; } @@ -4711,7 +4742,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized) or a FUNCTION_DECL, depending on DECL_CONTEXT and TYPE. */ { - register tree decl; + tree decl; if (decl_context == PARM) { @@ -4860,7 +4891,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized) pedwarn ("invalid storage class for function `%s'", name); decl = build_decl (FUNCTION_DECL, declarator, type); - decl = build_decl_attribute_variant (decl, decl_machine_attr); + decl = build_decl_attribute_variant (decl, decl_attr); if (pedantic && type_quals && ! DECL_IN_SYSTEM_HEADER (decl)) pedwarn ("ISO C forbids qualified function types"); @@ -4953,6 +4984,8 @@ grokdeclarator (declarator, declspecs, decl_context, initialized) if (C_TYPE_FIELDS_VOLATILE (TREE_TYPE (decl))) mark_addressable (decl); + decl_attributes (&decl, returned_attrs, 0); + return decl; } } @@ -5341,7 +5374,7 @@ finish_struct (t, fieldlist, attributes) TYPE_SIZE (t) = 0; - decl_attributes (&t, attributes, 0); + decl_attributes (&t, attributes, (int) ATTR_FLAG_TYPE_IN_PLACE); /* Nameless union parm types are useful as GCC extension. */ if (! (TREE_CODE (t) == UNION_TYPE && TYPE_NAME (t) == 0) && !pedantic) @@ -5705,7 +5738,7 @@ finish_enum (enumtype, values, attributes) if (in_parm_level_p ()) warning ("enum defined inside parms"); - decl_attributes (&enumtype, attributes, 0); + decl_attributes (&enumtype, attributes, (int) ATTR_FLAG_TYPE_IN_PLACE); /* Calculate the maximum value of any enumerator in this type. */ diff --git a/gcc/c-format.c b/gcc/c-format.c index d7ef210e4d4..331cd252e8f 100644 --- a/gcc/c-format.c +++ b/gcc/c-format.c @@ -82,14 +82,17 @@ static void record_function_format PARAMS ((tree, tree, enum format_type, int, int)); static void record_international_format PARAMS ((tree, tree, int)); -/* Handle the format attribute (with arguments ARGS) attached to the decl - DECL. It is already verified that DECL is a decl and ARGS contains - exactly three arguments. */ - -void -decl_handle_format_attribute (decl, args) - tree decl, args; +/* Handle a "format" attribute; arguments as in + struct attribute_spec.handler. */ +tree +handle_format_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; tree type = TREE_TYPE (decl); tree format_type_id = TREE_VALUE (args); tree format_num_expr = TREE_VALUE (TREE_CHAIN (args)); @@ -104,13 +107,15 @@ decl_handle_format_attribute (decl, args) { error_with_decl (decl, "argument format specified for non-function `%s'"); - return; + *no_add_attrs = true; + return NULL_TREE; } if (TREE_CODE (format_type_id) != IDENTIFIER_NODE) { error ("unrecognized format specifier"); - return; + *no_add_attrs = true; + return NULL_TREE; } else { @@ -121,7 +126,8 @@ decl_handle_format_attribute (decl, args) if (format_type == format_type_error) { warning ("`%s' is an unrecognized format function type", p); - return; + *no_add_attrs = true; + return NULL_TREE; } } @@ -143,7 +149,8 @@ decl_handle_format_attribute (decl, args) || TREE_INT_CST_HIGH (first_arg_num_expr) != 0) { error ("format string has invalid operand number"); - return; + *no_add_attrs = true; + return NULL_TREE; } format_num = TREE_INT_CST_LOW (format_num_expr); @@ -151,7 +158,8 @@ decl_handle_format_attribute (decl, args) if (first_arg_num != 0 && first_arg_num <= format_num) { error ("format string arg follows the args to be formatted"); - return; + *no_add_attrs = true; + return NULL_TREE; } /* If a parameter list is specified, verify that the format_num @@ -170,7 +178,8 @@ decl_handle_format_attribute (decl, args) != char_type_node)) { error ("format string arg not a string type"); - return; + *no_add_attrs = true; + return NULL_TREE; } else if (first_arg_num != 0) @@ -183,7 +192,8 @@ decl_handle_format_attribute (decl, args) if (arg_num != first_arg_num) { error ("args to be formatted is not '...'"); - return; + *no_add_attrs = true; + return NULL_TREE; } } } @@ -191,22 +201,27 @@ decl_handle_format_attribute (decl, args) if (format_type == strftime_format_type && first_arg_num != 0) { error ("strftime formats cannot format arguments"); - return; + *no_add_attrs = true; + return NULL_TREE; } record_function_format (DECL_NAME (decl), DECL_ASSEMBLER_NAME (decl), format_type, format_num, first_arg_num); + return NULL_TREE; } -/* Handle the format_arg attribute (with arguments ARGS) attached to - the decl DECL. It is already verified that DECL is a decl and - ARGS contains exactly one argument. */ - -void -decl_handle_format_arg_attribute (decl, args) - tree decl, args; +/* Handle a "format" attribute; arguments as in + struct attribute_spec.handler. */ +tree +handle_format_arg_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; tree type = TREE_TYPE (decl); tree format_num_expr = TREE_VALUE (args); unsigned HOST_WIDE_INT format_num; @@ -217,7 +232,8 @@ decl_handle_format_arg_attribute (decl, args) { error_with_decl (decl, "argument format specified for non-function `%s'"); - return; + *no_add_attrs = true; + return NULL_TREE; } /* Strip any conversions from the first arg number and verify it @@ -231,7 +247,8 @@ decl_handle_format_arg_attribute (decl, args) || TREE_INT_CST_HIGH (format_num_expr) != 0) { error ("format string has invalid operand number"); - return; + *no_add_attrs = true; + return NULL_TREE; } format_num = TREE_INT_CST_LOW (format_num_expr); @@ -252,7 +269,8 @@ decl_handle_format_arg_attribute (decl, args) != char_type_node)) { error ("format string arg not a string type"); - return; + *no_add_attrs = true; + return NULL_TREE; } } @@ -261,11 +279,13 @@ decl_handle_format_arg_attribute (decl, args) != char_type_node)) { error ("function does not return string type"); - return; + *no_add_attrs = true; + return NULL_TREE; } record_international_format (DECL_NAME (decl), DECL_ASSEMBLER_NAME (decl), format_num); + return NULL_TREE; } typedef struct function_format_info diff --git a/gcc/c-parse.in b/gcc/c-parse.in index 0d76c3e5966..85c2815409d 100644 --- a/gcc/c-parse.in +++ b/gcc/c-parse.in @@ -173,7 +173,7 @@ end ifc %type declspecs_ts declspecs_nots %type declspecs_ts_nosa declspecs_nots_nosa %type declspecs_nosc_ts declspecs_nosc_nots declspecs_nosc declspecs -%type maybe_type_quals_setattrs typespec_nonattr typespec_attr +%type maybe_type_quals_attrs typespec_nonattr typespec_attr %type typespec_reserved_nonattr typespec_reserved_attr %type typespec_nonreserved_nonattr @@ -182,7 +182,6 @@ end ifc %type init maybeasm %type asm_operands nonnull_asm_operands asm_operand asm_clobbers %type maybe_attribute attributes attribute attribute_list attrib -%type maybe_setattrs %type any_word extension %type compstmt compstmt_start compstmt_nostart compstmt_primary_start @@ -847,29 +846,11 @@ setspecs: /* empty */ all_prefix_attributes = prefix_attributes; } ; -/* ??? Yuck. See maybe_setattrs. */ -setattrs: /* empty */ - { all_prefix_attributes = chainon ($0, all_prefix_attributes); } - ; - -maybe_setattrs: - /* ??? Yuck. setattrs is a quick hack. We can't use - prefix_attributes because $1 only applies to this - declarator. We assume setspecs has already been done. - setattrs also avoids 5 reduce/reduce conflicts (otherwise multiple - attributes could be recognized here or in `attributes'). - Properly attributes ought to be able to apply to any level of - nested declarator, but the necessary compiler support isn't - present, so the attributes apply to a declaration (which may be - nested). */ - maybe_attribute setattrs - ; - /* Possibly attributes after a comma, which should reset all_prefix_attributes to prefix_attributes with these ones chained on the front. */ maybe_resetattrs: - { all_prefix_attributes = prefix_attributes; } - maybe_setattrs + maybe_attribute + { all_prefix_attributes = chainon ($1, prefix_attributes); } ; decl: @@ -1347,18 +1328,12 @@ declspecs: | declspecs_sc_ts_sa_ea ; -/* A (possibly empty) sequence of type qualifiers and attributes, to be - followed by the effect of setattrs if any attributes were present. */ -maybe_type_quals_setattrs: +/* A (possibly empty) sequence of type qualifiers and attributes. */ +maybe_type_quals_attrs: /* empty */ { $$ = NULL_TREE; } | declspecs_nosc_nots - { tree specs, attrs; - split_specs_attrs ($1, &specs, &attrs); - /* ??? Yuck. See maybe_setattrs. */ - if (attrs != NULL_TREE) - all_prefix_attributes = chainon (attrs, all_prefix_attributes); - $$ = specs; } + { $$ = $1; } ; /* A type specifier (but not a type qualifier). @@ -1669,8 +1644,8 @@ declarator: /* A declarator that is allowed only after an explicit typespec. */ after_type_declarator: - '(' maybe_setattrs after_type_declarator ')' - { $$ = $3; } + '(' maybe_attribute after_type_declarator ')' + { $$ = $2 ? tree_cons ($2, $3, NULL_TREE) : $3; } | after_type_declarator '(' parmlist_or_identifiers %prec '.' { $$ = build_nt (CALL_EXPR, $1, $3, NULL_TREE); } /* | after_type_declarator '(' error ')' %prec '.' @@ -1678,7 +1653,7 @@ after_type_declarator: poplevel (0, 0, 0); } */ | after_type_declarator array_declarator %prec '.' { $$ = set_array_declarator_type ($2, $1, 0); } - | '*' maybe_type_quals_setattrs after_type_declarator %prec UNARY + | '*' maybe_type_quals_attrs after_type_declarator %prec UNARY { $$ = make_pointer_declarator ($2, $3); } | TYPENAME ifobjc @@ -1717,12 +1692,12 @@ parm_declarator_nostarttypename: poplevel (0, 0, 0); } */ | parm_declarator_nostarttypename array_declarator %prec '.' { $$ = set_array_declarator_type ($2, $1, 0); } - | '*' maybe_type_quals_setattrs parm_declarator_starttypename %prec UNARY + | '*' maybe_type_quals_attrs parm_declarator_starttypename %prec UNARY { $$ = make_pointer_declarator ($2, $3); } - | '*' maybe_type_quals_setattrs parm_declarator_nostarttypename %prec UNARY + | '*' maybe_type_quals_attrs parm_declarator_nostarttypename %prec UNARY { $$ = make_pointer_declarator ($2, $3); } - | '(' maybe_setattrs parm_declarator_nostarttypename ')' - { $$ = $3; } + | '(' maybe_attribute parm_declarator_nostarttypename ')' + { $$ = $2 ? tree_cons ($2, $3, NULL_TREE) : $3; } ; /* A declarator allowed whether or not there has been @@ -1734,9 +1709,9 @@ notype_declarator: /* | notype_declarator '(' error ')' %prec '.' { $$ = build_nt (CALL_EXPR, $1, NULL_TREE, NULL_TREE); poplevel (0, 0, 0); } */ - | '(' maybe_setattrs notype_declarator ')' - { $$ = $3; } - | '*' maybe_type_quals_setattrs notype_declarator %prec UNARY + | '(' maybe_attribute notype_declarator ')' + { $$ = $2 ? tree_cons ($2, $3, NULL_TREE) : $3; } + | '*' maybe_type_quals_attrs notype_declarator %prec UNARY { $$ = make_pointer_declarator ($2, $3); } | notype_declarator array_declarator %prec '.' { $$ = set_array_declarator_type ($2, $1, 0); } @@ -1991,20 +1966,20 @@ absdcl1: /* a nonempty absolute declarator */ absdcl1_noea: direct_absdcl1 - | '*' maybe_type_quals_setattrs absdcl1_noea + | '*' maybe_type_quals_attrs absdcl1_noea { $$ = make_pointer_declarator ($2, $3); } ; absdcl1_ea: - '*' maybe_type_quals_setattrs + '*' maybe_type_quals_attrs { $$ = make_pointer_declarator ($2, NULL_TREE); } - | '*' maybe_type_quals_setattrs absdcl1_ea + | '*' maybe_type_quals_attrs absdcl1_ea { $$ = make_pointer_declarator ($2, $3); } ; direct_absdcl1: - '(' maybe_setattrs absdcl1 ')' - { $$ = $3; } + '(' maybe_attribute absdcl1 ')' + { $$ = $2 ? tree_cons ($2, $3, NULL_TREE) : $3; } | direct_absdcl1 '(' parmlist { $$ = build_nt (CALL_EXPR, $1, $3, NULL_TREE); } | direct_absdcl1 array_declarator @@ -3904,15 +3879,21 @@ yyprint (file, yychar, yyl) /* Return something to represent absolute declarators containing a *. TARGET is the absolute declarator that the * contains. - TYPE_QUALS is a list of modifiers such as const or volatile - to apply to the pointer type, represented as identifiers. + TYPE_QUALS_ATTRS is a list of modifiers such as const or volatile + to apply to the pointer type, represented as identifiers, possible mixed + with attributes. - We return an INDIRECT_REF whose "contents" are TARGET - and whose type is the modifier list. */ + We return an INDIRECT_REF whose "contents" are TARGET (inside a TREE_LIST, + if attributes are present) and whose type is the modifier list. */ tree -make_pointer_declarator (type_quals, target) - tree type_quals, target; +make_pointer_declarator (type_quals_attrs, target) + tree type_quals_attrs, target; { - return build1 (INDIRECT_REF, type_quals, target); + tree quals, attrs; + tree itarget = target; + split_specs_attrs (type_quals_attrs, &quals, &attrs); + if (attrs != NULL_TREE) + itarget = tree_cons (attrs, target, NULL_TREE); + return build1 (INDIRECT_REF, quals, itarget); } diff --git a/gcc/config/alpha/alpha.c b/gcc/config/alpha/alpha.c index 79c247b5189..4439368242f 100644 --- a/gcc/config/alpha/alpha.c +++ b/gcc/config/alpha/alpha.c @@ -181,13 +181,13 @@ static int unicosmk_need_dex PARAMS ((rtx)); /* Initialize the GCC target structure. */ #if TARGET_ABI_OPEN_VMS -static int vms_valid_decl_attribute_p PARAMS ((tree, tree, tree, tree)); +const struct attribute_spec vms_attribute_table[]; static unsigned int vms_section_type_flags PARAMS ((tree, const char *, int)); static void vms_asm_named_section PARAMS ((const char *, unsigned int)); static void vms_asm_out_constructor PARAMS ((rtx, int)); static void vms_asm_out_destructor PARAMS ((rtx, int)); -# undef TARGET_VALID_DECL_ATTRIBUTE -# define TARGET_VALID_DECL_ATTRIBUTE vms_valid_decl_attribute_p +# undef TARGET_ATTRIBUTE_TABLE +# define TARGET_ATTRIBUTE_TABLE vms_attribute_table # undef TARGET_SECTION_TYPE_FLAGS # define TARGET_SECTION_TYPE_FLAGS vms_section_type_flags #endif @@ -5732,17 +5732,12 @@ alpha_using_fp () #if TARGET_ABI_OPEN_VMS -static int -vms_valid_decl_attribute_p (decl, attributes, identifier, args) - tree decl ATTRIBUTE_UNUSED; - tree attributes ATTRIBUTE_UNUSED; - tree identifier; - tree args; +const struct attribute_spec vms_attribute_table[] = { - if (is_attribute_p ("overlaid", identifier)) - return (args == NULL_TREE); - return 0; -} + /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */ + { "overlaid", 0, 0, true, false, false, NULL }, + { NULL, 0, 0, false, false, false, NULL } +}; #endif @@ -7895,8 +7890,8 @@ vms_section_type_flags (decl, name, reloc) { unsigned int flags = default_section_type_flags (decl, name, reloc); - if (decl && DECL_MACHINE_ATTRIBUTES (decl) - && lookup_attribute ("overlaid", DECL_MACHINE_ATTRIBUTES (decl))) + if (decl && DECL_ATTRIBUTES (decl) + && lookup_attribute ("overlaid", DECL_ATTRIBUTES (decl))) flags |= SECTION_VMS_OVERLAY; return flags; diff --git a/gcc/config/arc/arc.c b/gcc/config/arc/arc.c index 0fe070be9a2..6875a6f502c 100644 --- a/gcc/config/arc/arc.c +++ b/gcc/config/arc/arc.c @@ -87,7 +87,8 @@ static int current_insn_set_cc_p; static void record_cc_ref PARAMS ((rtx)); static void arc_init_reg_tables PARAMS ((void)); static int get_arc_condition_code PARAMS ((rtx)); -static int arc_valid_decl_attribute PARAMS ((tree, tree, tree, tree)); +const struct attribute_spec arc_attribute_table[]; +static tree arc_handle_interrupt_attribute PARAMS ((tree *, tree, tree, int, bool *)); static void arc_output_function_prologue PARAMS ((FILE *, HOST_WIDE_INT)); static void arc_output_function_epilogue PARAMS ((FILE *, HOST_WIDE_INT)); @@ -96,8 +97,8 @@ static void arc_output_function_epilogue PARAMS ((FILE *, HOST_WIDE_INT)); #define TARGET_ASM_FUNCTION_PROLOGUE arc_output_function_prologue #undef TARGET_ASM_FUNCTION_EPILOGUE #define TARGET_ASM_FUNCTION_EPILOGUE arc_output_function_epilogue -#undef TARGET_VALID_DECL_ATTRIBUTE -#define TARGET_VALID_DECL_ATTRIBUTE arc_valid_decl_attribute +#undef TARGET_ATTRIBUTE_TABLE +#define TARGET_ATTRIBUTE_TABLE arc_attribute_table struct gcc_target targetm = TARGET_INITIALIZER; @@ -326,26 +327,40 @@ arc_init_reg_tables () interrupt - for interrupt functions */ -/* Return nonzero if IDENTIFIER is a valid decl attribute. */ - -static int -arc_valid_decl_attribute (type, attributes, identifier, args) - tree type ATTRIBUTE_UNUSED; - tree attributes ATTRIBUTE_UNUSED; - tree identifier; - tree args; +const struct attribute_spec arc_attribute_table[] = { - if (identifier == get_identifier ("__interrupt__") - && list_length (args) == 1 - && TREE_CODE (TREE_VALUE (args)) == STRING_CST) - { - tree value = TREE_VALUE (args); + /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */ + { "interrupt", 1, 1, true, false, false, arc_handle_interrupt_attribute }, + { NULL, 0, 0, false, false, false, NULL } +}; - if (!strcmp (TREE_STRING_POINTER (value), "ilink1") - || !strcmp (TREE_STRING_POINTER (value), "ilink2")) - return 1; +/* Handle an "interrupt" attribute; arguments as in + struct attribute_spec.handler. */ +static tree +arc_handle_interrupt_attribute (node, name, args, flags, no_add_attrs) + tree *node ATTRIBUTE_UNUSED; + tree name; + tree args; + int flags ATTRIBUTE_UNUSED; + bool *no_add_attrs; +{ + tree value = TREE_VALUE (args); + + if (TREE_CODE (value) != STRING_CST) + { + warning ("argument of `%s' attribute is not a string constant", + IDENTIFIER_POINTER (name)); + *no_add_attrs = true; } - return 0; + else if (strcmp (TREE_STRING_POINTER (value), "ilink1") + && strcmp (TREE_STRING_POINTER (value), "ilink2")) + { + warning ("argument of `%s' attribute is not \"ilink1\" or \"ilink2\"", + IDENTIFIER_POINTER (name)); + *no_add_attrs = true; + } + + return NULL_TREE; } @@ -956,7 +971,7 @@ arc_compute_function_type (decl) fn_type = ARC_FUNCTION_NORMAL; /* Now see if this is an interrupt handler. */ - for (a = DECL_MACHINE_ATTRIBUTES (current_function_decl); + for (a = DECL_ATTRIBUTES (current_function_decl); a; a = TREE_CHAIN (a)) { diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c index 1ad558e8b5b..fcd90ddf4bd 100644 --- a/gcc/config/arm/arm.c +++ b/gcc/config/arm/arm.c @@ -103,10 +103,9 @@ static int current_file_function_operand PARAMS ((rtx)); static Ulong arm_compute_save_reg_mask PARAMS ((void)); static Ulong arm_isr_value PARAMS ((tree)); static Ulong arm_compute_func_type PARAMS ((void)); -static int arm_valid_type_attribute_p PARAMS ((tree, tree, - tree, tree)); -static int arm_valid_decl_attribute_p PARAMS ((tree, tree, - tree, tree)); +static tree arm_handle_fndecl_attribute PARAMS ((tree *, tree, tree, int, bool *)); +static tree arm_handle_isr_attribute PARAMS ((tree *, tree, tree, int, bool *)); +const struct attribute_spec arm_attribute_table[]; static void arm_output_function_epilogue PARAMS ((FILE *, HOST_WIDE_INT)); static void arm_output_function_prologue PARAMS ((FILE *, @@ -130,16 +129,8 @@ static int arm_adjust_cost PARAMS ((rtx, rtx, rtx, int)); #define TARGET_MERGE_DECL_ATTRIBUTES merge_dllimport_decl_attributes #endif -#undef TARGET_VALID_TYPE_ATTRIBUTE -#define TARGET_VALID_TYPE_ATTRIBUTE arm_valid_type_attribute_p - -#undef TARGET_VALID_DECL_ATTRIBUTE -#ifdef ARM_PE - static int arm_pe_valid_decl_attribute_p PARAMS ((tree, tree, tree, tree)); -# define TARGET_VALID_DECL_ATTRIBUTE arm_pe_valid_decl_attribute_p -#else -# define TARGET_VALID_DECL_ATTRIBUTE arm_valid_decl_attribute_p -#endif +#undef TARGET_ATTRIBUTE_TABLE +#define TARGET_ATTRIBUTE_TABLE arm_attribute_table #undef TARGET_ASM_FUNCTION_PROLOGUE #define TARGET_ASM_FUNCTION_PROLOGUE arm_output_function_prologue @@ -845,7 +836,7 @@ arm_compute_func_type () if (current_function_needs_context) type |= ARM_FT_NESTED; - attr = DECL_MACHINE_ATTRIBUTES (current_function_decl); + attr = DECL_ATTRIBUTES (current_function_decl); a = lookup_attribute ("naked", attr); if (a != NULL_TREE) @@ -1909,39 +1900,120 @@ arm_pr_long_calls_off (pfile) } -/* Return nonzero if IDENTIFIER with arguments ARGS is a valid machine - specific attribute for TYPE. The attributes in ATTRIBUTES have - previously been assigned to TYPE. */ -static int -arm_valid_type_attribute_p (type, attributes, identifier, args) - tree type; - tree attributes ATTRIBUTE_UNUSED; - tree identifier; - tree args; +/* Table of machine attributes. */ +const struct attribute_spec arm_attribute_table[] = { - if ( TREE_CODE (type) != FUNCTION_TYPE - && TREE_CODE (type) != METHOD_TYPE - && TREE_CODE (type) != FIELD_DECL - && TREE_CODE (type) != TYPE_DECL) - return 0; - + /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */ /* Function calls made to this symbol must be done indirectly, because it may lie outside of the 26 bit addressing range of a normal function call. */ - if (is_attribute_p ("long_call", identifier)) - return (args == NULL_TREE); - + { "long_call", 0, 0, false, true, true, NULL }, /* Whereas these functions are always known to reside within the 26 bit addressing range. */ - if (is_attribute_p ("short_call", identifier)) - return (args == NULL_TREE); - + { "short_call", 0, 0, false, true, true, NULL }, /* Interrupt Service Routines have special prologue and epilogue requirements. */ - if (is_attribute_p ("isr", identifier) - || is_attribute_p ("interrupt", identifier)) - return arm_isr_value (args); + { "isr", 0, 1, false, false, false, arm_handle_isr_attribute }, + { "interrupt", 0, 1, false, false, false, arm_handle_isr_attribute }, + { "naked", 0, 0, true, false, false, arm_handle_fndecl_attribute }, +#ifdef ARM_PE + /* ARM/PE has three new attributes: + interfacearm - ? + dllexport - for exporting a function/variable that will live in a dll + dllimport - for importing a function/variable from a dll - return 0; + Microsoft allows multiple declspecs in one __declspec, separating + them with spaces. We do NOT support this. Instead, use __declspec + multiple times. + */ + { "dllimport", 0, 0, true, false, false, NULL }, + { "dllexport", 0, 0, true, false, false, NULL }, + { "interfacearm", 0, 0, true, false, false, arm_handle_fndecl_attribute }, +#endif + { NULL, 0, 0, false, false, false, NULL } +}; + +/* Handle an attribute requiring a FUNCTION_DECL; + arguments as in struct attribute_spec.handler. */ +static tree +arm_handle_fndecl_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) + { + warning ("`%s' attribute only applies to functions", + IDENTIFIER_POINTER (name)); + *no_add_attrs = true; + } + + return NULL_TREE; +} + +/* Handle an "interrupt" or "isr" attribute; + arguments as in struct attribute_spec.handler. */ +static tree +arm_handle_isr_attribute (node, name, args, flags, no_add_attrs) + tree *node; + tree name; + tree args; + int flags; + bool *no_add_attrs; +{ + if (DECL_P (*node)) + { + if (TREE_CODE (*node) != FUNCTION_DECL) + { + warning ("`%s' attribute only applies to functions", + IDENTIFIER_POINTER (name)); + *no_add_attrs = true; + } + /* FIXME: the argument if any is checked for type attributes; + should it be checked for decl ones? */ + } + else + { + if (TREE_CODE (*node) == FUNCTION_TYPE + || TREE_CODE (*node) == METHOD_TYPE) + { + if (arm_isr_value (args) == ARM_FT_UNKNOWN) + { + warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name)); + *no_add_attrs = true; + } + } + else if (TREE_CODE (*node) == POINTER_TYPE + && (TREE_CODE (TREE_TYPE (*node)) == FUNCTION_TYPE + || TREE_CODE (TREE_TYPE (*node)) == METHOD_TYPE) + && arm_isr_value (args) != ARM_FT_UNKNOWN) + { + *node = build_type_copy (*node); + TREE_TYPE (*node) = build_type_attribute_variant (TREE_TYPE (*node), + tree_cons (name, + args, + TYPE_ATTRIBUTES (TREE_TYPE (*node)))); + *no_add_attrs = true; + } + else + { + /* Possibly pass this attribute on from the type to a decl. */ + if (flags & ((int) ATTR_FLAG_DECL_NEXT + | (int) ATTR_FLAG_FUNCTION_NEXT + | (int) ATTR_FLAG_ARRAY_NEXT)) + { + *no_add_attrs = true; + return tree_cons (name, args, NULL_TREE); + } + else + { + warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name)); + } + } + } + + return NULL_TREE; } /* Return 0 if the attributes for two types are incompatible, 1 if they @@ -4132,85 +4204,6 @@ multi_register_push (op, mode) return 1; } -/* Routines for use with attributes. */ - -/* Return nonzero if ATTR is a valid attribute for DECL. - ATTRIBUTES are any existing attributes and ARGS are - the arguments supplied with ATTR. - - Supported attributes: - - naked: - don't output any prologue or epilogue code, the user is assumed - to do the right thing. - - isr or interrupt: - Interrupt Service Routine. - - interfacearm: - Always assume that this function will be entered in ARM mode, - not Thumb mode, and that the caller wishes to be returned to in - ARM mode. */ -static int -arm_valid_decl_attribute_p (decl, attributes, attr, args) - tree decl; - tree attributes ATTRIBUTE_UNUSED; - tree attr; - tree args; -{ - /* The interrupt attribute can take args, so check for it before - rejecting other attributes on the grounds that they did have args. */ - if (is_attribute_p ("isr", attr) - || is_attribute_p ("interrupt", attr)) - return TREE_CODE (decl) == FUNCTION_DECL; - - if (args != NULL_TREE) - return 0; - - if (is_attribute_p ("naked", attr)) - return TREE_CODE (decl) == FUNCTION_DECL; - -#ifdef ARM_PE - if (is_attribute_p ("interfacearm", attr)) - return TREE_CODE (decl) == FUNCTION_DECL; -#endif /* ARM_PE */ - - return 0; -} - -#ifdef ARM_PE - -/* ARM/PE has three new attributes: - naked - for interrupt functions - dllexport - for exporting a function/variable that will live in a dll - dllimport - for importing a function/variable from a dll - - Microsoft allows multiple declspecs in one __declspec, separating - them with spaces. We do NOT support this. Instead, use __declspec - multiple times. -*/ - -static int -arm_pe_valid_decl_attribute_p (decl, attributes, attr, args) - tree decl; - tree attributes; - tree attr; - tree args; -{ - if (args != NULL_TREE) - return 0; - - if (is_attribute_p ("dllexport", attr)) - return 1; - - if (is_attribute_p ("dllimport", attr)) - return 1; - - return arm_valid_decl_attribute_p (decl, attributes, attr, args); -} - -#endif /* ARM_PE */ - /* Routines for use in generating RTL. */ rtx arm_gen_load_multiple (base_regno, count, from, up, write_back, unchanging_p, @@ -9742,7 +9735,7 @@ is_called_in_ARM_mode (func) return TRUE; #ifdef ARM_PE - return lookup_attribute ("interfacearm", DECL_MACHINE_ATTRIBUTES (func)) != NULL_TREE; + return lookup_attribute ("interfacearm", DECL_ATTRIBUTES (func)) != NULL_TREE; #else return FALSE; #endif diff --git a/gcc/config/arm/pe.c b/gcc/config/arm/pe.c index 29c470e3f3c..9e7e95a5765 100644 --- a/gcc/config/arm/pe.c +++ b/gcc/config/arm/pe.c @@ -1,5 +1,5 @@ /* Routines for GCC for ARM/pe. - Copyright (C) 1995, 1996, 2000 Free Software Foundation, Inc. + Copyright (C) 1995, 1996, 2000, 2001 Free Software Foundation, Inc. Contributed by Doug Evans (dje@cygnus.com). This file is part of GNU CC. @@ -45,7 +45,7 @@ arm_dllexport_p (decl) if (TREE_CODE (decl) != VAR_DECL && TREE_CODE (decl) != FUNCTION_DECL) return 0; - exp = lookup_attribute ("dllexport", DECL_MACHINE_ATTRIBUTES (decl)); + exp = lookup_attribute ("dllexport", DECL_ATTRIBUTES (decl)); if (exp) return 1; @@ -67,7 +67,7 @@ arm_dllimport_p (decl) if (TREE_CODE (decl) != VAR_DECL && TREE_CODE (decl) != FUNCTION_DECL) return 0; - imp = lookup_attribute ("dllimport", DECL_MACHINE_ATTRIBUTES (decl)); + imp = lookup_attribute ("dllimport", DECL_ATTRIBUTES (decl)); if (imp) return 1; diff --git a/gcc/config/avr/avr.c b/gcc/config/avr/avr.c index 5e9c172658a..ed54cbb3553 100644 --- a/gcc/config/avr/avr.c +++ b/gcc/config/avr/avr.c @@ -58,8 +58,9 @@ static int compare_sign_p PARAMS ((rtx insn)); static int reg_was_0 PARAMS ((rtx insn, rtx op)); static int io_address_p PARAMS ((rtx x, int size)); void debug_hard_reg_set PARAMS ((HARD_REG_SET set)); -static int avr_valid_type_attribute PARAMS ((tree, tree, tree, tree)); -static int avr_valid_decl_attribute PARAMS ((tree, tree, tree, tree)); +static tree avr_handle_progmem_attribute PARAMS ((tree *, tree, tree, int, bool *)); +static tree avr_handle_fndecl_attribute PARAMS ((tree *, tree, tree, int, bool *)); +const struct attribute_spec avr_attribute_table[]; static void avr_output_function_prologue PARAMS ((FILE *, HOST_WIDE_INT)); static void avr_output_function_epilogue PARAMS ((FILE *, HOST_WIDE_INT)); @@ -177,11 +178,8 @@ int avr_case_values_threshold = 30000; #define TARGET_ASM_FUNCTION_PROLOGUE avr_output_function_prologue #undef TARGET_ASM_FUNCTION_EPILOGUE #define TARGET_ASM_FUNCTION_EPILOGUE avr_output_function_epilogue -#undef TARGET_VALID_DECL_ATTRIBUTE -#define TARGET_VALID_DECL_ATTRIBUTE avr_valid_decl_attribute - -#undef TARGET_VALID_TYPE_ATTRIBUTE -#define TARGET_VALID_TYPE_ATTRIBUTE avr_valid_type_attribute +#undef TARGET_ATTRIBUTE_TABLE +#define TARGET_ATTRIBUTE_TABLE avr_attribute_table struct gcc_target targetm = TARGET_INITIALIZER; @@ -310,7 +308,7 @@ avr_naked_function_p (func) if (TREE_CODE (func) != FUNCTION_DECL) abort (); - a = lookup_attribute ("naked", DECL_MACHINE_ATTRIBUTES (func)); + a = lookup_attribute ("naked", DECL_ATTRIBUTES (func)); return a != NULL_TREE; } @@ -326,7 +324,7 @@ interrupt_function_p (func) if (TREE_CODE (func) != FUNCTION_DECL) return 0; - a = lookup_attribute ("interrupt", DECL_MACHINE_ATTRIBUTES (func)); + a = lookup_attribute ("interrupt", DECL_ATTRIBUTES (func)); return a != NULL_TREE; } @@ -342,7 +340,7 @@ signal_function_p (func) if (TREE_CODE (func) != FUNCTION_DECL) return 0; - a = lookup_attribute ("signal", DECL_MACHINE_ATTRIBUTES (func)); + a = lookup_attribute ("signal", DECL_ATTRIBUTES (func)); return a != NULL_TREE; } @@ -4665,54 +4663,76 @@ class_likely_spilled_p (c) return (c != ALL_REGS && c != ADDW_REGS); } -/* Only `progmem' attribute valid for type. */ - -static int -avr_valid_type_attribute (type, attributes, identifier, args) - tree type ATTRIBUTE_UNUSED; - tree attributes ATTRIBUTE_UNUSED; - tree identifier; - tree args ATTRIBUTE_UNUSED; -{ - return is_attribute_p ("progmem", identifier); -} - -/* If IDENTIFIER with arguments ARGS is a valid machine specific - attribute for DECL return 1. - Valid attributes: +/* Valid attributes: progmem - put data to program memory; signal - make a function to be hardware interrupt. After function prologue interrupts are disabled; interrupt - make a function to be hardware interrupt. After function prologue interrupts are enabled; - naked - don't generate function prologue/epilogue and `ret' command. */ + naked - don't generate function prologue/epilogue and `ret' command. -static int -avr_valid_decl_attribute (decl, attributes, attr, args) - tree decl; - tree attributes ATTRIBUTE_UNUSED; - tree attr; - tree args ATTRIBUTE_UNUSED; + Only `progmem' attribute valid for type. */ + +const struct attribute_spec avr_attribute_table[] = { - if (is_attribute_p ("interrupt", attr) - || is_attribute_p ("signal", attr) - || is_attribute_p ("naked", attr)) - return TREE_CODE (decl) == FUNCTION_DECL; + /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */ + { "progmem", 0, 0, false, false, false, avr_handle_progmem_attribute }, + { "signal", 0, 0, true, false, false, avr_handle_fndecl_attribute }, + { "interrupt", 0, 0, true, false, false, avr_handle_fndecl_attribute }, + { "naked", 0, 0, true, false, false, avr_handle_fndecl_attribute }, + { NULL, 0, 0, false, false, false, NULL } +}; - if (is_attribute_p ("progmem", attr) - && (TREE_STATIC (decl) || DECL_EXTERNAL (decl))) +/* Handle a "progmem" attribute; arguments as in + struct attribute_spec.handler. */ +static tree +avr_handle_progmem_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 (DECL_P (*node)) { - if (DECL_INITIAL (decl) == NULL_TREE && !DECL_EXTERNAL (decl)) + if (TREE_STATIC (*node) || DECL_EXTERNAL (*node)) { - warning ("Only initialized variables can be placed into " - "program memory area."); - return 0; + if (DECL_INITIAL (*node) == NULL_TREE && !DECL_EXTERNAL (*node)) + { + warning ("Only initialized variables can be placed into " + "program memory area."); + *no_add_attrs = true; + } + } + else + { + warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name)); + *no_add_attrs = true; } - return 1; } - return 0; + + return NULL_TREE; } +/* Handle an attribute requiring a FUNCTION_DECL; arguments as in + struct attribute_spec.handler. */ +static tree +avr_handle_fndecl_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) + { + warning ("`%s' attribute only applies to functions", + IDENTIFIER_POINTER (name)); + *no_add_attrs = true; + } + + return NULL_TREE; +} /* Look for attribute `progmem' in DECL if found return 1, otherwise 0. */ @@ -4727,7 +4747,7 @@ avr_progmem_p (decl) return 0; if (NULL_TREE - != lookup_attribute ("progmem", DECL_MACHINE_ATTRIBUTES (decl))) + != lookup_attribute ("progmem", DECL_ATTRIBUTES (decl))) return 1; a=decl; diff --git a/gcc/config/avr/avr.h b/gcc/config/avr/avr.h index 8ae9302f5e1..9ded05e361e 100644 --- a/gcc/config/avr/avr.h +++ b/gcc/config/avr/avr.h @@ -1110,7 +1110,7 @@ enum reg_class { FUNDECL is a C variable whose value is a tree node that describes the function in question. Normally it is a node of type `FUNCTION_DECL' that describes the declaration of the function. - From this you can obtain the DECL_MACHINE_ATTRIBUTES of the + From this you can obtain the DECL_ATTRIBUTES of the function. FUNTYPE is a C variable whose value is a tree node that describes diff --git a/gcc/config/c4x/c4x.c b/gcc/config/c4x/c4x.c index 872cdfd65a3..7ed86b2ba58 100644 --- a/gcc/config/c4x/c4x.c +++ b/gcc/config/c4x/c4x.c @@ -191,14 +191,15 @@ static int c4x_parse_pragma PARAMS ((const char *, tree *, tree *)); static int c4x_r11_set_p PARAMS ((rtx)); static int c4x_rptb_valid_p PARAMS ((rtx, rtx)); static int c4x_label_ref_used_p PARAMS ((rtx, rtx)); -static int c4x_valid_type_attribute_p PARAMS ((tree, tree, tree, tree)); +static tree c4x_handle_fntype_attribute PARAMS ((tree *, tree, tree, int, bool *)); +const struct attribute_spec c4x_attribute_table[]; static void c4x_insert_attributes PARAMS ((tree, tree *)); static void c4x_asm_named_section PARAMS ((const char *, unsigned int)); static int c4x_adjust_cost PARAMS ((rtx, rtx, rtx, int)); /* Initialize the GCC target structure. */ -#undef TARGET_VALID_TYPE_ATTRIBUTE -#define TARGET_VALID_TYPE_ATTRIBUTE c4x_valid_type_attribute_p +#undef TARGET_ATTRIBUTE_TABLE +#define TARGET_ATTRIBUTE_TABLE c4x_attribute_table #undef TARGET_INSERT_ATTRIBUTES #define TARGET_INSERT_ATTRIBUTES c4x_insert_attributes @@ -4761,31 +4762,36 @@ c4x_insert_attributes (decl, attributes) } } - -/* Return nonzero if IDENTIFIER with arguments ARGS is a valid machine - specific attribute for TYPE. The attributes in ATTRIBUTES have - previously been assigned to TYPE. */ - -static int -c4x_valid_type_attribute_p (type, attributes, identifier, args) - tree type; - tree attributes ATTRIBUTE_UNUSED; - tree identifier; - tree args ATTRIBUTE_UNUSED; +/* Table of valid machine attributes. */ +const struct attribute_spec c4x_attribute_table[] = { - if (TREE_CODE (type) != FUNCTION_TYPE) - return 0; - - if (is_attribute_p ("interrupt", identifier)) - return 1; - - if (is_attribute_p ("assembler", identifier)) - return 1; - - if (is_attribute_p ("leaf_pretend", identifier)) - return 1; - - return 0; + /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */ + { "interrupt", 0, 0, false, true, true, c4x_handle_fntype_attribute }, + /* FIXME: code elsewhere in this file treats "naked" as a synonym of + "interrupt"; should it be accepted here? */ + { "assembler", 0, 0, false, true, true, c4x_handle_fntype_attribute }, + { "leaf_pretend", 0, 0, false, true, true, c4x_handle_fntype_attribute }, + { NULL, 0, 0, false, false, false, NULL } +}; + +/* Handle an attribute requiring a FUNCTION_TYPE; + arguments as in struct attribute_spec.handler. */ +static tree +c4x_handle_fntype_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_TYPE) + { + warning ("`%s' attribute only applies to functions", + IDENTIFIER_POINTER (name)); + *no_add_attrs = true; + } + + return NULL_TREE; } diff --git a/gcc/config/d30v/d30v.h b/gcc/config/d30v/d30v.h index abf2d4736f0..1ab9dc703fa 100644 --- a/gcc/config/d30v/d30v.h +++ b/gcc/config/d30v/d30v.h @@ -2272,7 +2272,7 @@ typedef struct d30v_stack { FUNDECL is a C variable whose value is a tree node that describes the function in question. Normally it is a node of type `FUNCTION_DECL' that describes the declaration of the function. From this it is possible to - obtain the DECL_MACHINE_ATTRIBUTES of the function. + obtain the DECL_ATTRIBUTES of the function. FUNTYPE is a C variable whose value is a tree node that describes the function in question. Normally it is a node of type `FUNCTION_TYPE' that diff --git a/gcc/config/fr30/fr30.h b/gcc/config/fr30/fr30.h index 57d56613ee4..e94902cb5ae 100644 --- a/gcc/config/fr30/fr30.h +++ b/gcc/config/fr30/fr30.h @@ -1,7 +1,7 @@ /*{{{ Comment. */ /* Definitions of FR30 target. - Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc. + Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc. Contributed by Cygnus Solutions. This file is part of GNU CC. @@ -824,7 +824,7 @@ enum reg_class FUNDECL is a C variable whose value is a tree node that describes the function in question. Normally it is a node of type `FUNCTION_DECL' that describes the declaration of the function. From this it is possible to - obtain the DECL_MACHINE_ATTRIBUTES of the function. + obtain the DECL_ATTRIBUTES of the function. FUNTYPE is a C variable whose value is a tree node that describes the function in question. Normally it is a node of type `FUNCTION_TYPE' that diff --git a/gcc/config/h8300/h8300.c b/gcc/config/h8300/h8300.c index c998ac22568..34686a6440e 100644 --- a/gcc/config/h8300/h8300.c +++ b/gcc/config/h8300/h8300.c @@ -53,7 +53,10 @@ static unsigned int compute_saved_regs PARAMS ((void)); static void push PARAMS ((FILE *, int)); static void pop PARAMS ((FILE *, int)); static const char *cond_string PARAMS ((enum rtx_code)); -static int h8300_valid_decl_attribute PARAMS ((tree, tree, tree, tree)); +const struct attribute_spec h8300_attribute_table[]; +static tree h8300_handle_fndecl_attribute PARAMS ((tree *, tree, tree, int, bool *)); +static tree h8300_handle_eightbit_data_attribute PARAMS ((tree *, tree, tree, int, bool *)); +static tree h8300_handle_tiny_data_attribute PARAMS ((tree *, tree, tree, int, bool *)); static void h8300_output_function_prologue PARAMS ((FILE *, HOST_WIDE_INT)); static void h8300_output_function_epilogue PARAMS ((FILE *, HOST_WIDE_INT)); static void h8300_asm_named_section PARAMS ((const char *, unsigned int)); @@ -98,8 +101,8 @@ static const char *const h8_mov_ops[2] = { "mov.w", "mov.l" }; const char *h8_push_op, *h8_pop_op, *h8_mov_op; /* Initialize the GCC target structure. */ -#undef TARGET_VALID_DECL_ATTRIBUTE -#define TARGET_VALID_DECL_ATTRIBUTE h8300_valid_decl_attribute +#undef TARGET_ATTRIBUTE_TABLE +#define TARGET_ATTRIBUTE_TABLE h8300_attribute_table #undef TARGET_ASM_FUNCTION_PROLOGUE #define TARGET_ASM_FUNCTION_PROLOGUE h8300_output_function_prologue @@ -3102,7 +3105,7 @@ h8300_interrupt_function_p (func) if (TREE_CODE (func) != FUNCTION_DECL) return 0; - a = lookup_attribute ("interrupt_handler", DECL_MACHINE_ATTRIBUTES (func)); + a = lookup_attribute ("interrupt_handler", DECL_ATTRIBUTES (func)); return a != NULL_TREE; } @@ -3118,7 +3121,7 @@ h8300_os_task_function_p (func) if (TREE_CODE (func) != FUNCTION_DECL) return 0; - a = lookup_attribute ("OS_Task", DECL_MACHINE_ATTRIBUTES (func)); + a = lookup_attribute ("OS_Task", DECL_ATTRIBUTES (func)); return a != NULL_TREE; } @@ -3134,7 +3137,7 @@ h8300_monitor_function_p (func) if (TREE_CODE (func) != FUNCTION_DECL) return 0; - a = lookup_attribute ("monitor", DECL_MACHINE_ATTRIBUTES (func)); + a = lookup_attribute ("monitor", DECL_ATTRIBUTES (func)); return a != NULL_TREE; } @@ -3150,7 +3153,7 @@ h8300_funcvec_function_p (func) if (TREE_CODE (func) != FUNCTION_DECL) return 0; - a = lookup_attribute ("function_vector", DECL_MACHINE_ATTRIBUTES (func)); + a = lookup_attribute ("function_vector", DECL_ATTRIBUTES (func)); return a != NULL_TREE; } @@ -3166,7 +3169,7 @@ h8300_eightbit_data_p (decl) if (TREE_CODE (decl) != VAR_DECL) return 0; - a = lookup_attribute ("eightbit_data", DECL_MACHINE_ATTRIBUTES (decl)); + a = lookup_attribute ("eightbit_data", DECL_ATTRIBUTES (decl)); return a != NULL_TREE; } @@ -3182,15 +3185,11 @@ h8300_tiny_data_p (decl) if (TREE_CODE (decl) != VAR_DECL) return 0; - a = lookup_attribute ("tiny_data", DECL_MACHINE_ATTRIBUTES (decl)); + a = lookup_attribute ("tiny_data", DECL_ATTRIBUTES (decl)); return a != NULL_TREE; } -/* Return nonzero if ATTR is a valid attribute for DECL. - ATTRIBUTES are any existing attributes and ARGS are the arguments - supplied with ATTR. - - Supported attributes: +/* Supported attributes: interrupt_handler: output a prologue and epilogue suitable for an interrupt handler. @@ -3204,47 +3203,99 @@ h8300_tiny_data_p (decl) tiny_data: This variable lives in the tiny data area and can be referenced with 16-bit absolute memory references. */ -static int -h8300_valid_decl_attribute (decl, attributes, attr, args) - tree decl; - tree attributes ATTRIBUTE_UNUSED; - tree attr; - tree args; +const struct attribute_spec h8300_attribute_table[] = { - if (args != NULL_TREE) - return 0; + /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */ + { "interrupt_handler", 0, 0, true, false, false, h8300_handle_fndecl_attribute }, + { "OS_Task", 0, 0, true, false, false, h8300_handle_fndecl_attribute }, + { "monitor", 0, 0, true, false, false, h8300_handle_fndecl_attribute }, + { "function_vector", 0, 0, true, false, false, h8300_handle_fndecl_attribute }, + { "eightbit_data", 0, 0, true, false, false, h8300_handle_eightbit_data_attribute }, + { "tiny_data", 0, 0, true, false, false, h8300_handle_tiny_data_attribute }, + { NULL, 0, 0, false, false, false, NULL } +}; - if (is_attribute_p ("interrupt_handler", attr) - || is_attribute_p ("OS_Task", attr) - || is_attribute_p ("monitor", attr) - || is_attribute_p ("function_vector", attr)) - return TREE_CODE (decl) == FUNCTION_DECL; - if (is_attribute_p ("eightbit_data", attr) - && (TREE_STATIC (decl) || DECL_EXTERNAL (decl))) +/* Handle an attribute requiring a FUNCTION_DECL; arguments as in + struct attribute_spec.handler. */ +static tree +h8300_handle_fndecl_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) + { + warning ("`%s' attribute only applies to functions", + IDENTIFIER_POINTER (name)); + *no_add_attrs = true; + } + + return NULL_TREE; +} + +/* Handle an "eightbit_data" attribute; arguments as in + struct attribute_spec.handler. */ +static tree +h8300_handle_eightbit_data_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_STATIC (decl) || DECL_EXTERNAL (decl)) { if (DECL_INITIAL (decl) == NULL_TREE) { warning ("Only initialized variables can be placed into the 8-bit area."); - return 0; + *no_add_attrs = true; } - DECL_SECTION_NAME (decl) = build_string (7, ".eight"); - return 1; + else + DECL_SECTION_NAME (decl) = build_string (7, ".eight"); + } + else + { + warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name)); + *no_add_attrs = true; } - if (is_attribute_p ("tiny_data", attr) - && (TREE_STATIC (decl) || DECL_EXTERNAL (decl))) + return NULL_TREE; +} + +/* Handle an "tiny_data" attribute; arguments as in + struct attribute_spec.handler. */ +static tree +h8300_handle_tiny_data_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_STATIC (decl) || DECL_EXTERNAL (decl)) { if (DECL_INITIAL (decl) == NULL_TREE) { warning ("Only initialized variables can be placed into the 8-bit area."); - return 0; + *no_add_attrs = true; } - DECL_SECTION_NAME (decl) = build_string (6, ".tiny"); - return 1; + else + DECL_SECTION_NAME (decl) = build_string (6, ".tiny"); + } + else + { + warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name)); + *no_add_attrs = true; } - return 0; + return NULL_TREE; } void diff --git a/gcc/config/i386/cygwin.h b/gcc/config/i386/cygwin.h index d325167673c..138d96fc740 100644 --- a/gcc/config/i386/cygwin.h +++ b/gcc/config/i386/cygwin.h @@ -191,7 +191,7 @@ union tree_node; It's also used to handle dllimport override semantics. */ #if 0 #define REDO_SECTION_INFO_P(DECL) \ - ((DECL_MACHINE_ATTRIBUTES (DECL) != NULL_TREE) \ + ((DECL_ATTRIBUTES (DECL) != NULL_TREE) \ || (TREE_CODE (DECL) == VAR_DECL && DECL_VIRTUAL_P (DECL))) #else #define REDO_SECTION_INFO_P(DECL) 1 diff --git a/gcc/config/i386/i386-protos.h b/gcc/config/i386/i386-protos.h index b6462e1f65f..a81a29b02d8 100644 --- a/gcc/config/i386/i386-protos.h +++ b/gcc/config/i386/i386-protos.h @@ -173,9 +173,9 @@ extern int ix86_return_pops_args PARAMS ((tree, tree, int)); extern int ix86_data_alignment PARAMS ((tree, int)); extern int ix86_local_alignment PARAMS ((tree, int)); extern int ix86_constant_alignment PARAMS ((tree, int)); -extern int ix86_valid_type_attribute_p PARAMS ((tree, tree, tree, tree)); -extern int i386_pe_valid_decl_attribute_p PARAMS ((tree, tree, tree, tree)); -extern int i386_pe_valid_type_attribute_p PARAMS ((tree, tree, tree, tree)); +extern tree ix86_handle_dll_attribute PARAMS ((tree *, tree, tree, int, bool *)); +extern tree ix86_handle_shared_attribute PARAMS ((tree *, tree, tree, int, bool *)); + extern unsigned int i386_pe_section_type_flags PARAMS ((tree, const char *, int)); extern void i386_pe_asm_named_section PARAMS ((const char *, unsigned int)); diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c index c89a0ab591d..028c1ac8a17 100644 --- a/gcc/config/i386/i386.c +++ b/gcc/config/i386/i386.c @@ -657,6 +657,9 @@ static int ix86_fp_comparison_cost PARAMS ((enum rtx_code code)); static int ix86_save_reg PARAMS ((int, int)); static void ix86_compute_frame_layout PARAMS ((struct ix86_frame *)); static int ix86_comp_type_attributes PARAMS ((tree, tree)); +const struct attribute_spec ix86_attribute_table[]; +static tree ix86_handle_cdecl_attribute PARAMS ((tree *, tree, tree, int, bool *)); +static tree ix86_handle_regparm_attribute PARAMS ((tree *, tree, tree, int, bool *)); #ifdef DO_GLOBAL_CTORS_BODY static void ix86_svr3_asm_out_constructor PARAMS ((rtx, int)); @@ -667,15 +670,11 @@ static void sco_asm_out_constructor PARAMS ((rtx, int)); #endif /* Initialize the GCC target structure. */ -#undef TARGET_VALID_TYPE_ATTRIBUTE +#undef TARGET_ATTRIBUTE_TABLE +#define TARGET_ATTRIBUTE_TABLE ix86_attribute_table #ifdef TARGET_DLLIMPORT_DECL_ATTRIBUTES -# define TARGET_VALID_TYPE_ATTRIBUTE i386_pe_valid_type_attribute_p -# undef TARGET_VALID_DECL_ATTRIBUTE -# define TARGET_VALID_DECL_ATTRIBUTE i386_pe_valid_decl_attribute_p # undef TARGET_MERGE_DECL_ATTRIBUTES # define TARGET_MERGE_DECL_ATTRIBUTES merge_dllimport_decl_attributes -#else -# define TARGET_VALID_TYPE_ATTRIBUTE ix86_valid_type_attribute_p #endif #undef TARGET_COMP_TYPE_ATTRIBUTES @@ -977,56 +976,94 @@ optimization_options (level, size) #endif } -/* Return nonzero if IDENTIFIER with arguments ARGS is a valid machine specific - attribute for TYPE. The attributes in ATTRIBUTES have previously been - assigned to TYPE. */ - -int -ix86_valid_type_attribute_p (type, attributes, identifier, args) - tree type; - tree attributes ATTRIBUTE_UNUSED; - tree identifier; - tree args; +/* Table of valid machine attributes. */ +const struct attribute_spec ix86_attribute_table[] = { - if (TREE_CODE (type) != FUNCTION_TYPE - && TREE_CODE (type) != METHOD_TYPE - && TREE_CODE (type) != FIELD_DECL - && TREE_CODE (type) != TYPE_DECL) - return 0; - + /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */ /* Stdcall attribute says callee is responsible for popping arguments if they are not variable. */ - if (is_attribute_p ("stdcall", identifier) - && !TARGET_64BIT) - return (args == NULL_TREE); - - /* Cdecl attribute says the callee is a normal C declaration. */ - if (is_attribute_p ("cdecl", identifier) - && !TARGET_64BIT) - return (args == NULL_TREE); - + { "stdcall", 0, 0, false, true, true, ix86_handle_cdecl_attribute }, + /* Cdecl attribute says the callee is a normal C declaration */ + { "cdecl", 0, 0, false, true, true, ix86_handle_cdecl_attribute }, /* Regparm attribute specifies how many integer arguments are to be passed in registers. */ - if (is_attribute_p ("regparm", identifier)) + { "regparm", 1, 1, false, true, true, ix86_handle_regparm_attribute }, +#ifdef TARGET_DLLIMPORT_DECL_ATTRIBUTES + { "dllimport", 1, 1, false, false, false, ix86_handle_dll_attribute }, + { "dllexport", 1, 1, false, false, false, ix86_handle_dll_attribute }, + { "shared", 1, 1, true, false, false, ix86_handle_shared_attribute }, +#endif + { NULL, 0, 0, false, false, false, NULL } +}; + +/* Handle a "cdecl" or "stdcall" attribute; + arguments as in struct attribute_spec.handler. */ +static tree +ix86_handle_cdecl_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_TYPE + && TREE_CODE (*node) != METHOD_TYPE + && TREE_CODE (*node) != FIELD_DECL + && TREE_CODE (*node) != TYPE_DECL) + { + warning ("`%s' attribute only applies to functions", + IDENTIFIER_POINTER (name)); + *no_add_attrs = true; + } + + if (TARGET_64BIT) + { + warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name)); + *no_add_attrs = true; + } + + return NULL_TREE; +} + +/* Handle a "regparm" attribute; + arguments as in struct attribute_spec.handler. */ +static tree +ix86_handle_regparm_attribute (node, name, args, flags, no_add_attrs) + tree *node; + tree name; + tree args; + int flags ATTRIBUTE_UNUSED; + bool *no_add_attrs; +{ + if (TREE_CODE (*node) != FUNCTION_TYPE + && TREE_CODE (*node) != METHOD_TYPE + && TREE_CODE (*node) != FIELD_DECL + && TREE_CODE (*node) != TYPE_DECL) + { + warning ("`%s' attribute only applies to functions", + IDENTIFIER_POINTER (name)); + *no_add_attrs = true; + } + else { tree cst; - if (! args || TREE_CODE (args) != TREE_LIST - || TREE_CHAIN (args) != NULL_TREE - || TREE_VALUE (args) == NULL_TREE) - return 0; - cst = TREE_VALUE (args); if (TREE_CODE (cst) != INTEGER_CST) - return 0; - - if (compare_tree_int (cst, REGPARM_MAX) > 0) - return 0; - - return 1; + { + warning ("`%s' attribute requires an integer constant argument", + IDENTIFIER_POINTER (name)); + *no_add_attrs = true; + } + else if (compare_tree_int (cst, REGPARM_MAX) > 0) + { + warning ("argument to `%s' attribute larger than %d", + IDENTIFIER_POINTER (name), REGPARM_MAX); + *no_add_attrs = true; + } } - return 0; + return NULL_TREE; } #if defined (OSF_OS) || defined (TARGET_OSF1ELF) diff --git a/gcc/config/i386/winnt.c b/gcc/config/i386/winnt.c index d32224f2382..e14359d1c4b 100644 --- a/gcc/config/i386/winnt.c +++ b/gcc/config/i386/winnt.c @@ -1,6 +1,6 @@ /* Subroutines for insn-output.c for Windows NT. Contributed by Douglas Rupp (drupp@cs.washington.edu) - Copyright (C) 1995, 1997, 1998 Free Software Foundation, Inc. + Copyright (C) 1995, 1997, 1998, 1999, 2000, 2001 Free Software Foundation, Inc. This file is part of GNU CC. @@ -49,51 +49,54 @@ int i386_pe_dllimport_p PARAMS ((tree)); void i386_pe_mark_dllexport PARAMS ((tree)); void i386_pe_mark_dllimport PARAMS ((tree)); -/* Return nonzero if ATTR is a valid attribute for DECL. - ATTRIBUTES are any existing attributes and ARGS are the arguments - supplied with ATTR. */ - -int -i386_pe_valid_decl_attribute_p (decl, attributes, attr, args) - tree decl; - tree attributes ATTRIBUTE_UNUSED; - tree attr; +/* Handle a "dllimport" or "dllexport" attribute; + arguments as in struct attribute_spec.handler. */ +tree +ix86_handle_dll_attribute (node, name, args, flags, no_add_attrs) + tree *node; + tree name; tree args; + int flags; + bool *no_add_attrs; { - if (args == NULL_TREE) + /* These attributes may apply to structure and union types being created, + but otherwise should pass to the declaration involved. */ + if (!DECL_P (*node)) { - if (is_attribute_p ("dllexport", attr)) - return 1; - if (is_attribute_p ("dllimport", attr)) - return 1; - if (is_attribute_p ("shared", attr)) - return TREE_CODE (decl) == VAR_DECL; + if (flags & ((int) ATTR_FLAG_DECL_NEXT | (int) ATTR_FLAG_FUNCTION_NEXT + | (int) ATTR_FLAG_ARRAY_NEXT)) + { + *no_add_attrs = true; + return tree_cons (name, args, NULL_TREE); + } + if (TREE_CODE (*node) != RECORD_TYPE && TREE_CODE (*node) != UNION_TYPE) + { + warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name)); + *no_add_attrs = true; + } } - return 0; + return NULL_TREE; } -/* Return nonzero if ATTR is a valid attribute for TYPE. - ATTRIBUTES are any existing attributes and ARGS are the arguments - supplied with ATTR. */ - -int -i386_pe_valid_type_attribute_p (type, attributes, attr, args) - tree type; - tree attributes; - tree attr; - tree args; +/* Handle a "shared" attribute; + arguments as in struct attribute_spec.handler. */ +tree +ix86_handle_shared_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 (args == NULL_TREE - && (TREE_CODE (type) == RECORD_TYPE || TREE_CODE (type) == UNION_TYPE)) + if (TREE_CODE (*node) != VAR_DECL) { - if (is_attribute_p ("dllexport", attr)) - return 1; - if (is_attribute_p ("dllimport", attr)) - return 1; + warning ("`%s' attribute only applies to variables", + IDENTIFIER_POINTER (name)); + *no_add_attrs = true; } - return ix86_valid_type_attribute_p (type, attributes, attr, args); + return NULL_TREE; } /* Return the type that we should use to determine if DECL is @@ -132,7 +135,7 @@ i386_pe_dllexport_p (decl) if (TREE_CODE (decl) != VAR_DECL && TREE_CODE (decl) != FUNCTION_DECL) return 0; - exp = lookup_attribute ("dllexport", DECL_MACHINE_ATTRIBUTES (decl)); + exp = lookup_attribute ("dllexport", DECL_ATTRIBUTES (decl)); if (exp) return 1; @@ -163,7 +166,7 @@ i386_pe_dllimport_p (decl) if (TREE_CODE (decl) != VAR_DECL && TREE_CODE (decl) != FUNCTION_DECL) return 0; - imp = lookup_attribute ("dllimport", DECL_MACHINE_ATTRIBUTES (decl)); + imp = lookup_attribute ("dllimport", DECL_ATTRIBUTES (decl)); if (imp) return 1; @@ -499,7 +502,7 @@ i386_pe_section_type_flags (decl, name, reloc) flags = SECTION_WRITE; if (decl && TREE_CODE (decl) == VAR_DECL - && lookup_attribute ("shared", DECL_MACHINE_ATTRIBUTES (decl))) + && lookup_attribute ("shared", DECL_ATTRIBUTES (decl))) flags |= SECTION_PE_SHARED; } diff --git a/gcc/config/ia64/ia64.c b/gcc/config/ia64/ia64.c index 9da42706d00..9c56f376a5c 100644 --- a/gcc/config/ia64/ia64.c +++ b/gcc/config/ia64/ia64.c @@ -138,7 +138,7 @@ static rtx ia64_expand_compare_and_swap PARAMS ((enum machine_mode, int, static rtx ia64_expand_lock_test_and_set PARAMS ((enum machine_mode, tree, rtx)); static rtx ia64_expand_lock_release PARAMS ((enum machine_mode, tree, rtx)); -static int ia64_valid_type_attribute PARAMS((tree, tree, tree, tree)); +const struct attribute_spec ia64_attribute_table[]; static void ia64_output_function_prologue PARAMS ((FILE *, HOST_WIDE_INT)); static void ia64_output_function_epilogue PARAMS ((FILE *, HOST_WIDE_INT)); static void ia64_output_function_end_prologue PARAMS ((FILE *)); @@ -156,8 +156,8 @@ static rtx ia64_cycle_display PARAMS ((int, rtx)); /* Initialize the GCC target structure. */ -#undef TARGET_VALID_TYPE_ATTRIBUTE -#define TARGET_VALID_TYPE_ATTRIBUTE ia64_valid_type_attribute +#undef TARGET_ATTRIBUTE_TABLE +#define TARGET_ATTRIBUTE_TABLE ia64_attribute_table #undef TARGET_INIT_BUILTINS #define TARGET_INIT_BUILTINS ia64_init_builtins @@ -6755,29 +6755,13 @@ ia64_epilogue_uses (regno) } } -/* Return true if IDENTIFIER is a valid attribute for TYPE. */ - -static int -ia64_valid_type_attribute (type, attributes, identifier, args) - tree type; - tree attributes ATTRIBUTE_UNUSED; - tree identifier; - tree args; +/* Table of valid machine attributes. */ +const struct attribute_spec ia64_attribute_table[] = { - /* We only support an attribute for function calls. */ - - if (TREE_CODE (type) != FUNCTION_TYPE - && TREE_CODE (type) != METHOD_TYPE) - return 0; - - /* The "syscall_linkage" attribute says the callee is a system call entry - point. This affects ia64_epilogue_uses. */ - - if (is_attribute_p ("syscall_linkage", identifier)) - return args == NULL_TREE; - - return 0; -} + /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */ + { "syscall_linkage", 0, 0, false, true, true, NULL }, + { NULL, 0, 0, false, false, false, NULL } +}; /* For ia64, SYMBOL_REF_FLAG set means that it is a function. diff --git a/gcc/config/m32r/m32r.c b/gcc/config/m32r/m32r.c index a9ca24fd224..f1ed72d2e8d 100644 --- a/gcc/config/m32r/m32r.c +++ b/gcc/config/m32r/m32r.c @@ -62,8 +62,8 @@ static int m32r_sched_odd_word_p; static void init_reg_tables PARAMS ((void)); static void block_move_call PARAMS ((rtx, rtx, rtx)); static int m32r_is_insn PARAMS ((rtx)); -static int m32r_valid_decl_attribute PARAMS ((tree, tree, - tree, tree)); +const struct attribute_spec m32r_attribute_table[]; +static tree m32r_handle_model_attribute PARAMS ((tree *, tree, tree, int, bool *)); static void m32r_output_function_prologue PARAMS ((FILE *, HOST_WIDE_INT)); static void m32r_output_function_epilogue PARAMS ((FILE *, HOST_WIDE_INT)); @@ -76,8 +76,8 @@ static int m32r_issue_rate PARAMS ((void)); /* Initialize the GCC target structure. */ -#undef TARGET_VALID_DECL_ATTRIBUTE -#define TARGET_VALID_DECL_ATTRIBUTE m32r_valid_decl_attribute +#undef TARGET_ATTRIBUTE_TABLE +#define TARGET_ATTRIBUTE_TABLE m32r_attribute_table #undef TARGET_ASM_FUNCTION_PROLOGUE #define TARGET_ASM_FUNCTION_PROLOGUE m32r_output_function_prologue @@ -250,10 +250,6 @@ init_reg_tables () Grep for MODEL in m32r.h for more info. */ -static tree interrupt_ident1; -static tree interrupt_ident2; -static tree model_ident1; -static tree model_ident2; static tree small_ident1; static tree small_ident2; static tree medium_ident1; @@ -264,12 +260,8 @@ static tree large_ident2; static void init_idents PARAMS ((void)) { - if (interrupt_ident1 == 0) + if (small_ident1 == 0) { - interrupt_ident1 = get_identifier ("interrupt"); - interrupt_ident2 = get_identifier ("__interrupt__"); - model_ident1 = get_identifier ("model"); - model_ident2 = get_identifier ("__model__"); small_ident1 = get_identifier ("small"); small_ident2 = get_identifier ("__small__"); medium_ident1 = get_identifier ("medium"); @@ -279,34 +271,43 @@ init_idents PARAMS ((void)) } } -/* Return nonzero if IDENTIFIER is a valid decl attribute. */ - -static int -m32r_valid_decl_attribute (type, attributes, identifier, args) - tree type ATTRIBUTE_UNUSED; - tree attributes ATTRIBUTE_UNUSED; - tree identifier; - tree args; +const struct attribute_spec m32r_attribute_table[] = { + /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */ + { "interrupt", 0, 0, true, false, false, NULL }, + { "model", 1, 1, true, false, false, m32r_handle_model_attribute }, + { NULL, 0, 0, false, false, false, NULL } +}; + + +/* Handle an "model" attribute; arguments as in + struct attribute_spec.handler. */ +static tree +m32r_handle_model_attribute (node, name, args, flags, no_add_attrs) + tree *node ATTRIBUTE_UNUSED; + tree name; + tree args; + int flags ATTRIBUTE_UNUSED; + bool *no_add_attrs; +{ + tree arg; + init_idents (); + arg = TREE_VALUE (args); - if ((identifier == interrupt_ident1 - || identifier == interrupt_ident2) - && list_length (args) == 0) - return 1; + if (arg != small_ident1 + && arg != small_ident2 + && arg != medium_ident1 + && arg != medium_ident2 + && arg != large_ident1 + && arg != large_ident2) + { + warning ("invalid argument of `%s' attribute", + IDENTIFIER_POINTER (name)); + *no_add_attrs = true; + } - if ((identifier == model_ident1 - || identifier == model_ident2) - && list_length (args) == 1 - && (TREE_VALUE (args) == small_ident1 - || TREE_VALUE (args) == small_ident2 - || TREE_VALUE (args) == medium_ident1 - || TREE_VALUE (args) == medium_ident2 - || TREE_VALUE (args) == large_ident1 - || TREE_VALUE (args) == large_ident2)) - return 1; - - return 0; + return NULL_TREE; } /* A C statement or statements to switch to the appropriate @@ -370,7 +371,7 @@ m32r_encode_section_info (decl) { case VAR_DECL : case FUNCTION_DECL : - model = lookup_attribute ("model", DECL_MACHINE_ATTRIBUTES (decl)); + model = lookup_attribute ("model", DECL_ATTRIBUTES (decl)); break; case STRING_CST : case CONSTRUCTOR : @@ -1747,7 +1748,7 @@ m32r_compute_function_type (decl) return fn_type; /* Compute function type. */ - fn_type = (lookup_attribute ("interrupt", DECL_MACHINE_ATTRIBUTES (current_function_decl)) != NULL_TREE + fn_type = (lookup_attribute ("interrupt", DECL_ATTRIBUTES (current_function_decl)) != NULL_TREE ? M32R_FUNCTION_INTERRUPT : M32R_FUNCTION_NORMAL); diff --git a/gcc/config/m68hc11/m68hc11.c b/gcc/config/m68hc11/m68hc11.c index 3bd9ce68fb2..da45de0458a 100644 --- a/gcc/config/m68hc11/m68hc11.c +++ b/gcc/config/m68hc11/m68hc11.c @@ -66,8 +66,8 @@ static rtx m68hc11_expand_compare PARAMS((enum rtx_code, rtx, rtx)); static int must_parenthesize PARAMS ((rtx)); static int m68hc11_shift_cost PARAMS ((enum machine_mode, rtx, int)); static int m68hc11_auto_inc_p PARAMS ((rtx)); -static int m68hc11_valid_type_attribute_p PARAMS((tree, tree, - tree, tree)); +static tree m68hc11_handle_fntype_attribute PARAMS ((tree *, tree, tree, int, bool *)); +const struct attribute_spec m68hc11_attribute_table[]; void create_regs_rtx PARAMS ((void)); static void m68hc11_add_gc_roots PARAMS ((void)); @@ -209,8 +209,8 @@ const char *m68hc11_soft_reg_count; static int nb_soft_regs; /* Initialize the GCC target structure. */ -#undef TARGET_VALID_TYPE_ATTRIBUTE -#define TARGET_VALID_TYPE_ATTRIBUTE m68hc11_valid_type_attribute_p +#undef TARGET_ATTRIBUTE_TABLE +#define TARGET_ATTRIBUTE_TABLE m68hc11_attribute_table #undef TARGET_ASM_FUNCTION_EPILOGUE #define TARGET_ASM_FUNCTION_EPILOGUE m68hc11_output_function_epilogue @@ -1130,30 +1130,34 @@ m68hc11_initialize_trampoline (tramp, fnaddr, cxt) /* Declaration of types. */ -/* If defined, a C expression whose value is nonzero if IDENTIFIER - with arguments ARGS is a valid machine specific attribute for TYPE. - The attributes in ATTRIBUTES have previously been assigned to TYPE. */ - -static int -m68hc11_valid_type_attribute_p (type, attributes, identifier, args) - tree type; - tree attributes ATTRIBUTE_UNUSED; - tree identifier; - tree args; +const struct attribute_spec m68hc11_attribute_table[] = { - if (TREE_CODE (type) != FUNCTION_TYPE - && TREE_CODE (type) != FIELD_DECL && TREE_CODE (type) != TYPE_DECL) - return 0; + /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */ + { "interrupt", 0, 0, false, true, true, m68hc11_handle_fntype_attribute }, + { "trap", 0, 0, false, true, true, m68hc11_handle_fntype_attribute }, + { NULL, 0, 0, false, false, false, NULL } +}; - if (TREE_CODE (type) == FUNCTION_TYPE) +/* Handle an attribute requiring a FUNCTION_TYPE, FIELD_DECL or TYPE_DECL; + arguments as in struct attribute_spec.handler. */ +static tree +m68hc11_handle_fntype_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_TYPE + && TREE_CODE (*node) != FIELD_DECL + && TREE_CODE (*node) != TYPE_DECL) { - if (is_attribute_p ("interrupt", identifier)) - return (args == NULL_TREE); - if (is_attribute_p ("trap", identifier)) - return (args == NULL_TREE); + warning ("`%s' attribute only applies to functions", + IDENTIFIER_POINTER (name)); + *no_add_attrs = true; } - return 0; + return NULL_TREE; } /* Define this macro if references to a symbol must be treated diff --git a/gcc/config/mcore/mcore.c b/gcc/config/mcore/mcore.c index 095eef38931..0a4a2b5f80e 100644 --- a/gcc/config/mcore/mcore.c +++ b/gcc/config/mcore/mcore.c @@ -130,8 +130,8 @@ static void mcore_mark_dllexport PARAMS ((tree)); static void mcore_mark_dllimport PARAMS ((tree)); static int mcore_dllexport_p PARAMS ((tree)); static int mcore_dllimport_p PARAMS ((tree)); -static int mcore_valid_decl_attribute PARAMS ((tree, tree, - tree, tree)); +const struct attribute_spec mcore_attribute_table[]; +static tree mcore_handle_naked_attribute PARAMS ((tree *, tree, tree, int, bool *)); static void mcore_asm_named_section PARAMS ((const char *, unsigned int)); @@ -141,8 +141,8 @@ static void mcore_asm_named_section PARAMS ((const char *, #define TARGET_MERGE_DECL_ATTRIBUTES merge_dllimport_decl_attributes #endif -#undef TARGET_VALID_DECL_ATTRIBUTE -#define TARGET_VALID_DECL_ATTRIBUTE mcore_valid_decl_attribute +#undef TARGET_ATTRIBUTE_TABLE +#define TARGET_ATTRIBUTE_TABLE mcore_attribute_table struct gcc_target targetm = TARGET_INITIALIZER; @@ -3387,7 +3387,7 @@ mcore_dllexport_p (decl) && TREE_CODE (decl) != FUNCTION_DECL) return 0; - return lookup_attribute ("dllexport", DECL_MACHINE_ATTRIBUTES (decl)) != 0; + return lookup_attribute ("dllexport", DECL_ATTRIBUTES (decl)) != 0; } static int @@ -3398,7 +3398,7 @@ mcore_dllimport_p (decl) && TREE_CODE (decl) != FUNCTION_DECL) return 0; - return lookup_attribute ("dllimport", DECL_MACHINE_ATTRIBUTES (decl)) != 0; + return lookup_attribute ("dllimport", DECL_ATTRIBUTES (decl)) != 0; } /* Cover function to implement ENCODE_SECTION_INFO. */ @@ -3449,24 +3449,27 @@ mcore_encode_section_info (decl) dllexport - for exporting a function/variable that will live in a dll dllimport - for importing a function/variable from a dll naked - do not create a function prologue/epilogue. */ -static int -mcore_valid_decl_attribute (decl, attributes, attr, args) - tree decl; - tree attributes ATTRIBUTE_UNUSED; - tree attr; - tree args; + +const struct attribute_spec mcore_attribute_table[] = { - if (args != NULL_TREE) - return 0; + /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */ + { "dllexport", 0, 0, true, false, false, NULL }, + { "dllimport", 0, 0, true, false, false, NULL }, + { "naked", 0, 0, true, false, false, mcore_handle_naked_attribute }, + { NULL, 0, 0, false, false, false, NULL } +}; - if (is_attribute_p ("dllexport", attr)) - return 1; - - if (is_attribute_p ("dllimport", attr)) - return 1; - - if (is_attribute_p ("naked", attr) && - TREE_CODE (decl) == FUNCTION_DECL) +/* Handle a "naked" attribute; arguments as in + struct attribute_spec.handler. */ +static tree +mcore_handle_naked_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) { /* PR14310 - don't complain about lack of return statement in naked functions. The solution here is a gross hack @@ -3483,11 +3486,15 @@ mcore_valid_decl_attribute (decl, attributes, attr, args) } else if (saved_warn_return_type_count) saved_warn_return_type_count = 2; - - return 1; + } + else + { + warning ("`%s' attribute only applies to functions", + IDENTIFIER_POINTER (name)); + *no_add_attrs = true; } - return 0; + return NULL_TREE; } /* Cover function for UNIQUE_SECTION. */ @@ -3530,7 +3537,7 @@ mcore_unique_section (decl, reloc) int mcore_naked_function_p () { - return lookup_attribute ("naked", DECL_MACHINE_ATTRIBUTES (current_function_decl)) != NULL_TREE; + return lookup_attribute ("naked", DECL_ATTRIBUTES (current_function_decl)) != NULL_TREE; } static void diff --git a/gcc/config/ns32k/ns32k.c b/gcc/config/ns32k/ns32k.c index b6bd0daa4f8..a7e89c25f17 100644 --- a/gcc/config/ns32k/ns32k.c +++ b/gcc/config/ns32k/ns32k.c @@ -37,6 +37,7 @@ Boston, MA 02111-1307, USA. */ #include "tm_p.h" #include "target.h" #include "target-def.h" +#include "toplev.h" #ifdef OSF_OS int ns32k_num_files = 0; @@ -64,13 +65,14 @@ static const char *const ns32k_out_reg_names[] = OUTPUT_REGISTER_NAMES; static rtx gen_indexed_expr PARAMS ((rtx, rtx, rtx)); static const char *singlemove_string PARAMS ((rtx *)); static void move_tail PARAMS ((rtx[], int, int)); -static int ns32k_valid_type_attribute_p PARAMS ((tree, tree, tree, tree)); +static tree ns32k_handle_fntype_attribute PARAMS ((tree *, tree, tree, int, bool *)); +const struct attribute_spec ns32k_attribute_table[]; static void ns32k_output_function_prologue PARAMS ((FILE *, HOST_WIDE_INT)); static void ns32k_output_function_epilogue PARAMS ((FILE *, HOST_WIDE_INT)); /* Initialize the GCC target structure. */ -#undef TARGET_VALID_TYPE_ATTRIBUTE -#define TARGET_VALID_TYPE_ATTRIBUTE ns32k_valid_type_attribute_p +#undef TARGET_ATTRIBUTE_TABLE +#define TARGET_ATTRIBUTE_TABLE ns32k_attribute_table #undef TARGET_ASM_FUNCTION_PROLOGUE #define TARGET_ASM_FUNCTION_PROLOGUE ns32k_output_function_prologue @@ -1008,32 +1010,39 @@ symbolic_reference_mentioned_p (op) return 0; } -/* Return nonzero if IDENTIFIER with arguments ARGS is a valid machine specific - attribute for TYPE. The attributes in ATTRIBUTES have previously been - assigned to TYPE. */ +/* Table of machine-specific attributes. */ -static int -ns32k_valid_type_attribute_p (type, attributes, identifier, args) - tree type; - tree attributes ATTRIBUTE_UNUSED; - tree identifier; - tree args; +const struct attribute_spec ns32k_attribute_table[] = { - if (TREE_CODE (type) != FUNCTION_TYPE - && TREE_CODE (type) != FIELD_DECL - && TREE_CODE (type) != TYPE_DECL) - return 0; - + /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */ /* Stdcall attribute says callee is responsible for popping arguments if they are not variable. */ - if (is_attribute_p ("stdcall", identifier)) - return (args == NULL_TREE); - + { "stdcall", 0, 0, false, true, true, ns32k_handle_fntype_attribute }, /* Cdecl attribute says the callee is a normal C declaration */ - if (is_attribute_p ("cdecl", identifier)) - return (args == NULL_TREE); + { "cdecl", 0, 0, false, true, true, ns32k_handle_fntype_attribute }, + { NULL, 0, 0, false, false, false, NULL } +}; - return 0; +/* Handle an attribute requiring a FUNCTION_TYPE, FIELD_DECL or TYPE_DECL; + arguments as in struct attribute_spec.handler. */ +static tree +ns32k_handle_fntype_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_TYPE + && TREE_CODE (*node) != FIELD_DECL + && TREE_CODE (*node) != TYPE_DECL) + { + warning ("`%s' attribute only applies to functions", + IDENTIFIER_POINTER (name)); + *no_add_attrs = true; + } + + return NULL_TREE; } diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c index c1b1f71152d..738c8a5bed8 100644 --- a/gcc/config/rs6000/rs6000.c +++ b/gcc/config/rs6000/rs6000.c @@ -127,7 +127,8 @@ static int constant_pool_expr_1 PARAMS ((rtx, int *, int *)); static void rs6000_free_machine_status PARAMS ((struct function *)); static void rs6000_init_machine_status PARAMS ((struct function *)); static int rs6000_ra_ever_killed PARAMS ((void)); -static int rs6000_valid_type_attribute_p PARAMS ((tree, tree, tree, tree)); +static tree rs6000_handle_longcall_attribute PARAMS ((tree *, tree, tree, int, bool *)); +const struct attribute_spec rs6000_attribute_table[]; static void rs6000_output_function_prologue PARAMS ((FILE *, HOST_WIDE_INT)); static void rs6000_output_function_epilogue PARAMS ((FILE *, HOST_WIDE_INT)); static rtx rs6000_emit_set_long_const PARAMS ((rtx, @@ -184,8 +185,8 @@ static char alt_reg_names[][8] = #endif /* Initialize the GCC target structure. */ -#undef TARGET_VALID_TYPE_ATTRIBUTE -#define TARGET_VALID_TYPE_ATTRIBUTE rs6000_valid_type_attribute_p +#undef TARGET_ATTRIBUTE_TABLE +#define TARGET_ATTRIBUTE_TABLE rs6000_attribute_table #undef TARGET_ASM_FUNCTION_PROLOGUE #define TARGET_ASM_FUNCTION_PROLOGUE rs6000_output_function_prologue @@ -8123,28 +8124,34 @@ rs6000_initialize_trampoline (addr, fnaddr, cxt) } -/* If defined, a C expression whose value is nonzero if IDENTIFIER - with arguments ARGS is a valid machine specific attribute for TYPE. - The attributes in ATTRIBUTES have previously been assigned to TYPE. */ - -static int -rs6000_valid_type_attribute_p (type, attributes, identifier, args) - tree type; - tree attributes ATTRIBUTE_UNUSED; - tree identifier; - tree args; +/* Table of valid machine attributes. */ +const struct attribute_spec rs6000_attribute_table[] = { - if (TREE_CODE (type) != FUNCTION_TYPE - && TREE_CODE (type) != FIELD_DECL - && TREE_CODE (type) != TYPE_DECL) - return 0; + /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */ + { "longcall", 0, 0, false, true, true, rs6000_handle_longcall_attribute }, + { NULL, 0, 0, false, false, false, NULL } +}; - /* Longcall attribute says that the function is not within 2**26 bytes - of the current function, and to do an indirect call. */ - if (is_attribute_p ("longcall", identifier)) - return (args == NULL_TREE); +/* Handle a "longcall" attribute; + arguments as in struct attribute_spec.handler. */ +static tree +rs6000_handle_longcall_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_TYPE + && TREE_CODE (*node) != FIELD_DECL + && TREE_CODE (*node) != TYPE_DECL) + { + warning ("`%s' attribute only applies to functions", + IDENTIFIER_POINTER (name)); + *no_add_attrs = true; + } - return 0; + return NULL_TREE; } /* Return a reference suitable for calling a function with the diff --git a/gcc/config/sh/sh.c b/gcc/config/sh/sh.c index 29a657b88fe..684cff1ac5e 100644 --- a/gcc/config/sh/sh.c +++ b/gcc/config/sh/sh.c @@ -154,15 +154,18 @@ static int calc_live_regs PARAMS ((int *, int *)); static void mark_use PARAMS ((rtx, rtx *)); static HOST_WIDE_INT rounded_frame_size PARAMS ((int)); static rtx mark_constant_pool_use PARAMS ((rtx)); -static int sh_valid_decl_attribute PARAMS ((tree, tree, tree, tree)); +const struct attribute_spec sh_attribute_table[]; +static tree sh_handle_interrupt_handler_attribute PARAMS ((tree *, tree, tree, int, bool *)); +static tree sh_handle_sp_switch_attribute PARAMS ((tree *, tree, tree, int, bool *)); +static tree sh_handle_trap_exit_attribute PARAMS ((tree *, tree, tree, int, bool *)); static void sh_output_function_epilogue PARAMS ((FILE *, HOST_WIDE_INT)); static void sh_insert_attributes PARAMS ((tree, tree *)); static void sh_asm_named_section PARAMS ((const char *, unsigned int)); static int sh_adjust_cost PARAMS ((rtx, rtx, rtx, int)); /* Initialize the GCC target structure. */ -#undef TARGET_VALID_DECL_ATTRIBUTE -#define TARGET_VALID_DECL_ATTRIBUTE sh_valid_decl_attribute +#undef TARGET_ATTRIBUTE_TABLE +#define TARGET_ATTRIBUTE_TABLE sh_attribute_table #undef TARGET_ASM_FUNCTION_EPILOGUE #define TARGET_ASM_FUNCTION_EPILOGUE sh_output_function_epilogue @@ -269,7 +272,7 @@ print_operand (stream, x, code) if ((lookup_attribute ("interrupt_handler", - DECL_MACHINE_ATTRIBUTES (current_function_decl))) + DECL_ATTRIBUTES (current_function_decl))) != NULL_TREE) interrupt_handler = 1; else @@ -3964,7 +3967,7 @@ calc_live_regs (count_ptr, live_regs_mask2) if ((lookup_attribute ("interrupt_handler", - DECL_MACHINE_ATTRIBUTES (current_function_decl))) + DECL_ATTRIBUTES (current_function_decl))) != NULL_TREE) interrupt_handler = 1; else @@ -4058,7 +4061,7 @@ sh_expand_prologue () current_function_interrupt = lookup_attribute ("interrupt_handler", - DECL_MACHINE_ATTRIBUTES (current_function_decl)) + DECL_ATTRIBUTES (current_function_decl)) != NULL_TREE; /* We have pretend args if we had an object sent partially in registers @@ -4656,11 +4659,7 @@ sh_insert_attributes (node, attributes) return; } -/* Return nonzero if ATTR is a valid attribute for DECL. - ATTRIBUTES are any existing attributes and ARGS are the arguments - supplied with ATTR. - - Supported attributes: +/* Supported attributes: interrupt_handler -- specifies this function is an interrupt handler. @@ -4670,59 +4669,110 @@ sh_insert_attributes (node, attributes) trap_exit -- use a trapa to exit an interrupt function instead of an rte instruction. */ -static int -sh_valid_decl_attribute (decl, attributes, attr, args) - tree decl; - tree attributes ATTRIBUTE_UNUSED; - tree attr; - tree args; +const struct attribute_spec sh_attribute_table[] = { - if (TREE_CODE (decl) != FUNCTION_DECL) - return 0; + /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */ + { "interrupt_handler", 0, 0, true, false, false, sh_handle_interrupt_handler_attribute }, + { "sp_switch", 1, 1, true, false, false, sh_handle_sp_switch_attribute }, + { "trap_exit", 1, 1, true, false, false, sh_handle_trap_exit_attribute }, + { NULL, 0, 0, false, false, false, NULL } +}; - if (is_attribute_p ("interrupt_handler", attr)) +/* Handle an "interrupt_handler" attribute; arguments as in + struct attribute_spec.handler. */ +static tree +sh_handle_interrupt_handler_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) { - return 1; + warning ("`%s' attribute only applies to functions", + IDENTIFIER_POINTER (name)); + *no_add_attrs = true; } - if (is_attribute_p ("sp_switch", attr)) + return NULL_TREE; +} + +/* Handle an "sp_switch" attribute; arguments as in + struct attribute_spec.handler. */ +static tree +sh_handle_sp_switch_attribute (node, name, args, flags, no_add_attrs) + tree *node; + tree name; + tree args; + int flags ATTRIBUTE_UNUSED; + bool *no_add_attrs; +{ + if (TREE_CODE (*node) != FUNCTION_DECL) + { + warning ("`%s' attribute only applies to functions", + IDENTIFIER_POINTER (name)); + *no_add_attrs = true; + } + else if (!pragma_interrupt) { /* The sp_switch attribute only has meaning for interrupt functions. */ - if (!pragma_interrupt) - return 0; - - /* sp_switch must have an argument. */ - if (!args || TREE_CODE (args) != TREE_LIST) - return 0; - + warning ("`%s' attribute only applies to interrupt functions", + IDENTIFIER_POINTER (name)); + *no_add_attrs = true; + } + else if (TREE_CODE (TREE_VALUE (args)) != STRING_CST) + { /* The argument must be a constant string. */ - if (TREE_CODE (TREE_VALUE (args)) != STRING_CST) - return 0; - + warning ("`%s' attribute argument not a string constant", + IDENTIFIER_POINTER (name)); + *no_add_attrs = true; + } + else + { sp_switch = gen_rtx_SYMBOL_REF (VOIDmode, TREE_STRING_POINTER (TREE_VALUE (args))); - return 1; } - if (is_attribute_p ("trap_exit", attr)) + return NULL_TREE; +} + +/* Handle an "trap_exit" attribute; arguments as in + struct attribute_spec.handler. */ +static tree +sh_handle_trap_exit_attribute (node, name, args, flags, no_add_attrs) + tree *node; + tree name; + tree args; + int flags ATTRIBUTE_UNUSED; + bool *no_add_attrs; +{ + if (TREE_CODE (*node) != FUNCTION_DECL) + { + warning ("`%s' attribute only applies to functions", + IDENTIFIER_POINTER (name)); + *no_add_attrs = true; + } + else if (!pragma_interrupt) { /* The trap_exit attribute only has meaning for interrupt functions. */ - if (!pragma_interrupt) - return 0; - - /* trap_exit must have an argument. */ - if (!args || TREE_CODE (args) != TREE_LIST) - return 0; - + warning ("`%s' attribute only applies to interrupt functions", + IDENTIFIER_POINTER (name)); + *no_add_attrs = true; + } + else if (TREE_CODE (TREE_VALUE (args)) != INTEGER_CST) + { /* The argument must be a constant integer. */ - if (TREE_CODE (TREE_VALUE (args)) != INTEGER_CST) - return 0; - + warning ("`%s' attribute argument not an integer constant", + IDENTIFIER_POINTER (name)); + *no_add_attrs = true; + } + else + { trap_exit = TREE_INT_CST_LOW (TREE_VALUE (args)); - return 1; } - return 0; + return NULL_TREE; } diff --git a/gcc/config/stormy16/stormy16.c b/gcc/config/stormy16/stormy16.c index ebb9be74064..6ecf8ae819e 100644 --- a/gcc/config/stormy16/stormy16.c +++ b/gcc/config/stormy16/stormy16.c @@ -1909,30 +1909,34 @@ stormy16_interrupt_function_p () return lookup_attribute ("interrupt", attributes) != NULL_TREE; } -/* If defined, a C function which returns nonzero if IDENTIFIER - with arguments ARGS is a valid machine specific attribute for TYPE. - The attributes in ATTRIBUTES have previously been assigned to TYPE. */ -#undef TARGET_VALID_TYPE_ATTRIBUTE -#define TARGET_VALID_TYPE_ATTRIBUTE stormy16_valid_type_attribute -static int stormy16_valid_type_attribute PARAMS ((tree TYPE, - tree ATTRIBUTES, - tree IDENTIFIER, - tree ARGS)); - -static int -stormy16_valid_type_attribute (type, attributes, identifier, args) - tree type; - tree attributes ATTRIBUTE_UNUSED; - tree identifier; - tree args ATTRIBUTE_UNUSED; +#undef TARGET_ATTRIBUTE_TABLE +#define TARGET_ATTRIBUTE_TABLE stormy16_attribute_table +static tree stormy16_handle_interrupt_attribute PARAMS ((tree *, tree, tree, int, bool *)); +static const struct attribute_spec stormy16_attribute_table[] = { - if (TREE_CODE (type) != FUNCTION_TYPE) - return 0; - - if (is_attribute_p ("interrupt", identifier)) - return 1; + /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */ + { "interrupt", 0, 0, false, true, true, stormy16_handle_interrupt_attribute }, + { NULL, 0, 0, false, false, false, NULL } +}; - return 0; +/* Handle an "interrupt" attribute; + arguments as in struct attribute_spec.handler. */ +static tree +stormy16_handle_interrupt_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_TYPE) + { + warning ("`%s' attribute only applies to functions", + IDENTIFIER_POINTER (name)); + *no_add_attrs = true; + } + + return NULL_TREE; } struct gcc_target targetm = TARGET_INITIALIZER; diff --git a/gcc/config/stormy16/stormy16.h b/gcc/config/stormy16/stormy16.h index a6badd17ba2..d5920bcbaa0 100644 --- a/gcc/config/stormy16/stormy16.h +++ b/gcc/config/stormy16/stormy16.h @@ -1975,7 +1975,7 @@ enum reg_class FUNDECL is a C variable whose value is a tree node that describes the function in question. Normally it is a node of type `FUNCTION_DECL' that describes the declaration of the function. From this it is possible to - obtain the DECL_MACHINE_ATTRIBUTES of the function. + obtain the DECL_ATTRIBUTES of the function. FUNTYPE is a C variable whose value is a tree node that describes the function in question. Normally it is a node of type `FUNCTION_TYPE' that diff --git a/gcc/config/v850/v850-c.c b/gcc/config/v850/v850-c.c index d541a6657a3..84aef1fe4d3 100644 --- a/gcc/config/v850/v850-c.c +++ b/gcc/config/v850/v850-c.c @@ -35,7 +35,7 @@ Boston, MA 02111-1307, USA. */ static int pop_data_area PARAMS ((v850_data_area)); static int push_data_area PARAMS ((v850_data_area)); -static int mark_current_function_as_interrupt PARAMS ((void)); +static void mark_current_function_as_interrupt PARAMS ((void)); /* Push a data area onto the stack. */ @@ -85,7 +85,7 @@ pop_data_area (data_area) /* Set the machine specific 'interrupt' attribute on the current function. */ -static int +static void mark_current_function_as_interrupt () { tree name; @@ -104,8 +104,8 @@ mark_current_function_as_interrupt () return 0; } - return valid_machine_attribute - (name, NULL_TREE, current_function_decl, NULL_TREE); + decl_attributes (¤t_function_decl, + tree_cons (name, NULL_TREE, NULL_TREE), 0); } diff --git a/gcc/config/v850/v850.c b/gcc/config/v850/v850.c index 8ce09bf3e5b..ea83c153164 100644 --- a/gcc/config/v850/v850.c +++ b/gcc/config/v850/v850.c @@ -53,7 +53,9 @@ static int const_costs_int PARAMS ((HOST_WIDE_INT, int)); static void substitute_ep_register PARAMS ((rtx, rtx, int, int, rtx *, rtx *)); static int ep_memory_offset PARAMS ((enum machine_mode, int)); static void v850_set_data_area PARAMS ((tree, v850_data_area)); -static int v850_valid_decl_attribute PARAMS ((tree, tree, tree, tree)); +const struct attribute_spec v850_attribute_table[]; +static tree v850_handle_interrupt_attribute PARAMS ((tree *, tree, tree, int, bool *)); +static tree v850_handle_data_area_attribute PARAMS ((tree *, tree, tree, int, bool *)); static void v850_insert_attributes PARAMS ((tree, tree *)); /* True if the current function has anonymous arguments. */ @@ -84,8 +86,8 @@ static int v850_interrupt_cache_p = FALSE; static int v850_interrupt_p = FALSE; /* Initialize the GCC target structure. */ -#undef TARGET_VALID_DECL_ATTRIBUTE -#define TARGET_VALID_DECL_ATTRIBUTE v850_valid_decl_attribute +#undef TARGET_ATTRIBUTE_TABLE +#define TARGET_ATTRIBUTE_TABLE v850_attribute_table #undef TARGET_INSERT_ATTRIBUTES #define TARGET_INSERT_ATTRIBUTES v850_insert_attributes @@ -1978,13 +1980,13 @@ v850_data_area v850_get_data_area (decl) tree decl; { - if (lookup_attribute ("sda", DECL_MACHINE_ATTRIBUTES (decl)) != NULL_TREE) + if (lookup_attribute ("sda", DECL_ATTRIBUTES (decl)) != NULL_TREE) return DATA_AREA_SDA; - if (lookup_attribute ("tda", DECL_MACHINE_ATTRIBUTES (decl)) != NULL_TREE) + if (lookup_attribute ("tda", DECL_ATTRIBUTES (decl)) != NULL_TREE) return DATA_AREA_TDA; - if (lookup_attribute ("zda", DECL_MACHINE_ATTRIBUTES (decl)) != NULL_TREE) + if (lookup_attribute ("zda", DECL_ATTRIBUTES (decl)) != NULL_TREE) return DATA_AREA_ZDA; return DATA_AREA_NORMAL; @@ -2008,62 +2010,92 @@ v850_set_data_area (decl, data_area) return; } - DECL_MACHINE_ATTRIBUTES (decl) = tree_cons - (name, NULL, DECL_MACHINE_ATTRIBUTES (decl)); + DECL_ATTRIBUTES (decl) = tree_cons + (name, NULL, DECL_ATTRIBUTES (decl)); } -/* Return nonzero if ATTR is a valid attribute for DECL. - ARGS are the arguments supplied with ATTR. */ +const struct attribute_spec v850_attribute_table[] = +{ + /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */ + { "interrupt_handler", 0, 0, true, false, false, v850_handle_interrupt_attribute }, + { "interrupt", 0, 0, true, false, false, v850_handle_interrupt_attribute }, + { "sda", 0, 0, true, false, false, v850_handle_data_area_attribute }, + { "tda", 0, 0, true, false, false, v850_handle_data_area_attribute }, + { "zda", 0, 0, true, false, false, v850_handle_data_area_attribute }, + { NULL, 0, 0, false, false, false, NULL } +}; -static int -v850_valid_decl_attribute (decl, unused, attr, args) - tree decl; - tree unused ATTRIBUTE_UNUSED; - tree attr; - tree args; +/* Handle an "interrupt" attribute; arguments as in + struct attribute_spec.handler. */ +static tree +v850_handle_interrupt_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) + { + warning ("`%s' attribute only applies to functions", + IDENTIFIER_POINTER (name)); + *no_add_attrs = true; + } + + return NULL_TREE; +} + +/* Handle a "sda", "tda" or "zda" attribute; arguments as in + struct attribute_spec.handler. */ +static tree +v850_handle_data_area_attribute (node, name, args, flags, no_add_attrs) + tree *node; + tree name; + tree args ATTRIBUTE_UNUSED; + int flags ATTRIBUTE_UNUSED; + bool *no_add_attrs; { v850_data_area data_area; v850_data_area area; - - if (args != NULL_TREE) - return 0; - - if (is_attribute_p ("interrupt_handler", attr) - || is_attribute_p ("interrupt", attr)) - return TREE_CODE (decl) == FUNCTION_DECL; + tree decl = *node; /* Implement data area attribute. */ - if (is_attribute_p ("sda", attr)) + if (is_attribute_p ("sda", name)) data_area = DATA_AREA_SDA; - else if (is_attribute_p ("tda", attr)) + else if (is_attribute_p ("tda", name)) data_area = DATA_AREA_TDA; - else if (is_attribute_p ("zda", attr)) + else if (is_attribute_p ("zda", name)) data_area = DATA_AREA_ZDA; else - return 0; + abort (); switch (TREE_CODE (decl)) { case VAR_DECL: if (current_function_decl != NULL_TREE) - error_with_decl (decl, "\ + { + error_with_decl (decl, "\ a data area attribute cannot be specified for local variables"); - + *no_add_attrs = true; + } + /* Drop through. */ case FUNCTION_DECL: area = v850_get_data_area (decl); if (area != DATA_AREA_NORMAL && data_area != area) - error_with_decl (decl, "\ + { + error_with_decl (decl, "\ data area of '%s' conflicts with previous declaration"); - - return 1; + *no_add_attrs = true; + } + break; default: break; } - - return 0; + + return NULL_TREE; } @@ -2083,13 +2115,13 @@ v850_interrupt_function_p (func) if (TREE_CODE (func) != FUNCTION_DECL) return 0; - a = lookup_attribute ("interrupt_handler", DECL_MACHINE_ATTRIBUTES (func)); + a = lookup_attribute ("interrupt_handler", DECL_ATTRIBUTES (func)); if (a != NULL_TREE) ret = 1; else { - a = lookup_attribute ("interrupt", DECL_MACHINE_ATTRIBUTES (func)); + a = lookup_attribute ("interrupt", DECL_ATTRIBUTES (func)); ret = a != NULL_TREE; } diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 8d0498f1ec6..345cef4b008 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,43 @@ +2001-09-21 Joseph S. Myers + + 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 + * 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. + 2001-09-15 Gabriel Dos Reis * Make-lang.in (cp/error.o): Depend on real.h diff --git a/gcc/cp/class.c b/gcc/cp/class.c index 1526a05142b..0c106c375bf 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -5293,7 +5293,7 @@ finish_struct (t, attributes) as necessary. */ unreverse_member_declarations (t); - cplus_decl_attributes (&t, attributes, NULL_TREE, 0); + cplus_decl_attributes (&t, attributes, (int) ATTR_FLAG_TYPE_IN_PLACE); /* Nadger the current location so that diagnostics point to the start of the struct, not the end. */ diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 04837da1d88..2662356451b 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -3734,7 +3734,7 @@ extern tree grokbitfield PARAMS ((tree, tree, tree)); extern tree groktypefield PARAMS ((tree, tree)); extern tree grokoptypename PARAMS ((tree, tree)); extern int copy_assignment_arg_p PARAMS ((tree, int)); -extern void cplus_decl_attributes PARAMS ((tree *, tree, tree, int)); +extern void cplus_decl_attributes PARAMS ((tree *, tree, int)); extern tree constructor_name_full PARAMS ((tree)); extern tree constructor_name PARAMS ((tree)); extern void defer_fn PARAMS ((tree)); @@ -4208,7 +4208,7 @@ extern tree walk_tree_without_duplicates PARAMS ((tree *, walk_tree_fn, void *)); extern tree copy_tree_r PARAMS ((tree *, int *, void *)); -extern int cp_valid_lang_attribute PARAMS ((tree, tree, tree, tree)); +extern const struct attribute_spec cp_attribute_table[]; extern tree make_ptrmem_cst PARAMS ((tree, tree)); extern tree cp_build_qualified_type_real PARAMS ((tree, int, int)); extern void remap_save_expr PARAMS ((tree *, splay_tree, tree, int *)); diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 924427273d4..60938a702ba 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -45,7 +45,7 @@ Boston, MA 02111-1307, USA. */ #include "tm_p.h" #include "target.h" -extern int (*valid_lang_attribute) PARAMS ((tree, tree, tree, tree)); +extern const struct attribute_spec *lang_attribute_table; #ifndef BOOL_TYPE_SIZE /* `bool' has size and alignment `1', on all platforms. */ @@ -3438,7 +3438,7 @@ duplicate_decls (newdecl, olddecl) /* Copy all the DECL_... slots specified in the new decl except for any that we copy here from the old type. */ - DECL_MACHINE_ATTRIBUTES (newdecl) + DECL_ATTRIBUTES (newdecl) = (*targetm.merge_decl_attributes) (olddecl, newdecl); if (TREE_CODE (newdecl) == TEMPLATE_DECL) @@ -3746,7 +3746,7 @@ duplicate_decls (newdecl, olddecl) /* NEWDECL contains the merged attribute lists. Update OLDDECL to be the same. */ - DECL_MACHINE_ATTRIBUTES (olddecl) = DECL_MACHINE_ATTRIBUTES (newdecl); + DECL_ATTRIBUTES (olddecl) = DECL_ATTRIBUTES (newdecl); return 1; } @@ -6493,7 +6493,7 @@ init_decl_processing () /* Show we use EH for cleanups. */ using_eh_for_cleanups (); - valid_lang_attribute = cp_valid_lang_attribute; + lang_attribute_table = cp_attribute_table; /* Maintain consistency. Perhaps we should just complain if they say -fwritable-strings? */ @@ -6986,7 +6986,7 @@ shadow_tag (declspecs) if (TYPE_FIELDS (t)) { tree decl = grokdeclarator (NULL_TREE, declspecs, NORMAL, 0, - NULL_TREE); + NULL); finish_anon_union (decl); } } @@ -7002,7 +7002,7 @@ groktypename (typename) return typename; return grokdeclarator (TREE_VALUE (typename), TREE_PURPOSE (typename), - TYPENAME, 0, NULL_TREE); + TYPENAME, 0, NULL); } /* Decode a declarator in an ordinary declaration or data definition. @@ -7031,7 +7031,6 @@ start_decl (declarator, declspecs, initialized, attributes, prefix_attributes) tree context; extern int have_extern_spec; extern int used_extern_spec; - tree attrlist; #if 0 /* See code below that used this. */ @@ -7046,13 +7045,10 @@ start_decl (declarator, declspecs, initialized, attributes, prefix_attributes) used_extern_spec = 1; } - if (attributes || prefix_attributes) - attrlist = build_tree_list (attributes, prefix_attributes); - else - attrlist = NULL_TREE; + attributes = chainon (attributes, prefix_attributes); decl = grokdeclarator (declarator, declspecs, NORMAL, initialized, - attrlist); + &attributes); if (decl == NULL_TREE || TREE_CODE (decl) == VOID_TYPE) return NULL_TREE; @@ -7119,7 +7115,7 @@ start_decl (declarator, declspecs, initialized, attributes, prefix_attributes) } /* Set attributes here so if duplicate decl, will have proper attributes. */ - cplus_decl_attributes (&decl, attributes, prefix_attributes, 0); + cplus_decl_attributes (&decl, attributes, 0); if (context && COMPLETE_TYPE_P (complete_type (context))) { @@ -8482,7 +8478,7 @@ start_handler_parms (declspecs, declarator) if (declspecs) { decl = grokdeclarator (declarator, declspecs, CATCHPARM, - 1, NULL_TREE); + 1, NULL); if (decl == NULL_TREE) error ("invalid catch parameter"); } @@ -9425,8 +9421,9 @@ check_special_function_return_type (sfk, type, optype) BITFIELD for a field with specified width. INITIALIZED is 1 if the decl has an initializer. - ATTRLIST is a TREE_LIST node with prefix attributes in TREE_VALUE and - normal attributes in TREE_PURPOSE, or NULL_TREE. + ATTRLIST is a pointer to the list of attributes, which may be NULL + if there are none; *ATTRLIST may be modified if attributes from inside + the declarator should be applied to the declaration. In the TYPENAME case, DECLARATOR is really an abstract declarator. It may also be so in the PARM case, for a prototype where the @@ -9464,7 +9461,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist) tree declarator; enum decl_context decl_context; int initialized; - tree attrlist; + tree *attrlist; { RID_BIT_TYPE specbits; int nclasses = 0; @@ -9487,7 +9484,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist) int bitfield = 0; #if 0 /* See the code below that used this. */ - tree decl_machine_attr = NULL_TREE; + tree decl_attr = NULL_TREE; #endif /* Set this to error_mark_node for FIELD_DECLs we could not handle properly. All FIELD_DECLs we build here have `init' put into their DECL_INITIAL. */ @@ -9506,8 +9503,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist) tree raises = NULL_TREE; int template_count = 0; tree in_namespace = NULL_TREE; - tree inner_attrs; - int ignore_attrs; + tree returned_attrs = NULL_TREE; RIDBIT_RESET_ALL (specbits); if (decl_context == FUNCDEF) @@ -9598,24 +9594,22 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist) cp_finish_decl so we can get the variable initialized... */ - tree attributes, prefix_attributes; + tree attributes; *next = TREE_OPERAND (decl, 0); init = CALL_DECLARATOR_PARMS (decl); if (attrlist) { - attributes = TREE_PURPOSE (attrlist); - prefix_attributes = TREE_VALUE (attrlist); + attributes = *attrlist; } else { attributes = NULL_TREE; - prefix_attributes = NULL_TREE; } decl = start_decl (declarator, declspecs, 1, - attributes, prefix_attributes); + attributes, NULL_TREE); decl_type_access_control (decl); if (decl) { @@ -9953,7 +9947,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist) type = TREE_TYPE (t); #if 0 /* See the code below that used this. */ - decl_machine_attr = DECL_MACHINE_ATTRIBUTES (id); + decl_attr = DECL_ATTRIBUTES (id); #endif typedef_decl = t; } @@ -10312,9 +10306,6 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist) Descend through it, creating more complex types, until we reach the declared identifier (or NULL_TREE, in an absolute declarator). */ - inner_attrs = NULL_TREE; - ignore_attrs = 0; - while (declarator && TREE_CODE (declarator) != IDENTIFIER_NODE && TREE_CODE (declarator) != TEMPLATE_ID_EXPR) { @@ -10363,28 +10354,30 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist) } } - /* See the comment for the TREE_LIST case, below. */ - if (ignore_attrs) - ignore_attrs = 0; - else if (inner_attrs) - { - decl_attributes (&type, inner_attrs, 0); - inner_attrs = NULL_TREE; - } - switch (TREE_CODE (declarator)) { case TREE_LIST: { /* We encode a declarator with embedded attributes using - a TREE_LIST. The attributes apply to the declarator - directly inside them, so we have to skip an iteration - before applying them to the type. If the declarator just - inside is the declarator-id, we apply the attrs to the - decl itself. */ - inner_attrs = TREE_PURPOSE (declarator); - ignore_attrs = 1; + a TREE_LIST. */ + tree attrs = TREE_PURPOSE (declarator); + tree inner_decl; declarator = TREE_VALUE (declarator); + inner_decl = declarator; + while (inner_decl != NULL_TREE + && TREE_CODE (inner_decl) == TREE_LIST) + inner_decl = TREE_VALUE (inner_decl); + int attr_flags = 0; + if (inner_decl == NULL_TREE + || TREE_CODE (inner_decl) == IDENTIFIER_NODE) + attr_flags |= (int) ATTR_FLAG_DECL_NEXT; + if (TREE_CODE (inner_decl) == CALL_EXPR) + attr_flags |= (int) ATTR_FLAG_FUNCTION_NEXT; + if (TREE_CODE (inner_decl) == ARRAY_REF) + attr_flags |= (int) ATTR_FLAG_ARRAY_NEXT; + returned_attrs = decl_attributes (&type, + chainon (returned_attrs, attrs), + attr_flags); } break; @@ -10883,15 +10876,12 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist) } } - /* See the comment for the TREE_LIST case, above. */ - if (inner_attrs) + if (returned_attrs) { - if (! ignore_attrs) - decl_attributes (&type, inner_attrs, 0); - else if (attrlist) - TREE_VALUE (attrlist) = chainon (inner_attrs, TREE_VALUE (attrlist)); + if (attrlist) + *attrlist = chainon (returned_attrs, *attrlist); else - attrlist = build_tree_list (NULL_TREE, inner_attrs); + attrlist = &returned_attrs; } /* Now TYPE has the actual type. */ @@ -11302,8 +11292,8 @@ friend declaration requires class-key, i.e. `friend %#T'", return decl; #if 0 /* This clobbers the attrs stored in `decl' from `attrlist'. */ - /* The decl and setting of decl_machine_attr is also turned off. */ - decl = build_decl_attribute_variant (decl, decl_machine_attr); + /* The decl and setting of decl_attr is also turned off. */ + decl = build_decl_attribute_variant (decl, decl_attr); #endif /* [class.conv.ctor] @@ -11401,7 +11391,7 @@ friend declaration requires class-key, i.e. `friend %#T'", } t = do_friend (ctype, declarator, decl, - last_function_parms, attrlist, flags, quals, + last_function_parms, *attrlist, flags, quals, funcdef_flag); } if (t && funcdef_flag) @@ -11838,7 +11828,7 @@ grokparms (first_parm) break; decl = grokdeclarator (TREE_VALUE (decl), TREE_PURPOSE (decl), - PARM, init != NULL_TREE, NULL_TREE); + PARM, init != NULL_TREE, NULL); if (! decl || TREE_TYPE (decl) == error_mark_node) continue; @@ -13269,7 +13259,7 @@ start_function (declspecs, declarator, attrs, flags) } else { - decl1 = grokdeclarator (declarator, declspecs, FUNCDEF, 1, NULL_TREE); + decl1 = grokdeclarator (declarator, declspecs, FUNCDEF, 1, NULL); /* If the declarator is not suitable for a function definition, cause a syntax error. */ if (decl1 == NULL_TREE || TREE_CODE (decl1) != FUNCTION_DECL) return 0; @@ -13554,7 +13544,7 @@ start_function (declspecs, declarator, attrs, flags) pushlevel (0); current_binding_level->parm_flag = 1; - cplus_decl_attributes (&decl1, NULL_TREE, attrs, 0); + cplus_decl_attributes (&decl1, attrs, 0); /* Promote the value to int before returning it. */ if (c_promoting_integer_type_p (restype)) @@ -14056,7 +14046,7 @@ start_method (declspecs, declarator, attrlist) tree declarator, declspecs, attrlist; { tree fndecl = grokdeclarator (declarator, declspecs, MEMFUNCDEF, 0, - attrlist); + &attrlist); /* Something too ugly to handle. */ if (fndecl == NULL_TREE) diff --git a/gcc/cp/decl.h b/gcc/cp/decl.h index c5417d1ea48..6f1418a3a3e 100644 --- a/gcc/cp/decl.h +++ b/gcc/cp/decl.h @@ -31,7 +31,7 @@ enum decl_context }; /* We need this in here to get the decl_context definition. */ -extern tree grokdeclarator PARAMS ((tree, tree, enum decl_context, int, tree)); +extern tree grokdeclarator PARAMS ((tree, tree, enum decl_context, int, tree *)); /* Parsing a function declarator leaves a list of parameter names or a chain or parameter decls here. */ diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c index 5c62acaa28d..28236efb3e5 100644 --- a/gcc/cp/decl2.c +++ b/gcc/cp/decl2.c @@ -1531,7 +1531,7 @@ grokfield (declarator, declspecs, init, asmspec_tree, attrlist) && TREE_CHAIN (init) == NULL_TREE) init = NULL_TREE; - value = grokdeclarator (declarator, declspecs, FIELD, init != 0, attrlist); + value = grokdeclarator (declarator, declspecs, FIELD, init != 0, &attrlist); if (! value || value == error_mark_node) /* friend or constructor went bad. */ return value; @@ -1628,8 +1628,7 @@ grokfield (declarator, declspecs, init, asmspec_tree, attrlist) value = push_template_decl (value); if (attrlist) - cplus_decl_attributes (&value, TREE_PURPOSE (attrlist), - TREE_VALUE (attrlist), 0); + cplus_decl_attributes (&value, attrlist, 0); if (TREE_CODE (value) == VAR_DECL) { @@ -1679,7 +1678,7 @@ grokbitfield (declarator, declspecs, width) tree declarator, declspecs, width; { register tree value = grokdeclarator (declarator, declspecs, BITFIELD, - 0, NULL_TREE); + 0, NULL); if (! value) return NULL_TREE; /* friends went bad. */ @@ -1735,7 +1734,7 @@ tree grokoptypename (declspecs, declarator) tree declspecs, declarator; { - tree t = grokdeclarator (declarator, declspecs, TYPENAME, 0, NULL_TREE); + tree t = grokdeclarator (declarator, declspecs, TYPENAME, 0, NULL); return mangle_conv_op_name_for_type (t); } @@ -1824,8 +1823,8 @@ grok_function_init (decl, init) } void -cplus_decl_attributes (decl, attributes, prefix_attributes, flags) - tree *decl, attributes, prefix_attributes; +cplus_decl_attributes (decl, attributes, flags) + tree *decl, attributes; int flags; { if (*decl == NULL_TREE || *decl == void_type_node) @@ -1834,7 +1833,7 @@ cplus_decl_attributes (decl, attributes, prefix_attributes, flags) if (TREE_CODE (*decl) == TEMPLATE_DECL) decl = &DECL_TEMPLATE_RESULT (*decl); - decl_attributes (decl, chainon (attributes, prefix_attributes), flags); + decl_attributes (decl, attributes, flags); if (TREE_CODE (*decl) == TYPE_DECL) SET_IDENTIFIER_TYPE_VALUE (DECL_NAME (*decl), TREE_TYPE (*decl)); @@ -2371,17 +2370,9 @@ import_export_class (ctype) if (CLASSTYPE_INTERFACE_ONLY (ctype)) return; - if ((*targetm.valid_type_attribute) (ctype, - TYPE_ATTRIBUTES (ctype), - get_identifier ("dllimport"), - NULL_TREE) - && lookup_attribute ("dllimport", TYPE_ATTRIBUTES (ctype))) + if (lookup_attribute ("dllimport", TYPE_ATTRIBUTES (ctype))) import_export = -1; - else if ((*targetm.valid_type_attribute) (ctype, - TYPE_ATTRIBUTES (ctype), - get_identifier ("dllexport"), - NULL_TREE) - && lookup_attribute ("dllexport", TYPE_ATTRIBUTES (ctype))) + else if (lookup_attribute ("dllexport", TYPE_ATTRIBUTES (ctype))) import_export = 1; /* If we got -fno-implicit-templates, we import template classes that diff --git a/gcc/cp/friend.c b/gcc/cp/friend.c index f7ff9848a6f..d6d720cb380 100644 --- a/gcc/cp/friend.c +++ b/gcc/cp/friend.c @@ -309,7 +309,6 @@ do_friend (ctype, declarator, decl, parmdecls, attrlist, int funcdef_flag; { int is_friend_template = 0; - tree prefix_attributes, attributes; /* Every decl that gets here is a friend of something. */ DECL_FRIEND_P (decl) = 1; @@ -435,19 +434,8 @@ do_friend (ctype, declarator, decl, parmdecls, attrlist, handle them in start_decl_1, but since this is a friend decl start_decl_1 never gets to see it. */ - if (attrlist) - { - attributes = TREE_PURPOSE (attrlist); - prefix_attributes = TREE_VALUE (attrlist); - } - else - { - attributes = NULL_TREE; - prefix_attributes = NULL_TREE; - } - /* Set attributes here so if duplicate decl, will have proper attributes. */ - cplus_decl_attributes (&decl, attributes, prefix_attributes, 0); + cplus_decl_attributes (&decl, attrlist, 0); return decl; } diff --git a/gcc/cp/parse.y b/gcc/cp/parse.y index 3b890221912..9801c3817fa 100644 --- a/gcc/cp/parse.y +++ b/gcc/cp/parse.y @@ -164,7 +164,7 @@ parse_field (declarator, attributes, asmspec, init) tree declarator, attributes, asmspec, init; { tree d = grokfield (declarator, current_declspecs, init, asmspec, - build_tree_list (attributes, prefix_attributes)); + chainon (attributes, prefix_attributes)); decl_type_access_control (d); return d; } @@ -182,7 +182,7 @@ parse_bitfield (declarator, attributes, width) tree declarator, attributes, width; { tree d = grokbitfield (declarator, current_declspecs, width); - cplus_decl_attributes (&d, attributes, prefix_attributes, 0); + cplus_decl_attributes (&d, chainon (attributes, prefix_attributes), 0); decl_type_access_control (d); return d; } @@ -2639,11 +2639,9 @@ component_decl_1: $$ = NULL_TREE; } | notype_declarator maybeasm maybe_attribute maybe_init - { $$ = grokfield ($$, NULL_TREE, $4, $2, - build_tree_list ($3, NULL_TREE)); } + { $$ = grokfield ($$, NULL_TREE, $4, $2, $3); } | constructor_declarator maybeasm maybe_attribute maybe_init - { $$ = grokfield ($$, NULL_TREE, $4, $2, - build_tree_list ($3, NULL_TREE)); } + { $$ = grokfield ($$, NULL_TREE, $4, $2, $3); } | ':' expr_no_commas { $$ = grokbitfield (NULL_TREE, NULL_TREE, $2); } | error @@ -2661,10 +2659,9 @@ component_decl_1: { tree specs, attrs; split_specs_attrs ($1.t, &specs, &attrs); $$ = grokfield ($2, specs, $5, $3, - build_tree_list ($4, attrs)); } + chainon ($4, attrs)); } | component_constructor_declarator maybeasm maybe_attribute maybe_init - { $$ = grokfield ($$, NULL_TREE, $4, $2, - build_tree_list ($3, NULL_TREE)); } + { $$ = grokfield ($$, NULL_TREE, $4, $2, $3); } | using_decl { $$ = do_class_using_decl ($1); } diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 05ce365aa20..292513fb43e 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -1929,7 +1929,7 @@ process_template_parm (list, next) my_friendly_assert (TREE_CODE (TREE_PURPOSE (parm)) == TREE_LIST, 260); /* is a const-param */ parm = grokdeclarator (TREE_VALUE (parm), TREE_PURPOSE (parm), - PARM, 0, NULL_TREE); + PARM, 0, NULL); /* [temp.param] @@ -9356,7 +9356,7 @@ void do_decl_instantiation (declspecs, declarator, storage) tree declspecs, declarator, storage; { - tree decl = grokdeclarator (declarator, declspecs, NORMAL, 0, NULL_TREE); + tree decl = grokdeclarator (declarator, declspecs, NORMAL, 0, NULL); tree result = NULL_TREE; int extern_p = 0; diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c index 04e8add6a0d..32783adc728 100644 --- a/gcc/cp/tree.c +++ b/gcc/cp/tree.c @@ -50,6 +50,10 @@ static tree verify_stmt_tree_r PARAMS ((tree *, int *, void *)); static tree find_tree_r PARAMS ((tree *, int *, void *)); extern int cp_statement_code_p PARAMS ((enum tree_code)); +static tree handle_java_interface_attribute PARAMS ((tree *, tree, tree, int, bool *)); +static tree handle_com_interface_attribute PARAMS ((tree *, tree, tree, int, bool *)); +static tree handle_init_priority_attribute PARAMS ((tree *, tree, tree, int, bool *)); + /* If REF is an lvalue, returns the kind of lvalue that REF is. Otherwise, returns clk_none. If TREAT_CLASS_RVALUES_AS_LVALUES is non-zero, rvalues of class type are considered lvalues. */ @@ -2182,108 +2186,145 @@ pod_type_p (t) return 1; } -/* Return a 1 if ATTR_NAME and ATTR_ARGS denote a valid C++-specific - attribute for either declaration DECL or type TYPE and 0 otherwise. - Plugged into valid_lang_attribute. */ - -int -cp_valid_lang_attribute (attr_name, attr_args, decl, type) - tree attr_name; - tree attr_args ATTRIBUTE_UNUSED; - tree decl ATTRIBUTE_UNUSED; - tree type ATTRIBUTE_UNUSED; +/* Table of valid C++ attributes. */ +const struct attribute_spec cp_attribute_table[] = { - if (is_attribute_p ("java_interface", attr_name)) - { - if (attr_args != NULL_TREE - || decl != NULL_TREE - || ! CLASS_TYPE_P (type) - || ! TYPE_FOR_JAVA (type)) - { - error ("`java_interface' attribute can only be applied to Java class definitions"); - return 0; - } - TYPE_JAVA_INTERFACE (type) = 1; - return 1; - } - if (is_attribute_p ("com_interface", attr_name)) - { - static int warned; - if (attr_args != NULL_TREE - || decl != NULL_TREE - || ! CLASS_TYPE_P (type) - || type != TYPE_MAIN_VARIANT (type)) - { - warning ("`com_interface' attribute can only be applied to class definitions"); - return 0; - } + /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */ + { "java_interface", 0, 0, false, false, false, handle_java_interface_attribute }, + { "com_interface", 0, 0, false, false, false, handle_com_interface_attribute }, + { "init_priority", 1, 1, true, false, false, handle_init_priority_attribute }, + { NULL, 0, 0, false, false, false, NULL } +}; - if (! warned++) - warning ("\ -`com_interface' is obsolete; g++ vtables are now COM-compatible by default"); - return 1; - } - else if (is_attribute_p ("init_priority", attr_name)) +/* Handle a "java_interface" attribute; arguments as in + struct attribute_spec.handler. */ +static tree +handle_java_interface_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) + || !CLASS_TYPE_P (*node) + || !TYPE_FOR_JAVA (*node)) { - tree initp_expr = (attr_args ? TREE_VALUE (attr_args): NULL_TREE); - int pri; + error ("`%s' attribute can only be applied to Java class definitions", + IDENTIFIER_POINTER (name)); + *no_add_attrs = true; + return NULL_TREE; + } + if (!(flags & (int) ATTR_FLAG_TYPE_IN_PLACE)) + *node = build_type_copy (*node); + TYPE_JAVA_INTERFACE (*node) = 1; - if (initp_expr) - STRIP_NOPS (initp_expr); + return NULL_TREE; +} + +/* Handle a "com_interface" attribute; arguments as in + struct attribute_spec.handler. */ +static tree +handle_com_interface_attribute (node, name, args, flags, no_add_attrs) + tree *node; + tree name; + tree args ATTRIBUTE_UNUSED; + int flags ATTRIBUTE_UNUSED; + bool *no_add_attrs; +{ + static int warned; + + *no_add_attrs = true; + + if (DECL_P (*node) + || !CLASS_TYPE_P (*node) + || *node != TYPE_MAIN_VARIANT (*node)) + { + warning ("`%s' attribute can only be applied to class definitions", + IDENTIFIER_POINTER (name)); + return NULL_TREE; + } + + if (!warned++) + warning ("`%s' is obsolete; g++ vtables are now COM-compatible by default", + IDENTIFIER_POINTER (name)); + + return NULL_TREE; +} + +/* Handle an "init_priority" attribute; arguments as in + struct attribute_spec.handler. */ +static tree +handle_init_priority_attribute (node, name, args, flags, no_add_attrs) + tree *node; + tree name; + tree args; + int flags ATTRIBUTE_UNUSED; + bool *no_add_attrs; +{ + tree initp_expr = TREE_VALUE (args); + tree decl = *node; + tree type = TREE_TYPE (decl); + int pri; + + STRIP_NOPS (initp_expr); - if (!initp_expr || TREE_CODE (initp_expr) != INTEGER_CST) - { - error ("requested init_priority is not an integer constant"); - return 0; - } - - pri = TREE_INT_CST_LOW (initp_expr); - - type = strip_array_types (type); - - if (decl == NULL_TREE - || TREE_CODE (decl) != VAR_DECL - || ! TREE_STATIC (decl) - || DECL_EXTERNAL (decl) - || (TREE_CODE (type) != RECORD_TYPE - && TREE_CODE (type) != UNION_TYPE) - /* Static objects in functions are initialized the - first time control passes through that - function. This is not precise enough to pin down an - init_priority value, so don't allow it. */ - || current_function_decl) - { - error ("can only use init_priority attribute on file-scope definitions of objects of class type"); - return 0; - } - - if (pri > MAX_INIT_PRIORITY || pri <= 0) - { - error ("requested init_priority is out of range"); - return 0; - } - - /* Check for init_priorities that are reserved for - language and runtime support implementations.*/ - if (pri <= MAX_RESERVED_INIT_PRIORITY) - { - warning - ("requested init_priority is reserved for internal use"); - } - - if (SUPPORTS_INIT_PRIORITY) - { - DECL_INIT_PRIORITY (decl) = pri; - return 1; - } - else - { - error ("init_priority attribute is not supported on this platform"); - return 0; - } + if (!initp_expr || TREE_CODE (initp_expr) != INTEGER_CST) + { + error ("requested init_priority is not an integer constant"); + *no_add_attrs = true; + return NULL_TREE; } - return 0; + pri = TREE_INT_CST_LOW (initp_expr); + + type = strip_array_types (type); + + if (decl == NULL_TREE + || TREE_CODE (decl) != VAR_DECL + || !TREE_STATIC (decl) + || DECL_EXTERNAL (decl) + || (TREE_CODE (type) != RECORD_TYPE + && TREE_CODE (type) != UNION_TYPE) + /* Static objects in functions are initialized the + first time control passes through that + function. This is not precise enough to pin down an + init_priority value, so don't allow it. */ + || current_function_decl) + { + error ("can only use `%s' attribute on file-scope definitions of objects of class type", + IDENTIFIER_POINTER (name)); + *no_add_attrs = true; + return NULL_TREE; + } + + if (pri > MAX_INIT_PRIORITY || pri <= 0) + { + error ("requested init_priority is out of range"); + *no_add_attrs = true; + return NULL_TREE; + } + + /* Check for init_priorities that are reserved for + language and runtime support implementations.*/ + if (pri <= MAX_RESERVED_INIT_PRIORITY) + { + warning + ("requested init_priority is reserved for internal use"); + } + + if (SUPPORTS_INIT_PRIORITY) + { + DECL_INIT_PRIORITY (decl) = pri; + return NULL_TREE; + } + else + { + error ("`%s' attribute is not supported on this platform", + IDENTIFIER_POINTER (name)); + *no_add_attrs = true; + return NULL_TREE; + } } /* Return a new PTRMEM_CST of the indicated TYPE. The MEMBER is the diff --git a/gcc/doc/c-tree.texi b/gcc/doc/c-tree.texi index 9d9c25da6cd..350c9bca245 100644 --- a/gcc/doc/c-tree.texi +++ b/gcc/doc/c-tree.texi @@ -1658,14 +1658,11 @@ to the same declaration or type, or @code{NULL_TREE} if there are no further attributes in the list. Attributes may be attached to declarations and to types; these -attributes may be accessed with the following macros. At present only -machine-dependent attributes are stored in this way (other attributes -cause changes to the declaration or type or to other internal compiler -data structures, but are not themselves stored along with the -declaration or type), but in future all attributes may be stored like -this. +attributes may be accessed with the following macros. All attributes +are stored in this way, and many also cause other changes to the +declaration or type or to other internal compiler data structures. -@deftypefn {Tree Macro} tree DECL_MACHINE_ATTRIBUTES (tree @var{decl}) +@deftypefn {Tree Macro} tree DECL_ATTRIBUTES (tree @var{decl}) This macro returns the attributes on the declaration @var{decl}. @end deftypefn diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi index 08344960b52..ea60b57fbf6 100644 --- a/gcc/doc/extend.texi +++ b/gcc/doc/extend.texi @@ -2449,6 +2449,14 @@ language. Some details may vary for C++ and Objective-C@. Because of infelicities in the grammar for attributes, some forms described here may not be successfully parsed in all cases. +There are some problems with the semantics of attributes in C++. For +example, there are no manglings for attributes, although they may affect +code generation, so problems may arise when attributed types are used in +conjunction with templates or overloading. Similarly, @code{typeid} +does not distinguish between types with different attributes. Support +for attributes in C++ may be restricted in future to attributes on +declarations only, but not on nested declarators. + @xref{Function Attributes}, for details of the semantics of attributes applying to functions. @xref{Variable Attributes}, for details of the semantics of attributes applying to variables. @xref{Type Attributes}, @@ -2520,9 +2528,8 @@ defined is not complete until after the attribute specifiers. Otherwise, an attribute specifier appears as part of a declaration, counting declarations of unnamed parameters and type names, and relates to that declaration (which may be nested in another declaration, for -example in the case of a parameter declaration). In future, attribute -specifiers in some places may however apply to a particular declarator -within a declaration instead; these cases are noted below. Where an +example in the case of a parameter declaration), or to a particular declarator +within a declaration. Where an attribute specifier is applied to a parameter declared as a function or an array, it should apply to the function or array rather than the pointer to which the parameter is implicitly converted, but this is not @@ -2597,11 +2604,11 @@ ignored. An attribute specifier list may appear at the start of a nested declarator. At present, there are some limitations in this usage: the -attributes apply to the identifier declared, rather than to a specific -declarator. When attribute specifiers follow the @code{*} of a pointer +attributes correctly apply to the declarator, but for most individual +attributes the semantics this implies are not implemented. +When attribute specifiers follow the @code{*} of a pointer declarator, they may be mixed with any type qualifiers present. -The following describes intended future -semantics which make this syntax more useful only. It will make the +The following describes the formal semantics of this syntax. It will make the most sense if you are familiar with the formal specification of declarators in the ISO C standard. @@ -2642,8 +2649,26 @@ char *__attribute__((aligned(8))) *f; @noindent specifies the type ``pointer to 8-byte-aligned pointer to @code{char}''. -Note again that this describes intended future semantics, not current -implementation. +Note again that this does not work with most attributes; for example, +the usage of @samp{aligned} and @samp{noreturn} attributes given above +is not yet supported. + +For compatibility with existing code written for compiler versions that +did not implement attributes on nested declarators, some laxity is +allowed in the placing of attributes. If an attribute that only applies +to types is applied to a declaration, it will be treated as applying to +the type of that declaration. If an attribute that only applies to +declarations is applied to the type of a declaration, it will be treated +as applying to that declaration; and, for compatibility with code +placing the attributes immediately before the identifier declared, such +an attribute applied to a function return type will be treated as +applying to the function type, and such an attribute applied to an array +element type will be treated as applying to the array type. If an +attribute that only applies to function types is applied to a +pointer-to-function type, it will be treated as applying to the pointer +target type; if such an attribute is applied to a function return type +that is not a pointer-to-function type, it will be treated as applying +to the function type. @node Function Prototypes @section Prototypes and Old-Style Function Definitions diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi index 71e4cd953a1..721e16124d0 100644 --- a/gcc/doc/tm.texi +++ b/gcc/doc/tm.texi @@ -48,6 +48,7 @@ through the macros defined in the @file{.h} file. * Debugging Info:: Defining the format of debugging output. * Cross-compilation:: Handling floating point for cross-compilers. * Mode Switching:: Insertion of mode-switching instructions. +* Target Attributes:: Defining target-specific uses of @code{__attribute__}. * Misc:: Everything else. @end menu @@ -70,8 +71,8 @@ macros for which the default definition is inappropriate. For example: /* @r{Initialize the GCC target structure.} */ -#undef TARGET_VALID_TYPE_ATTRIBUTE -#define TARGET_VALID_TYPE_ATTRIBUTE @var{machine}_valid_type_attribute_p +#undef TARGET_COMP_TYPE_ATTRIBUTES +#define TARGET_COMP_TYPE_ATTRIBUTES @var{machine}_comp_type_attributes struct gcc_target targetm = TARGET_INITIALIZER; @end smallexample @@ -2528,7 +2529,7 @@ This describes the stack layout and calling conventions. * Caller Saves:: * Function Entry:: * Profiling:: -* Inlining and Tail Calls:: +* Tail Calls:: @end menu @node Frame Layout @@ -3222,7 +3223,7 @@ after the function returns. @var{fundecl} is a C variable whose value is a tree node that describes the function in question. Normally it is a node of type @code{FUNCTION_DECL} that describes the declaration of the function. -From this you can obtain the @code{DECL_MACHINE_ATTRIBUTES} of the function. +From this you can obtain the @code{DECL_ATTRIBUTES} of the function. @var{funtype} is a C variable whose value is a tree node that describes the function in question. Normally it is a node of type @@ -4204,18 +4205,11 @@ profiling when the frame pointer is omitted. @end table -@node Inlining and Tail Calls -@subsection Permitting inlining and tail calls -@cindex inlining +@node Tail Calls +@subsection Permitting tail calls +@cindex tail calls @table @code -@findex FUNCTION_ATTRIBUTE_INLINABLE_P -@item FUNCTION_ATTRIBUTE_INLINABLE_P (@var{decl}) -A C expression that evaluates to true if it is ok to inline @var{decl} -into the current function, despite its having target-specific -attributes. By default, if a function has a target specific attribute -attached to it, it will not be inlined. - @findex FUNCTION_OK_FOR_SIBCALL @item FUNCTION_OK_FOR_SIBCALL (@var{decl}) A C expression that evaluates to true if it is ok to perform a sibling @@ -8031,6 +8025,85 @@ Generate one or more insns to set @var{entity} to @var{mode}. the insn(s) are to be inserted. @end table +@node Target Attributes +@section Defining target-specific uses of @code{__attribute__} +@cindex target attributes +@cindex machine attributes +@cindex attributes, target-specific + +Target-specific attributes may be defined for functions, data and types. +These are described using the following target hooks; they also need to +be documented in @file{extend.texi}. + +@deftypevr {Target Hook} {const struct attribute_spec *} TARGET_ATTRIBUTE_TABLE +If defined, this target hook points to an array of @samp{struct +attribute_spec} (defined in @file{tree.h}) specifying the machine +specific attributes for this target and some of the restrictions on the +entities to which these attributes are applied and the arguments they +take. +@end deftypevr + +@deftypefn {Target Hook} int TARGET_COMP_TYPE_ATTRIBUTES (tree @var{type1}, tree @var{type2}) +If defined, this target hook is a function which returns zero if the attributes on +@var{type1} and @var{type2} are incompatible, one if they are compatible, +and two if they are nearly compatible (which causes a warning to be +generated). If this is not defined, machine-specific attributes are +supposed always to be compatible. +@end deftypefn + +@deftypefn {Target Hook} void TARGET_SET_DEFAULT_TYPE_ATTRIBUTES (tree @var{type}) +If defined, this target hook is a function which assigns default attributes to +newly defined @var{type}. +@end deftypefn + +@deftypefn {Target Hook} tree TARGET_MERGE_TYPE_ATTRIBUTES (tree @var{type1}, tree @var{type2}) +Define this target hook if the merging of type attributes needs special +handling. If defined, the result is a list of the combined +@code{TYPE_ATTRIBUTES} of @var{type1} and @var{type2}. It is assumed +that @code{comptypes} has already been called and returned 1. This +function may call @code{merge_attributes} to handle machine-independent +merging. +@end deftypefn + +@deftypefn {Target Hook} tree TARGET_MERGE_DECL_ATTRIBUTES (tree @var{olddecl}, tree @var{newdecl}) +Define this target hook if the merging of decl attributes needs special +handling. If defined, the result is a list of the combined +@code{DECL_ATTRIBUTES} of @var{olddecl} and @var{newdecl}. +@var{newdecl} is a duplicate declaration of @var{olddecl}. Examples of +when this is needed are when one attribute overrides another, or when an +attribute is nullified by a subsequent definition. This function may +call @code{merge_attributes} to handle machine-independent merging. + +@findex TARGET_DLLIMPORT_DECL_ATTRIBUTES +If the only target-specific handling you require is @samp{dllimport} for +Windows targets, you should define the macro +@code{TARGET_DLLIMPORT_DECL_ATTRIBUTES}. This links in a function +called @code{merge_dllimport_decl_attributes} which can then be defined +as the expansion of @code{TARGET_MERGE_DECL_ATTRIBUTES}. This is done +in @file{i386/cygwin.h} and @file{i386/i386.c}, for example. +@end deftypefn + +@deftypefn {Target Hook} void TARGET_INSERT_ATTRIBUTES (tree @var{node}, tree *@var{attr_ptr}) +Define this target hook if you want to be able to add attributes to a decl +when it is being created. This is normally useful for back ends which +wish to implement a pragma by using the attributes which correspond to +the pragma's effect. The @var{node} argument is the decl which is being +created. The @var{attr_ptr} argument is a pointer to the attribute list +for this decl. The list itself should not be modified, since it may be +shared with other decls, but attributes may be chained on the head of +the list and @code{*@var{attr_ptr}} modified to point to the new +attributes, or a copy of the list may be made if further changes are +needed. +@end deftypefn + +@deftypefn {Target Hook} bool TARGET_FUNCTION_ATTRIBUTE_INLINABLE_P (tree @var{fndecl}) +@cindex inlining +This target hook returns @code{true} if it is ok to inline @var{fndecl} +into the current function, despite its having target-specific +attributes, @code{false} otherwise. By default, if a function has a +target specific attribute attached to it, it will not be inlined. +@end deftypefn + @node Misc @section Miscellaneous Parameters @cindex parameters, miscellaneous @@ -8404,7 +8477,7 @@ other compilers for the same target. In general, we discourage definition of target-specific pragmas for GCC@. If the pragma can be implemented by attributes then you should consider -defining @samp{INSERT_ATTRIBUTES} as well. +defining the target hook @samp{TARGET_INSERT_ATTRIBUTES} as well. Preprocessor macros that appear on pragma lines are not expanded. All @samp{#pragma} directives that do not match any registered pragma are @@ -8484,74 +8557,7 @@ pack value of zero resets the behaviour to the default. Successive invocations of this pragma cause the previous values to be stacked, so that invocations of @samp{#pragma pack(pop)} will return to the previous value. -@end table -@deftypefn {Target Hook} int TARGET_VALID_DECL_ATTRIBUTE (tree @var{decl}, tree @var{attributes}, tree @var{identifier}, tree @var{args}) -If defined, this target hook is a function which returns nonzero if @var{identifier} with -arguments @var{args} is a valid machine specific attribute for @var{decl}. -The attributes in @var{attributes} have previously been assigned to @var{decl}. -@end deftypefn - -@deftypefn {Target Hook} int TARGET_VALID_TYPE_ATTRIBUTE (tree @var{type}, tree @var{attributes}, tree @var{identifier}, tree @var{args}) -If defined, this target hook is a function which returns nonzero if @var{identifier} with -arguments @var{args} is a valid machine specific attribute for @var{type}. -The attributes in @var{attributes} have previously been assigned to @var{type}. -@end deftypefn - -@deftypefn {Target Hook} int TARGET_COMP_TYPE_ATTRIBUTES (tree @var{type1}, tree @var{type2}) -If defined, this target hook is a function which returns zero if the attributes on -@var{type1} and @var{type2} are incompatible, one if they are compatible, -and two if they are nearly compatible (which causes a warning to be -generated). If this is not defined, machine-specific attributes are -supposed always to be compatible. -@end deftypefn - -@deftypefn {Target Hook} void TARGET_SET_DEFAULT_TYPE_ATTRIBUTES (tree @var{type}) -If defined, this target hook is a function which assigns default attributes to -newly defined @var{type}. -@end deftypefn - -@deftypefn {Target Hook} tree TARGET_MERGE_TYPE_ATTRIBUTES (tree @var{type1}, tree @var{type2}) -Define this target hook if the merging of type attributes needs special -handling. If defined, the result is a list of the combined -@code{TYPE_ATTRIBUTES} of @var{type1} and @var{type2}. It is assumed -that @code{comptypes} has already been called and returned 1. This -function may call @code{merge_attributes} to handle machine-independent -merging. -@end deftypefn - -@deftypefn {Target Hook} tree TARGET_MERGE_DECL_ATTRIBUTES (tree @var{olddecl}, tree @var{newdecl}) -Define this target hook if the merging of decl attributes needs special -handling. If defined, the result is a list of the combined -@code{DECL_MACHINE_ATTRIBUTES} of @var{olddecl} and @var{newdecl}. -@var{newdecl} is a duplicate declaration of @var{olddecl}. Examples of -when this is needed are when one attribute overrides another, or when an -attribute is nullified by a subsequent definition. This function may -call @code{merge_attributes} to handle machine-independent merging. - -@findex TARGET_DLLIMPORT_DECL_ATTRIBUTES -If the only target-specific handling you require is @samp{dllimport} for -Windows targets, you should define the macro -@code{TARGET_DLLIMPORT_DECL_ATTRIBUTES}. This links in a function -called @code{merge_dllimport_decl_attributes} which can then be defined -as the expansion of @code{TARGET_MERGE_DECL_ATTRIBUTES}. This is done -in @file{i386/cygwin.h} and @file{i386/i386.c}, for example. -@end deftypefn - -@deftypefn {Target Hook} void TARGET_INSERT_ATTRIBUTES (tree @var{node}, tree *@var{attr_ptr}) -Define this target hook if you want to be able to add attributes to a decl -when it is being created. This is normally useful for back ends which -wish to implement a pragma by using the attributes which correspond to -the pragma's effect. The @var{node} argument is the decl which is being -created. The @var{attr_ptr} argument is a pointer to the attribute list -for this decl. The list itself should not be modified, since it may be -shared with other decls, but attributes may be chained on the head of -the list and @code{*@var{attr_ptr}} modified to point to the new -attributes, or a copy of the list may be made if further changes are -needed. -@end deftypefn - -@table @code @findex DOLLARS_IN_IDENTIFIERS @item DOLLARS_IN_IDENTIFIERS Define this macro to control use of the character @samp{$} in identifier diff --git a/gcc/ggc-common.c b/gcc/ggc-common.c index 154d47b3f48..80de3802fed 100644 --- a/gcc/ggc-common.c +++ b/gcc/ggc-common.c @@ -453,7 +453,7 @@ ggc_mark_trees () ggc_mark_tree (DECL_INITIAL (t)); ggc_mark_tree (DECL_ABSTRACT_ORIGIN (t)); ggc_mark_tree (DECL_SECTION_NAME (t)); - ggc_mark_tree (DECL_MACHINE_ATTRIBUTES (t)); + ggc_mark_tree (DECL_ATTRIBUTES (t)); if (DECL_RTL_SET_P (t)) ggc_mark_rtx (DECL_RTL (t)); ggc_mark_rtx (DECL_LIVE_RANGE_RTL (t)); diff --git a/gcc/integrate.c b/gcc/integrate.c index db5993580d3..7887b36cf18 100644 --- a/gcc/integrate.c +++ b/gcc/integrate.c @@ -42,6 +42,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA #include "loop.h" #include "params.h" #include "ggc.h" +#include "target.h" #include "obstack.h" #define obstack_chunk_alloc xmalloc @@ -63,12 +64,6 @@ extern struct obstack *function_maybepermanent_obstack; ? (1 + (3 * list_length (DECL_ARGUMENTS (DECL))) / 2) \ : (8 * (8 + list_length (DECL_ARGUMENTS (DECL))))) #endif - -/* Decide whether a function with a target specific attribute - attached can be inlined. By default we disallow this. */ -#ifndef FUNCTION_ATTRIBUTE_INLINABLE_P -#define FUNCTION_ATTRIBUTE_INLINABLE_P(FNDECL) 0 -#endif /* Private type used by {get/has}_func_hard_reg_initial_val. */ @@ -82,6 +77,8 @@ typedef struct initial_value_struct { initial_value_pair *entries; } initial_value_struct; +static bool function_attribute_inlinable_p PARAMS ((tree)); + static void setup_initial_hard_reg_value_integration PARAMS ((struct function *, struct inline_remap *)); static rtvec initialize_for_inline PARAMS ((tree)); @@ -130,6 +127,38 @@ get_label_from_map (map, i) return x; } +/* Return false if the function FNDECL cannot be inlined on account of its + attributes, true otherwise. */ +static bool +function_attribute_inlinable_p (fndecl) + tree fndecl; +{ + bool has_machine_attr = false; + tree a; + + for (a = DECL_ATTRIBUTES (fndecl); a; a = TREE_CHAIN (a)) + { + tree name = TREE_PURPOSE (a); + int i; + + for (i = 0; targetm.attribute_table[i].name != NULL; i++) + { + if (is_attribute_p (targetm.attribute_table[i].name, name)) + { + has_machine_attr = true; + break; + } + } + if (has_machine_attr) + break; + } + + if (has_machine_attr) + return (*targetm.function_attribute_inlinable_p) (fndecl); + else + return true; +} + /* Zero if the current function (whose FUNCTION_DECL is FNDECL) is safe and reasonable to integrate into other functions. Nonzero means value is a warning msgid with a single %s @@ -250,9 +279,8 @@ function_cannot_inline_p (fndecl) /* If the function has a target specific attribute attached to it, then we assume that we should not inline it. This can be overriden - by the target if it defines FUNCTION_ATTRIBUTE_INLINABLE_P. */ - if (DECL_MACHINE_ATTRIBUTES (fndecl) - && ! FUNCTION_ATTRIBUTE_INLINABLE_P (fndecl)) + by the target if it defines TARGET_FUNCTION_ATTRIBUTE_INLINABLE_P. */ + if (!function_attribute_inlinable_p (fndecl)) return N_("function with target specific attribute(s) cannot be inlined"); return NULL; diff --git a/gcc/print-tree.c b/gcc/print-tree.c index c0550f7123e..f4476ba2d47 100644 --- a/gcc/print-tree.c +++ b/gcc/print-tree.c @@ -1,5 +1,5 @@ /* Prints out tree in human readable form - GNU C-compiler - Copyright (C) 1990, 1991, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000 + Copyright (C) 1990, 1991, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001 Free Software Foundation, Inc. This file is part of GCC. @@ -433,8 +433,8 @@ print_node (file, prefix, node, indent) } print_node_brief (file, "context", DECL_CONTEXT (node), indent + 4); - print_node_brief (file, "machine_attributes", - DECL_MACHINE_ATTRIBUTES (node), indent + 4); + print_node_brief (file, "attributes", + DECL_ATTRIBUTES (node), indent + 4); print_node_brief (file, "abstract_origin", DECL_ABSTRACT_ORIGIN (node), indent + 4); diff --git a/gcc/target-def.h b/gcc/target-def.h index 3282b3ca249..4b298bc5288 100644 --- a/gcc/target-def.h +++ b/gcc/target-def.h @@ -107,11 +107,11 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. /* All in tree.c. */ #define TARGET_MERGE_DECL_ATTRIBUTES merge_decl_attributes #define TARGET_MERGE_TYPE_ATTRIBUTES merge_type_attributes -#define TARGET_VALID_DECL_ATTRIBUTE default_valid_attribute_p -#define TARGET_VALID_TYPE_ATTRIBUTE default_valid_attribute_p +#define TARGET_ATTRIBUTE_TABLE default_target_attribute_table #define TARGET_COMP_TYPE_ATTRIBUTES default_comp_type_attributes #define TARGET_SET_DEFAULT_TYPE_ATTRIBUTES default_set_default_type_attributes #define TARGET_INSERT_ATTRIBUTES default_insert_attributes +#define TARGET_FUNCTION_ATTRIBUTE_INLINABLE_P default_function_attribute_inlinable_p /* In builtins.c. */ #define TARGET_INIT_BUILTINS default_init_builtins @@ -129,11 +129,11 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. TARGET_SCHED, \ TARGET_MERGE_DECL_ATTRIBUTES, \ TARGET_MERGE_TYPE_ATTRIBUTES, \ - TARGET_VALID_DECL_ATTRIBUTE, \ - TARGET_VALID_TYPE_ATTRIBUTE, \ + TARGET_ATTRIBUTE_TABLE, \ TARGET_COMP_TYPE_ATTRIBUTES, \ TARGET_SET_DEFAULT_TYPE_ATTRIBUTES, \ TARGET_INSERT_ATTRIBUTES, \ + TARGET_FUNCTION_ATTRIBUTE_INLINABLE_P, \ TARGET_INIT_BUILTINS, \ TARGET_EXPAND_BUILTIN, \ TARGET_SECTION_TYPE_FLAGS, \ diff --git a/gcc/target.h b/gcc/target.h index 8d73f496ba0..f7eca62368e 100644 --- a/gcc/target.h +++ b/gcc/target.h @@ -121,17 +121,8 @@ struct gcc_target /* Given two types, merge their attributes and return the result. */ tree (* merge_type_attributes) PARAMS ((tree, tree)); - /* Return nonzero if IDENTIFIER with arguments ARGS is a valid machine - specific attribute for DECL. The attributes in ATTRIBUTES have - previously been assigned to DECL. */ - int (* valid_decl_attribute) PARAMS ((tree decl, tree attributes, - tree identifier, tree args)); - - /* Return nonzero if IDENTIFIER with arguments ARGS is a valid machine - specific attribute for TYPE. The attributes in ATTRIBUTES have - previously been assigned to TYPE. */ - int (* valid_type_attribute) PARAMS ((tree type, tree attributes, - tree identifier, tree args)); + /* Table of machine attributes and functions to handle them. */ + const struct attribute_spec *attribute_table; /* Return zero if the attributes on TYPE1 and TYPE2 are incompatible, one if they are compatible and two if they are nearly compatible @@ -144,6 +135,10 @@ struct gcc_target /* Insert attributes on the newly created DECL. */ void (* insert_attributes) PARAMS ((tree decl, tree *attributes)); + /* Return true if FNDECL (which has at least one machine attribute) + can be inlined despite its machine attributes, false otherwise. */ + bool (* function_attribute_inlinable_p) PARAMS ((tree fndecl)); + /* Set up target-specific built-in functions. */ void (* init_builtins) PARAMS ((void)); diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 16d4816af73..74508a6c941 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2001-09-21 Joseph S. Myers + + Table-driven attributes. + * g++.dg/ext/attrib1.C: New test. + 2001-09-20 DJ Delorie * gcc.dg/20000926-1.c: Update expected warning messages. diff --git a/gcc/testsuite/g++.dg/ext/attrib1.C b/gcc/testsuite/g++.dg/ext/attrib1.C new file mode 100644 index 00000000000..2bd69e82a54 --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/attrib1.C @@ -0,0 +1,10 @@ +// Test for interpretation of attribute immediately before function name. +// Origin: Joseph Myers +// { dg-do compile } + +// An attribute immediately before the function name should in this +// case properly apply to the return type, but compatibility with +// existing code using this form requires it to apply to the function +// type instead in the case of attributes applying to function types, +// and to the declaration in the case of attributes applying to declarations. +int ****__attribute__((format(printf, 1, 2))) foo(const char *, ...); diff --git a/gcc/tree.c b/gcc/tree.c index 731791c8602..1741f6a7f02 100644 --- a/gcc/tree.c +++ b/gcc/tree.c @@ -2605,14 +2605,14 @@ build_expr_wfl (node, file, line, col) return wfl; } -/* Return a declaration like DDECL except that its DECL_MACHINE_ATTRIBUTE +/* Return a declaration like DDECL except that its DECL_ATTRIBUTES is ATTRIBUTE. */ tree build_decl_attribute_variant (ddecl, attribute) tree ddecl, attribute; { - DECL_MACHINE_ATTRIBUTES (ddecl) = attribute; + DECL_ATTRIBUTES (ddecl) = attribute; return ddecl; } @@ -2670,19 +2670,6 @@ build_type_attribute_variant (ttype, attribute) return ttype; } -/* Default value of targetm.valid_decl_attribute_p and - targetm.valid_type_attribute_p that always returns false. */ - -int -default_valid_attribute_p (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; -} - /* Default value of targetm.comp_type_attributes that always returns 1. */ int @@ -2710,116 +2697,20 @@ default_insert_attributes (decl, attr_ptr) { } -/* Return 1 if ATTR_NAME and ATTR_ARGS is valid for either declaration - DECL or type TYPE and 0 otherwise. Validity is determined the - target functions valid_decl_attribute and valid_machine_attribute. */ - -int -valid_machine_attribute (attr_name, attr_args, decl, type) - tree attr_name; - tree attr_args; - tree decl; - tree type; +/* Default value of targetm.attribute_table that is empty. */ +const struct attribute_spec default_target_attribute_table[] = { - tree type_attrs; + { NULL, 0, 0, false, false, false, NULL } +}; - if (TREE_CODE (attr_name) != IDENTIFIER_NODE) - abort (); - - if (decl) - { - tree decl_attrs = DECL_MACHINE_ATTRIBUTES (decl); - - if ((*targetm.valid_decl_attribute) (decl, decl_attrs, attr_name, - attr_args)) - { - tree attr = lookup_attribute (IDENTIFIER_POINTER (attr_name), - decl_attrs); - - if (attr != NULL_TREE) - { - /* Override existing arguments. Declarations are unique - so we can modify this in place. */ - TREE_VALUE (attr) = attr_args; - } - else - { - decl_attrs = tree_cons (attr_name, attr_args, decl_attrs); - decl = build_decl_attribute_variant (decl, decl_attrs); - } - - /* Don't apply the attribute to both the decl and the type. */ - return 1; - } - } - - type_attrs = TYPE_ATTRIBUTES (type); - if ((*targetm.valid_type_attribute) (type, type_attrs, attr_name, - attr_args)) - { - tree attr = lookup_attribute (IDENTIFIER_POINTER (attr_name), - type_attrs); - - if (attr != NULL_TREE) - { - /* 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 - { - /* If this is part of a declaration, create a type variant, - otherwise, this is part of a type definition, so add it - to the base type. */ - type_attrs = tree_cons (attr_name, attr_args, type_attrs); - if (decl != 0) - type = build_type_attribute_variant (type, type_attrs); - else - TYPE_ATTRIBUTES (type) = type_attrs; - } - - if (decl) - TREE_TYPE (decl) = type; - - return 1; - } - /* Handle putting a type attribute on pointer-to-function-type - by putting the attribute on the function type. */ - else if (POINTER_TYPE_P (type) - && TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE - && (*targetm.valid_type_attribute) (TREE_TYPE (type), type_attrs, - attr_name, attr_args)) - { - tree inner_type = TREE_TYPE (type); - tree inner_attrs = TYPE_ATTRIBUTES (inner_type); - tree attr = lookup_attribute (IDENTIFIER_POINTER (attr_name), - type_attrs); - - if (attr != NULL_TREE) - TREE_VALUE (attr) = attr_args; - else - { - inner_attrs = tree_cons (attr_name, attr_args, inner_attrs); - inner_type = build_type_attribute_variant (inner_type, - inner_attrs); - } - - if (decl) - TREE_TYPE (decl) = build_pointer_type (inner_type); - else - { - /* Clear TYPE_POINTER_TO for the old inner type, since - `type' won't be pointing to it anymore. */ - TYPE_POINTER_TO (TREE_TYPE (type)) = NULL_TREE; - TREE_TYPE (type) = inner_type; - } - - return 1; - } - - return 0; +/* Default value of targetm.function_attribute_inlinable_p that always + returns false. */ +bool +default_function_attribute_inlinable_p (fndecl) + tree fndecl ATTRIBUTE_UNUSED; +{ + /* By default, functions with machine attributes cannot be inlined. */ + return false; } /* Return non-zero if IDENT is a valid name for attribute ATTR, @@ -2873,7 +2764,9 @@ is_attribute_p (attr, ident) /* 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 not found. If the attribute appears more than once, this only + returns the first occurance; the TREE_CHAIN of the return value should + be passed back in if further occurances are wanted. */ tree lookup_attribute (attr_name, list) @@ -2915,19 +2808,29 @@ merge_attributes (a1, a2) else { /* Pick the longest list, and hang on the other list. */ - /* ??? For the moment we punt on the issue of attrs with args. */ if (list_length (a1) < list_length (a2)) attributes = a2, a2 = a1; for (; a2 != 0; a2 = TREE_CHAIN (a2)) - if (lookup_attribute (IDENTIFIER_POINTER (TREE_PURPOSE (a2)), - attributes) == NULL_TREE) - { - a1 = copy_node (a2); - TREE_CHAIN (a1) = attributes; - attributes = a1; - } + { + tree a; + for (a = lookup_attribute (IDENTIFIER_POINTER (TREE_PURPOSE (a2)), + attributes); + a != NULL_TREE; + a = lookup_attribute (IDENTIFIER_POINTER (TREE_PURPOSE (a2)), + TREE_CHAIN (a))) + { + if (simple_cst_equal (TREE_VALUE (a), TREE_VALUE (a2)) == 1) + break; + } + if (a == NULL_TREE) + { + a1 = copy_node (a2); + TREE_CHAIN (a1) = attributes; + attributes = a1; + } + } } } return attributes; @@ -2951,8 +2854,8 @@ tree merge_decl_attributes (olddecl, newdecl) tree olddecl, newdecl; { - return merge_attributes (DECL_MACHINE_ATTRIBUTES (olddecl), - DECL_MACHINE_ATTRIBUTES (newdecl)); + return merge_attributes (DECL_ATTRIBUTES (olddecl), + DECL_ATTRIBUTES (newdecl)); } #ifdef TARGET_DLLIMPORT_DECL_ATTRIBUTES @@ -2974,8 +2877,8 @@ merge_dllimport_decl_attributes (old, new) tree a; int delete_dllimport_p; - old = DECL_MACHINE_ATTRIBUTES (old); - new = DECL_MACHINE_ATTRIBUTES (new); + old = DECL_ATTRIBUTES (old); + new = DECL_ATTRIBUTES (new); /* What we need to do here is remove from `old' dllimport if it doesn't appear in `new'. dllimport behaves like extern: if a declaration is @@ -3345,8 +3248,15 @@ attribute_list_contained (l1, l2) for (; t2 != 0; t2 = TREE_CHAIN (t2)) { - tree attr - = lookup_attribute (IDENTIFIER_POINTER (TREE_PURPOSE (t2)), l1); + tree attr; + for (attr = lookup_attribute (IDENTIFIER_POINTER (TREE_PURPOSE (t2)), l1); + attr != NULL_TREE; + attr = lookup_attribute (IDENTIFIER_POINTER (TREE_PURPOSE (t2)), + TREE_CHAIN (attr))) + { + if (simple_cst_equal (TREE_VALUE (t2), TREE_VALUE (attr)) == 1) + break; + } if (attr == 0) return 0; diff --git a/gcc/tree.h b/gcc/tree.h index 8ef9156d8f1..aee84340355 100644 --- a/gcc/tree.h +++ b/gcc/tree.h @@ -1,5 +1,5 @@ /* Front-end tree definitions for GNU compiler. - Copyright (C) 1989, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000 + Copyright (C) 1989, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001 Free Software Foundation, Inc. This file is part of GCC. @@ -1337,9 +1337,8 @@ struct tree_type type, or NULL_TREE if the given decl has "file scope". */ #define DECL_CONTEXT(NODE) (DECL_CHECK (NODE)->decl.context) #define DECL_FIELD_CONTEXT(NODE) (FIELD_DECL_CHECK (NODE)->decl.context) -/* In a DECL this is the field where configuration dependent machine - attributes are store */ -#define DECL_MACHINE_ATTRIBUTES(NODE) (DECL_CHECK (NODE)->decl.machine_attributes) +/* In a DECL this is the field where attributes are stored. */ +#define DECL_ATTRIBUTES(NODE) (DECL_CHECK (NODE)->decl.attributes) /* In a FIELD_DECL, this is the field position, counting in bytes, of the byte containing the bit closest to the beginning of the structure. */ #define DECL_FIELD_OFFSET(NODE) (FIELD_DECL_CHECK (NODE)->decl.arguments) @@ -1754,7 +1753,7 @@ struct tree_decl tree abstract_origin; tree assembler_name; tree section_name; - tree machine_attributes; + tree attributes; rtx rtl; /* RTL representation for object. */ rtx live_range_rtl; @@ -2069,14 +2068,82 @@ extern tree make_tree PARAMS ((tree, rtx)); extern tree build_type_attribute_variant PARAMS ((tree, tree)); extern tree build_decl_attribute_variant PARAMS ((tree, tree)); +/* Structure describing an attribute and a function to handle it. */ +struct attribute_spec +{ + /* The name of the attribute (without any leading or trailing __), + or NULL to mark the end of a table of attributes. */ + const char *name; + /* The minimum length of the list of arguments of the attribute. */ + int min_length; + /* The maximum length of the list of arguments of the attribute + (-1 for no maximum). */ + int max_length; + /* Whether this attribute requires a DECL. If it does, it will be passed + from types of DECLs, function return types and array element types to + the DECLs, function types and array types respectively; but when + applied to a type in any other circumstances, it will be ignored with + a warning. (If greater control is desired for a given attribute, + this should be false, and the flags argument to the handler may be + used to gain greater control in that case.) */ + bool decl_required; + /* Whether this attribute requires a type. If it does, it will be passed + from a DECL to the type of that DECL. */ + bool type_required; + /* Whether this attribute requires a function (or method) type. If it does, + it will be passed from a function pointer type to the target type, + and from a function return type (which is not itself a function + pointer type) to the function type. */ + bool function_type_required; + /* Function to handle this attribute. NODE points to the node to which + the attribute is to be applied. If a DECL, it should be modified in + place; if a TYPE, a copy should be created. NAME is the name of the + attribute (possibly with leading or trailing __). ARGS is the TREE_LIST + of the arguments (which may be NULL). FLAGS gives further information + about the context of the attribute. Afterwards, the attributes will + be added to the DECL_ATTRIBUTES or TYPE_ATTRIBUTES, as appropriate, + unless *NO_ADD_ATTRS is set to true (which should be done on error, + as well as in any other cases when the attributes should not be added + to the DECL or TYPE). Depending on FLAGS, any attributes to be + applied to another type or DECL later may be returned; + otherwise the return value should be NULL_TREE. This pointer may be + NULL if no special handling is required beyond the checks implied + by the rest of this structure. */ + tree (*handler) PARAMS ((tree *node, tree name, tree args, + int flags, bool *no_add_attrs)); +}; + +extern const struct attribute_spec default_target_attribute_table[]; + +/* Flags that may be passed in the third argument of decl_attributes, and + to handler functions for attributes. */ +enum attribute_flags +{ + /* The type passed in is the type of a DECL, and any attributes that + should be passed in again to be applied to the DECL rather than the + type should be returned. */ + ATTR_FLAG_DECL_NEXT = 1, + /* The type passed in is a function return type, and any attributes that + should be passed in again to be applied to the function type rather + than the return type should be returned. */ + ATTR_FLAG_FUNCTION_NEXT = 2, + /* The type passed in is an array element type, and any attributes that + should be passed in again to be applied to the array type rather + than the element type should be returned. */ + ATTR_FLAG_ARRAY_NEXT = 4, + /* The type passed in is a structure, union or enumeration type being + created, and should be modified in place. */ + ATTR_FLAG_TYPE_IN_PLACE = 8 +}; + /* Default versions of target-overridable functions. */ extern tree merge_decl_attributes PARAMS ((tree, tree)); extern tree merge_type_attributes PARAMS ((tree, tree)); -extern int default_valid_attribute_p PARAMS ((tree, tree, tree, tree)); extern int default_comp_type_attributes PARAMS ((tree, tree)); extern void default_set_default_type_attributes PARAMS ((tree)); extern void default_insert_attributes PARAMS ((tree, tree *)); +extern bool default_function_attribute_inlinable_p PARAMS ((tree)); /* Split a list of declspecs and attributes into two. */