OSDN Git Service

Table-driven attributes.
authorjsm28 <jsm28@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 21 Sep 2001 01:27:06 +0000 (01:27 +0000)
committerjsm28 <jsm28@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 21 Sep 2001 01:27:06 +0000 (01:27 +0000)
* c-decl.c, config/alpha/alpha.c, config/arc/arc.c,
config/arm/arm.c, config/arm/pe.c, config/avr/avr.c,
config/avr/avr.h, config/d30v/d30v.h, config/fr30/fr30.h,
config/h8300/h8300.c, config/i386/cygwin.h, config/i386/winnt.c,
config/m32r/m32r.c, config/mcore/mcore.c, config/sh/sh.c,
config/stormy16/stormy16.h, config/v850/v850.c, doc/c-tree.texi,
doc/tm.texi, ggc-common.c, integrate.c, print-tree.c, tree.c,
tree.h: Rename DECL_MACHINE_ATTRIBUTES to DECL_ATTRIBUTES.
* tree.h (struct tree_decl): Change machine_attributes to
attributes.
* doc/c-tree.texi: Document that all attributes are now attached
to decls and types.
* c-common.c (add_attribute, attrtab, attrtab_idx,
default_valid_lang_attribute, valid_lang_attribute): Remove.
(attribute_tables, attributes_initialized,
c_common_attribute_table, default_lang_attribute_table): New
variables.
(handle_packed_attribute, handle_nocommon_attribute,
handle_common_attribute, handle_noreturn_attribute,
handle_unused_attribute, handle_const_attribute,
handle_transparent_union_attribute, handle_constructor_attribute,
handle_destructor_attribute, handle_mode_attribute,
handle_section_attribute, handle_aligned_attribute,
handle_weak_attribute, handle_alias_attribute,
handle_no_instrument_function_attribute,
handle_no_check_memory_usage_attribute, handle_malloc_attribute,
handle_no_limit_stack_attribute, handle_pure_attribute): New
functions.
(init_attributes, decl_attributes): Rewrite to implement
table-driven attributes.
* c-common.h (enum attribute_flags): Move to tree.h.
* c-format.c (decl_handle_format_attribute,
decl_handle_format_arg_attribute): Rename to
handle_format_attribute and handle_format_arg_attribute.  Update
for table-driven attributes.
* c-common.h (decl_handle_format_attribute,
decl_handle_format_arg_attribute): Remove prototypes.
(handle_format_attribute, handle_format_arg_attribute): Add
prototypes.
* c-decl.c (grokdeclarator): Handle attributes nested inside
declarators.
* c-parse.in (setattrs, maybe_setattrs): Remove.
(maybe_type_quals_setattrs): Rename to maybe_type_quals_attrs.
Update to handle nested attributes properly.
(maybe_resetattrs, after_type_declarator,
parm_declarator_nostarttypename, notype_declarator, absdcl1_noea,
absdcl1_ea, direct_absdcl1): Update to handle nested attributes
properly.
(make_pointer_declarator): Update to handle nested attributes
properly.
* doc/extend.texi: Update documentation of limits of attributes
syntax.  Warn about problems with attribute semantics in C++.
* target.h (struct target): Remove valid_decl_attribute and
valid_type_attribute.  Add attribute_table and
function_attribute_inlinable_p.
* target-def.h (TARGET_VALID_DECL_ATTRIBUTE,
TARGET_VALID_TYPE_ATTRIBUTE): Remove.
(TARGET_ATTRIBUTE_TABLE, TARGET_FUNCTION_ATTRIBUTE_INLINABLE_P):
Add.
(TARGET_INITIALIZER): Update.
* integrate.c (FUNCTION_ATTRIBUTE_INLINABLE_P): Remove default
definition.
(function_attribute_inlinable_p): New function.  Check for the
presence of any machine attributes before using
targetm.function_attribute_inlinable_p.
(function_cannot_inline_p): Update.
* Makefile.in (integrate.o): Update dependencies.
* doc/tm.texi: Update documentation of target attributes and
example definition of TARGET_VALID_TYPE_ATTRIBUTE.
* tree.c (default_valid_attribute_p, valid_machine_attribute):
Remove.
(default_target_attribute_table,
default_function_attribute_inlinable_p): New.
(lookup_attribute): Update comment to clarify handling of multiple
attributes with the same name.
(merge_attributes, attribute_list_contained): Allow multiple
attributes with the same name but different arguments to appear in
the same attribute list.
* tree.h (default_valid_attribute_p): Remove prototype.
(struct attribute_spec): New.
(default_target_attribute_table): Declare.
(enum attribute_flags): Move from c-common.h.  Add
ATTR_FLAG_TYPE_IN_PLACE.
(default_function_attribute_inlinable_p): Declare.
* config/alpha/alpha.c (vms_valid_decl_attribute_p): Remove.
(TARGET_VALID_DECL_ATTRIBUTE): Don't define.
(TARGET_ATTRIBUTE_TABLE): Define.
(vms_attribute_table): New.
* config/arc/arc.c (arc_valid_decl_attribute): Remove.
(TARGET_VALID_DECL_ATTRIBUTE): Don't define.
(TARGET_ATTRIBUTE_TABLE): Define.
(arc_attribute_table, arc_handle_interrupt_attribute): New.
* config/arm/arm.c (arm_valid_type_attribute_p,
arm_valid_decl_attribute_p, arm_pe_valid_decl_attribute_p):
Remove.
(TARGET_VALID_TYPE_ATTRIBUTE, TARGET_VALID_DECL_ATTRIBUTE): Don't
define.
(TARGET_ATTRIBUTE_TABLE): Define.
(arm_attribute_table, arm_handle_fndecl_attribute,
arm_handle_isr_attribute): New.
* config/avr/avr.c (avr_valid_type_attribute,
avr_valid_decl_attribute): Remove.
(TARGET_VALID_DECL_ATTRIBUTE, TARGET_VALID_TYPE_ATTRIBUTE): Don't
define.
(TARGET_ATTRIBUTE_TABLE): Define.
(avr_attribute_table, avr_handle_progmem_attribute,
avr_handle_fndecl_attribute): New.
* config/c4x/c4x.c (c4x_valid_type_attribute_p): Remove.
(TARGET_VALID_TYPE_ATTRIBUTE): Don't define.
(TARGET_ATTRIBUTE_TABLE): Define.
(c4x_attribute_table, c4x_handle_fntype_attribute): New.
* config/h8300/h8300.c (h8300_valid_decl_attribute): Remove.
(TARGET_VALID_DECL_ATTRIBUTE): Don't define.
(TARGET_ATTRIBUTE_TABLE): Define.
(h8300_attribute_table, h8300_handle_fndecl_attribute,
h8300_handle_eightbit_data_attribute,
h8300_handle_tiny_data_attribute): New.
* config/i386/i386-protos.h (ix86_valid_type_attribute_p,
i386_pe_valid_decl_attribute_p, i386_pe_valid_type_attribute_p):
Remove prototypes.
(ix86_handle_dll_attribute, ix86_handle_shared_attribute): New
declarations.
* config/i386/i386.c (ix86_valid_type_attribute_p: Remove.
(TARGET_VALID_TYPE_ATTRIBUTE, TARGET_VALID_DECL_ATTRIBUTE): Don't
define.
(TARGET_ATTRIBUTE_TABLE): Define.
(ix86_attribute_table, ix86_handle_cdecl_attribute,
ix86_handle_regparm_attribute): New.
* config/i386/winnt.c (i386_pe_valid_decl_attribute_p,
i386_pe_valid_type_attribute_p): Remove.
(ix86_handle_dll_attribute, ix86_handle_shared_attribute): New.
* config/ia64/ia64.c (ia64_valid_type_attribute): Remove.
(TARGET_VALID_TYPE_ATTRIBUTE): Don't define.
(TARGET_ATTRIBUTE_TABLE): Define.
(ia64_attribute_table): New.
* config/m32r/m32r.c (m32r_valid_decl_attribute, interrupt_ident1,
interrupt_ident2, model_ident1, model_ident2): Remove.
(TARGET_VALID_DECL_ATTRIBUTE): Don't define.
(TARGET_ATTRIBUTE_TABLE): Define.
(init_idents): Update.
(m32r_attribute_table, m32r_handle_model_attribute): New.
* config/m68hc11/m68hc11.c (m68hc11_valid_type_attribute_p):
Remove.
(TARGET_VALID_TYPE_ATTRIBUTE): Don't define.
(TARGET_ATTRIBUTE_TABLE): Define.
(m68hc11_attribute_table, m68hc11_handle_fntype_attribute): New.
* config/mcore/mcore.c (mcore_valid_decl_attribute): Remove.
(TARGET_VALID_DECL_ATTRIBUTE): Don't define.
(TARGET_ATTRIBUTE_TABLE): Define.
(mcore_attribute_table, mcore_handle_naked_attribute): New.
* config/ns32k/ns32k.c (ns32k_valid_type_attribute_p): Remove.
(TARGET_VALID_TYPE_ATTRIBUTE): Don't define.
(TARGET_ATTRIBUTE_TABLE): Define.
(ns32k_attribute_table, ns32k_handle_fntype_attribute): New.
* config/rs6000/rs6000.c (rs6000_valid_type_attribute_p): Remove.
(TARGET_VALID_TYPE_ATTRIBUTE): Don't define.
(TARGET_ATTRIBUTE_TABLE): Define.
(rs6000_attribute_table, rs6000_handle_longcall_attribute): New.
* config/sh/sh.c (sh_valid_decl_attribute): Remove.
(TARGET_VALID_DECL_ATTRIBUTE): Don't define.
(TARGET_ATTRIBUTE_TABLE): Define.
(sh_attribute_table, sh_handle_interrupt_handler_attribute,
sh_handle_sp_switch_attribute, sh_handle_trap_exit_attribute):
New.
* config/stormy16/stormy16.c (stormy16_valid_type_attribute):
Remove.
(TARGET_VALID_TYPE_ATTRIBUTE): Don't define
(TARGET_ATTRIBUTE_TABLE): Define.
(stormy16_attribute_table, stormy16_handle_interrupt_attribute):
New.
* config/v850/v850.c (v850_valid_decl_attribute): Remove.
(TARGET_VALID_DECL_ATTRIBUTE): Don't define.
(TARGET_ATTRIBUTE_TABLE): Define.
(v850_attribute_table, v850_handle_interrupt_attribute,
v850_handle_data_area_attribute): New.
* config/v850/v850-c.c (mark_current_function_as_interrupt):
Return void.  Call decl_attributes instead of
valid_machine_attribute.

cp:
Table-driven attributes.
* decl.c: Rename DECL_MACHINE_ATTRIBUTES to DECL_ATTRIBUTES.
* decl2.c (cplus_decl_attributes): Only take one attributes
parameter.
* cp-tree.c (cplus_decl_attributes): Update prototype.
* class.c (finish_struct), decl.c (start_decl, start_function),
decl2.c (grokfield), friend.c (do_friend), parse.y
(parse_bitfield): Update calls to cplus_decl_attributes.
* decl.c (grokdeclarator): Take a pointer to a single ordinary
attribute list.
* decl.h (grokdeclarator): Update prototype.
* decl2.c (grokfield): Take a single ordinary attribute list.
* friend.c (do_friend): Likewise.
* decl.c (shadow_tag, groktypename, start_decl,
start_handler_parms, grokdeclarator, grokparms, start_function,
start_method), decl2.c (grokfield, grokbitfield, grokoptypename),
parse.y (parse_field, parse_bitfield, component_decl_1), pt.c
(process_template_parm, do_decl_instantiation): Pass single
ordinary attribute lists around.
* decl.c (grokdeclarator): Correct handling of nested attributes.
Revert the patch
1998-10-18  Jason Merrill  <jason@yorick.cygnus.com>
* decl.c (grokdeclarator): Embedded attrs bind to the right,
not the left.
.
* cp-tree.h (cp_valid_lang_attribute): Remove declaration
(cp_attribute_table): Declare.
* decl.c (valid_lang_attribute): Don't define.
(lang_attribute_table): Define.
(init_decl_processing): Initialize lang_attribute_table instead of
valid_lang_attribute.
* tree.c (cp_valid_lang_attribute): Remove.
(handle_java_interface_attribute, handle_com_interface_attribute,
handle_init_priority_attribute): New functions.
(cp_attribute_table): New array.
* decl2.c (import_export_class): Don't use
targetm.valid_type_attribute.

testsuite:
Table-driven attributes.
* g++.dg/ext/attrib1.C: New test.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@45718 138bc75d-0d04-0410-961f-82ee72b054a4

54 files changed:
gcc/ChangeLog
gcc/Makefile.in
gcc/c-common.c
gcc/c-common.h
gcc/c-decl.c
gcc/c-format.c
gcc/c-parse.in
gcc/config/alpha/alpha.c
gcc/config/arc/arc.c
gcc/config/arm/arm.c
gcc/config/arm/pe.c
gcc/config/avr/avr.c
gcc/config/avr/avr.h
gcc/config/c4x/c4x.c
gcc/config/d30v/d30v.h
gcc/config/fr30/fr30.h
gcc/config/h8300/h8300.c
gcc/config/i386/cygwin.h
gcc/config/i386/i386-protos.h
gcc/config/i386/i386.c
gcc/config/i386/winnt.c
gcc/config/ia64/ia64.c
gcc/config/m32r/m32r.c
gcc/config/m68hc11/m68hc11.c
gcc/config/mcore/mcore.c
gcc/config/ns32k/ns32k.c
gcc/config/rs6000/rs6000.c
gcc/config/sh/sh.c
gcc/config/stormy16/stormy16.c
gcc/config/stormy16/stormy16.h
gcc/config/v850/v850-c.c
gcc/config/v850/v850.c
gcc/cp/ChangeLog
gcc/cp/class.c
gcc/cp/cp-tree.h
gcc/cp/decl.c
gcc/cp/decl.h
gcc/cp/decl2.c
gcc/cp/friend.c
gcc/cp/parse.y
gcc/cp/pt.c
gcc/cp/tree.c
gcc/doc/c-tree.texi
gcc/doc/extend.texi
gcc/doc/tm.texi
gcc/ggc-common.c
gcc/integrate.c
gcc/print-tree.c
gcc/target-def.h
gcc/target.h
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/ext/attrib1.C [new file with mode: 0644]
gcc/tree.c
gcc/tree.h

index 6ebf1c6..00a5217 100644 (file)
@@ -1,3 +1,185 @@
+2001-09-21  Joseph S. Myers  <jsm28@cam.ac.uk>
+
+       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 <amylaar@redhat.com>
 
        * sh-protos.h (sh_pr_n_sets): Declare.
index db4dfcd..ddde078 100644 (file)
@@ -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)
index 1515e45..8d00cfe 100644 (file)
@@ -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;
 }
 \f
-/* To speed up processing of attributes, we maintain an array of
-   IDENTIFIER_NODES and the corresponding attribute types.  */
-
-/* Array to hold attribute information.  */
-
-static struct {enum attrs id; tree name; int min, max, decl_req;} attrtab[50];
-
-static int attrtab_idx = 0;
-
-/* Add an entry to the attribute table above.  */
-
-static void
-add_attribute (id, string, min_len, max_len, decl_req)
-     enum attrs id;
-     const char *string;
-     int min_len, max_len;
-     int decl_req;
+/* Table of the tables of attributes (common, language, machine) searched.  */
+static const struct attribute_spec *attribute_tables[3];
+
+static bool attributes_initialized = false;
+
+static tree handle_packed_attribute PARAMS ((tree *, tree, tree, int, bool *));
+static tree handle_nocommon_attribute PARAMS ((tree *, tree, tree, int, bool *));
+static tree handle_common_attribute PARAMS ((tree *, tree, tree, int, bool *));
+static tree handle_noreturn_attribute PARAMS ((tree *, tree, tree, int, bool *));
+static tree handle_unused_attribute PARAMS ((tree *, tree, tree, int, bool *));
+static tree handle_const_attribute PARAMS ((tree *, tree, tree, int, bool *));
+static tree handle_transparent_union_attribute PARAMS ((tree *, tree, tree, int, bool *));
+static tree handle_constructor_attribute PARAMS ((tree *, tree, tree, int, bool *));
+static tree handle_destructor_attribute PARAMS ((tree *, tree, tree, int, bool *));
+static tree handle_mode_attribute PARAMS ((tree *, tree, tree, int, bool *));
+static tree handle_section_attribute PARAMS ((tree *, tree, tree, int, bool *));
+static tree handle_aligned_attribute PARAMS ((tree *, tree, tree, int, bool *));
+static tree handle_weak_attribute PARAMS ((tree *, tree, tree, int, bool *));
+static tree handle_alias_attribute PARAMS ((tree *, tree, tree, int, bool *));
+static tree handle_no_instrument_function_attribute PARAMS ((tree *, tree, tree, int, bool *));
+static tree handle_no_check_memory_usage_attribute PARAMS ((tree *, tree, tree, int, bool *));
+static tree handle_malloc_attribute PARAMS ((tree *, tree, tree, int, bool *));
+static tree handle_no_limit_stack_attribute PARAMS ((tree *, tree, tree, int, bool *));
+static tree handle_pure_attribute PARAMS ((tree *, tree, tree, int, bool *));
+
+/* Table of machine-independent attributes common to all C-like languages.  */
+static const struct attribute_spec c_common_attribute_table[] =
 {
-  char buf[100];
-
-  attrtab[attrtab_idx].id = id;
-  attrtab[attrtab_idx].name = get_identifier (string);
-  attrtab[attrtab_idx].min = min_len;
-  attrtab[attrtab_idx].max = max_len;
-  attrtab[attrtab_idx++].decl_req = decl_req;
+  /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
+  { "packed",                 0, 0, false, false, false, handle_packed_attribute },
+  { "nocommon",               0, 0, true,  false, false, handle_nocommon_attribute },
+  { "common",                 0, 0, true,  false, false, handle_common_attribute },
+  /* FIXME: logically, noreturn attributes should be listed as
+     "false, true, true" and apply to function types.  But implementing this
+     would require all the places in the compiler that use TREE_THIS_VOLATILE
+     on a decl to identify non-returning functions to be located and fixed
+     to check the function type instead.  */
+  { "noreturn",               0, 0, true,  false, false, handle_noreturn_attribute },
+  { "volatile",               0, 0, true,  false, false, handle_noreturn_attribute },
+  { "unused",                 0, 0, false, false, false, handle_unused_attribute },
+  /* The same comments as for noreturn attributes apply to const ones.  */
+  { "const",                  0, 0, true,  false, false, handle_const_attribute },
+  { "transparent_union",      0, 0, false, false, false, handle_transparent_union_attribute },
+  { "constructor",            0, 0, true,  false, false, handle_constructor_attribute },
+  { "destructor",             0, 0, true,  false, false, handle_destructor_attribute },
+  { "mode",                   1, 1, true,  false, false, handle_mode_attribute },
+  { "section",                1, 1, true,  false, false, handle_section_attribute },
+  { "aligned",                0, 1, false, false, false, handle_aligned_attribute },
+  { "format",                 3, 3, true,  false, false, handle_format_attribute },
+  { "format_arg",             1, 1, true,  false, false, handle_format_arg_attribute },
+  { "weak",                   0, 0, true,  false, false, handle_weak_attribute },
+  { "alias",                  1, 1, true,  false, false, handle_alias_attribute },
+  { "no_instrument_function", 0, 0, true,  false, false, handle_no_instrument_function_attribute },
+  { "no_check_memory_usage",  0, 0, true,  false, false, handle_no_check_memory_usage_attribute },
+  { "malloc",                 0, 0, true,  false, false, handle_malloc_attribute },
+  { "no_stack_limit",         0, 0, true,  false, false, handle_no_limit_stack_attribute },
+  { "pure",                   0, 0, true,  false, false, handle_pure_attribute },
+  { NULL,                     0, 0, false, false, false, NULL }
+};
 
-  sprintf (buf, "__%s__", string);
+/* Default empty table of language attributes.  */
+static const struct attribute_spec default_lang_attribute_table[] =
+{
+  { NULL, 0, 0, false, false, false, NULL }
+};
 
-  attrtab[attrtab_idx].id = id;
-  attrtab[attrtab_idx].name = get_identifier (buf);
-  attrtab[attrtab_idx].min = min_len;
-  attrtab[attrtab_idx].max = max_len;
-  attrtab[attrtab_idx++].decl_req = decl_req;
-}
+/* Table of machine-independent attributes for a particular language.  */
+const struct attribute_spec *lang_attribute_table = default_lang_attribute_table;
 
-/* Initialize attribute table.  */
+/* Initialize attribute tables, and make some sanity checks
+   if --enable-checking.  */
 
 static void
 init_attributes ()
 {
-  add_attribute (A_PACKED, "packed", 0, 0, 0);
-  add_attribute (A_NOCOMMON, "nocommon", 0, 0, 1);
-  add_attribute (A_COMMON, "common", 0, 0, 1);
-  add_attribute (A_NORETURN, "noreturn", 0, 0, 1);
-  add_attribute (A_NORETURN, "volatile", 0, 0, 1);
-  add_attribute (A_UNUSED, "unused", 0, 0, 0);
-  add_attribute (A_CONST, "const", 0, 0, 1);
-  add_attribute (A_T_UNION, "transparent_union", 0, 0, 0);
-  add_attribute (A_CONSTRUCTOR, "constructor", 0, 0, 1);
-  add_attribute (A_DESTRUCTOR, "destructor", 0, 0, 1);
-  add_attribute (A_MODE, "mode", 1, 1, 1);
-  add_attribute (A_SECTION, "section", 1, 1, 1);
-  add_attribute (A_ALIGNED, "aligned", 0, 1, 0);
-  add_attribute (A_FORMAT, "format", 3, 3, 1);
-  add_attribute (A_FORMAT_ARG, "format_arg", 1, 1, 1);
-  add_attribute (A_WEAK, "weak", 0, 0, 1);
-  add_attribute (A_ALIAS, "alias", 1, 1, 1);
-  add_attribute (A_NO_INSTRUMENT_FUNCTION, "no_instrument_function", 0, 0, 1);
-  add_attribute (A_NO_CHECK_MEMORY_USAGE, "no_check_memory_usage", 0, 0, 1);
-  add_attribute (A_MALLOC, "malloc", 0, 0, 1);
-  add_attribute (A_NO_LIMIT_STACK, "no_stack_limit", 0, 0, 1);
-  add_attribute (A_PURE, "pure", 0, 0, 1);
+#ifdef ENABLE_CHECKING
+  int i;
+#endif
+  attribute_tables[0] = c_common_attribute_table;
+  attribute_tables[1] = lang_attribute_table;
+  attribute_tables[2] = targetm.attribute_table;
+#ifdef ENABLE_CHECKING
+  /* Make some sanity checks on the attribute tables.  */
+  for (i = 0;
+       i < (int) (sizeof (attribute_tables) / sizeof (attribute_tables[0]));
+       i++)
+    {
+      int j;
+      for (j = 0; attribute_tables[i][j].name != NULL; j++)
+       {
+         /* The name must not begin and end with __.  */
+         const char *name = attribute_tables[i][j].name;
+         int len = strlen (name);
+         if (name[0] == '_' && name[1] == '_'
+             && name[len - 1] == '_' && name[len - 2] == '_')
+           abort ();
+         /* The minimum and maximum lengths must be consistent.  */
+         if (attribute_tables[i][j].min_length < 0)
+           abort ();
+         if (attribute_tables[i][j].max_length != -1
+             && attribute_tables[i][j].max_length < attribute_tables[i][j].min_length)
+           abort ();
+         /* An attribute cannot require both a DECL and a TYPE.  */
+         if (attribute_tables[i][j].decl_required
+             && attribute_tables[i][j].type_required)
+           abort ();
+         /* If an attribute requires a function type, in particular
+            it requires a type.  */
+         if (attribute_tables[i][j].function_type_required
+             && !attribute_tables[i][j].type_required)
+           abort ();
+       }
+    }
+  /* Check that each name occurs just once in each table.  */
+  for (i = 0;
+       i < (int) (sizeof (attribute_tables) / sizeof (attribute_tables[0]));
+       i++)
+    {
+      int j, k;
+      for (j = 0; attribute_tables[i][j].name != NULL; j++)
+       for (k = j + 1; attribute_tables[i][k].name != NULL; k++)
+         if (!strcmp (attribute_tables[i][j].name,
+                      attribute_tables[i][k].name))
+           abort ();
+    }
+  /* Check that no name occurs in more than one table.  */
+  for (i = 0;
+       i < (int) (sizeof (attribute_tables) / sizeof (attribute_tables[0]));
+       i++)
+    {
+      int j;
+      for (j = i + 1;
+          j < (int) (sizeof (attribute_tables) / sizeof (attribute_tables[0]));
+          j++)
+       {
+         int k, l;
+         for (k = 0; attribute_tables[i][k].name != NULL; k++)
+           for (l = 0; attribute_tables[j][l].name != NULL; l++)
+             if (!strcmp (attribute_tables[i][k].name,
+                          attribute_tables[j][l].name))
+               abort ();
+       }
+    }
+#endif
+  attributes_initialized = true;
 }
 \f
-/* Default implementation of valid_lang_attribute, below.  By default, there
-   are no language-specific attributes.  */
-
-static int
-default_valid_lang_attribute (attr_name, attr_args, decl, type)
-  tree attr_name ATTRIBUTE_UNUSED;
-  tree attr_args ATTRIBUTE_UNUSED;
-  tree decl ATTRIBUTE_UNUSED;
-  tree type ATTRIBUTE_UNUSED;
-{
-  return 0;
-}
-
-/* Return a 1 if ATTR_NAME and ATTR_ARGS denote a valid language-specific
-   attribute for either declaration DECL or type TYPE and 0 otherwise.  */
-
-int (*valid_lang_attribute) PARAMS ((tree, tree, tree, tree))
-     = default_valid_lang_attribute;
-
 /* Process the attributes listed in ATTRIBUTES and install them in *NODE,
    which is either a DECL (including a TYPE_DECL) or a TYPE.  If a DECL,
-   it should be modified in place; if a TYPE, a copy should be created.
-   FLAGS gives further information, in the form of a bitwise OR of flags
-   in enum attribute_flags from c-common.h.  Depending on these flags,
-   some attributes may be returned to be applied at a later stage (for
-   example, to apply a decl attribute to the declaration rather than to
-   its type).  */
+   it should be modified in place; if a TYPE, a copy should be created
+   unless ATTR_FLAG_TYPE_IN_PLACE is set in FLAGS.  FLAGS gives further
+   information, in the form of a bitwise OR of flags in enum attribute_flags
+   from tree.h.  Depending on these flags, some attributes may be
+   returned to be applied at a later stage (for example, to apply
+   a decl attribute to the declaration rather than to its type).  */
 
 tree
 decl_attributes (node, attributes, flags)
      tree *node, attributes;
-     int flags ATTRIBUTE_UNUSED;
+     int flags;
 {
-  tree decl = 0, type = 0;
-  int is_type = 0;
   tree a;
+  tree returned_attrs = NULL_TREE;
 
-  if (attrtab_idx == 0)
+  if (!attributes_initialized)
     init_attributes ();
 
-  if (DECL_P (*node))
-    {
-      decl = *node;
-      type = TREE_TYPE (decl);
-      is_type = TREE_CODE (*node) == TYPE_DECL;
-    }
-  else if (TYPE_P (*node))
-    type = *node, is_type = 1;
-
   (*targetm.insert_attributes) (*node, &attributes);
 
   for (a = attributes; a; a = TREE_CHAIN (a))
     {
       tree name = TREE_PURPOSE (a);
       tree args = TREE_VALUE (a);
+      tree *anode = node;
+      const struct attribute_spec *spec = NULL;
+      bool no_add_attrs = 0;
       int i;
-      enum attrs id;
-
-      for (i = 0; i < attrtab_idx; i++)
-       if (attrtab[i].name == name)
-         break;
 
-      if (i == attrtab_idx)
+      for (i = 0;
+          i < (int) (sizeof (attribute_tables) / sizeof (attribute_tables[0]));
+          i++)
        {
-         if (! valid_machine_attribute (name, args, decl, type)
-             && ! (* valid_lang_attribute) (name, args, decl, type))
-           warning ("`%s' attribute directive ignored",
-                    IDENTIFIER_POINTER (name));
-         else if (decl != 0)
-           type = TREE_TYPE (decl);
-         continue;
+         int j;
+         for (j = 0; attribute_tables[i][j].name != NULL; j++)
+           {
+             if (is_attribute_p (attribute_tables[i][j].name, name))
+               {
+                 spec = &attribute_tables[i][j];
+                 break;
+               }
+           }
+         if (spec != NULL)
+           break;
        }
-      else if (attrtab[i].decl_req && decl == 0)
+
+      if (spec == NULL)
        {
-         warning ("`%s' attribute does not apply to types",
+         warning ("`%s' attribute directive ignored",
                   IDENTIFIER_POINTER (name));
          continue;
        }
-      else if (list_length (args) < attrtab[i].min
-              || list_length (args) > attrtab[i].max)
+      else if (list_length (args) < spec->min_length
+              || (spec->max_length >= 0
+                  && list_length (args) > spec->max_length))
        {
          error ("wrong number of arguments specified for `%s' attribute",
                 IDENTIFIER_POINTER (name));
          continue;
        }
 
-      id = attrtab[i].id;
-      switch (id)
+      if (spec->decl_required && !DECL_P (*anode))
        {
-       case A_PACKED:
-         if (is_type)
-           TYPE_PACKED (type) = 1;
-         else if (TREE_CODE (decl) == FIELD_DECL)
-           DECL_PACKED (decl) = 1;
-         /* We can't set DECL_PACKED for a VAR_DECL, because the bit is
-            used for DECL_REGISTER.  It wouldn't mean anything anyway.  */
-         else
-           warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
-         break;
-
-       case A_NOCOMMON:
-         if (TREE_CODE (decl) == VAR_DECL)
-           DECL_COMMON (decl) = 0;
-         else
-           warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
-         break;
-
-       case A_COMMON:
-         if (TREE_CODE (decl) == VAR_DECL)
-           DECL_COMMON (decl) = 1;
-         else
-           warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
-         break;
-
-       case A_NORETURN:
-         if (TREE_CODE (decl) == FUNCTION_DECL)
-           TREE_THIS_VOLATILE (decl) = 1;
-         else if (TREE_CODE (type) == POINTER_TYPE
-                  && TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE)
-           TREE_TYPE (decl) = type
-             = build_pointer_type
-               (build_type_variant (TREE_TYPE (type),
-                                    TREE_READONLY (TREE_TYPE (type)), 1));
-         else
-           warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
-         break;
-
-       case A_MALLOC:
-         if (TREE_CODE (decl) == FUNCTION_DECL)
-           DECL_IS_MALLOC (decl) = 1;
-         /* ??? TODO: Support types.  */
+         if (flags & ((int) ATTR_FLAG_DECL_NEXT
+                      | (int) ATTR_FLAG_FUNCTION_NEXT
+                      | (int) ATTR_FLAG_ARRAY_NEXT))
+           {
+             /* Pass on this attribute to be tried again.  */
+             returned_attrs = tree_cons (name, args, returned_attrs);
+             continue;
+           }
          else
-           warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
-         break;
+           {
+             warning ("`%s' attribute does not apply to types",
+                      IDENTIFIER_POINTER (name));
+             continue;
+           }
+       }
 
-       case A_UNUSED:
-         if (is_type)
-           if (decl)
-             TREE_USED (decl) = 1;
-           else
-             TREE_USED (type) = 1;
-         else if (TREE_CODE (decl) == PARM_DECL
-                  || TREE_CODE (decl) == VAR_DECL
-                  || TREE_CODE (decl) == FUNCTION_DECL
-                  || TREE_CODE (decl) == LABEL_DECL)
-           TREE_USED (decl) = 1;
-         else
-           warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
-         break;
+      if (spec->type_required && DECL_P (*anode))
+       {
+         anode = &TREE_TYPE (*anode);
+       }
 
-       case A_CONST:
-         if (TREE_CODE (decl) == FUNCTION_DECL)
-           TREE_READONLY (decl) = 1;
-         else if (TREE_CODE (type) == POINTER_TYPE
-                  && TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE)
-           TREE_TYPE (decl) = type
-             = build_pointer_type
-               (build_type_variant (TREE_TYPE (type), 1,
-                                    TREE_THIS_VOLATILE (TREE_TYPE (type))));
-         else
-           warning ( "`%s' attribute ignored", IDENTIFIER_POINTER (name));
-         break;
+      if (spec->function_type_required && TREE_CODE (*anode) != FUNCTION_TYPE
+         && TREE_CODE (*anode) != METHOD_TYPE)
+       {
+         if (TREE_CODE (*anode) == POINTER_TYPE
+             && (TREE_CODE (TREE_TYPE (*anode)) == FUNCTION_TYPE
+                 || TREE_CODE (TREE_TYPE (*anode)) == METHOD_TYPE))
+           {
+             if (!(flags & (int) ATTR_FLAG_TYPE_IN_PLACE))
+               *anode = build_type_copy (*anode);
+             anode = &TREE_TYPE (*anode);
+           }
+         else if (flags & (int) ATTR_FLAG_FUNCTION_NEXT)
+           {
+             /* Pass on this attribute to be tried again.  */
+             returned_attrs = tree_cons (name, args, returned_attrs);
+             continue;
+           }
 
-       case A_PURE:
-         if (TREE_CODE (decl) == FUNCTION_DECL)
-           DECL_IS_PURE (decl) = 1;
-         /* ??? TODO: Support types.  */
-         else
-           warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
-         break;
+         if (TREE_CODE (*anode) != FUNCTION_TYPE
+             && TREE_CODE (*anode) != METHOD_TYPE)
+           {
+             warning ("`%s' attribute only applies to function types",
+                      IDENTIFIER_POINTER (name));
+             continue;
+           }
+       }
 
+      if (spec->handler != NULL)
+       returned_attrs = chainon ((*spec->handler) (anode, name, args,
+                                                   flags, &no_add_attrs),
+                                 returned_attrs);
+      if (!no_add_attrs)
+       {
+         tree old_attrs;
+         tree a;
 
-       case A_T_UNION:
-         if (is_type
-             && TREE_CODE (type) == UNION_TYPE
-             && (decl == 0
-                 || (TYPE_FIELDS (type) != 0
-                     && TYPE_MODE (type) == DECL_MODE (TYPE_FIELDS (type)))))
-           TYPE_TRANSPARENT_UNION (type) = 1;
-         else if (decl != 0 && TREE_CODE (decl) == PARM_DECL
-                  && TREE_CODE (type) == UNION_TYPE
-                  && TYPE_MODE (type) == DECL_MODE (TYPE_FIELDS (type)))
-           DECL_TRANSPARENT_UNION (decl) = 1;
+         if (DECL_P (*anode))
+           old_attrs = DECL_ATTRIBUTES (*anode);
          else
-           warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
-         break;
+           old_attrs = TYPE_ATTRIBUTES (*anode);
 
-       case A_CONSTRUCTOR:
-         if (TREE_CODE (decl) == FUNCTION_DECL
-             && TREE_CODE (type) == FUNCTION_TYPE
-             && decl_function_context (decl) == 0)
+         for (a = lookup_attribute (spec->name, old_attrs);
+              a != NULL_TREE;
+              a = lookup_attribute (spec->name, TREE_CHAIN (a)))
            {
-             DECL_STATIC_CONSTRUCTOR (decl) = 1;
-             TREE_USED (decl) = 1;
+             if (simple_cst_equal (TREE_VALUE (a), args) == 1)
+               break;
            }
-         else
-           warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
-         break;
 
-       case A_DESTRUCTOR:
-         if (TREE_CODE (decl) == FUNCTION_DECL
-             && TREE_CODE (type) == FUNCTION_TYPE
-             && decl_function_context (decl) == 0)
+         if (a == NULL_TREE)
            {
-             DECL_STATIC_DESTRUCTOR (decl) = 1;
-             TREE_USED (decl) = 1;
+             /* This attribute isn't already in the list.  */
+             if (DECL_P (*anode))
+               DECL_ATTRIBUTES (*anode) = tree_cons (name, args, old_attrs);
+             else if (flags & (int) ATTR_FLAG_TYPE_IN_PLACE)
+               TYPE_ATTRIBUTES (*anode) = tree_cons (name, args, old_attrs);
+             else
+               *anode = build_type_attribute_variant (*anode,
+                                                      tree_cons (name, args,
+                                                                 old_attrs));
            }
-         else
-           warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
-         break;
+       }
+    }
 
-       case A_MODE:
-         if (TREE_CODE (TREE_VALUE (args)) != IDENTIFIER_NODE)
-           warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
-         else
-           {
-             int j;
-             const char *p = IDENTIFIER_POINTER (TREE_VALUE (args));
-             int len = strlen (p);
-             enum machine_mode mode = VOIDmode;
-             tree typefm;
-
-             if (len > 4 && p[0] == '_' && p[1] == '_'
-                 && p[len - 1] == '_' && p[len - 2] == '_')
-               {
-                 char *newp = (char *) alloca (len - 1);
+  return returned_attrs;
+}
 
-                 strcpy (newp, &p[2]);
-                 newp[len - 4] = '\0';
-                 p = newp;
-               }
+/* Handle a "packed" attribute; arguments as in
+   struct attribute_spec.handler.  */
+static tree
+handle_packed_attribute (node, name, args, flags, no_add_attrs)
+     tree *node;
+     tree name;
+     tree args ATTRIBUTE_UNUSED;
+     int flags;
+     bool *no_add_attrs;
+{
+  tree *type = NULL;
+  if (DECL_P (*node))
+    {
+      if (TREE_CODE (*node) == TYPE_DECL)
+       type = &TREE_TYPE (*node);
+    }
+  else
+    type = node;
+  if (type)
+    {
+      if (!(flags & (int) ATTR_FLAG_TYPE_IN_PLACE))
+       *type = build_type_copy (*type);
+      TYPE_PACKED (*type) = 1;
+    }
+  else if (TREE_CODE (*node) == FIELD_DECL)
+    DECL_PACKED (*node) = 1;
+  /* We can't set DECL_PACKED for a VAR_DECL, because the bit is
+     used for DECL_REGISTER.  It wouldn't mean anything anyway.  */
+  else
+    {
+      warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
+      *no_add_attrs = true;
+    }
 
-             /* Give this decl a type with the specified mode.
-                First check for the special modes.  */
-             if (! strcmp (p, "byte"))
-               mode = byte_mode;
-             else if (!strcmp (p, "word"))
-               mode = word_mode;
-             else if (! strcmp (p, "pointer"))
-               mode = ptr_mode;
-             else
-               for (j = 0; j < NUM_MACHINE_MODES; j++)
-                 if (!strcmp (p, GET_MODE_NAME (j)))
-                   mode = (enum machine_mode) j;
-
-             if (mode == VOIDmode)
-               error ("unknown machine mode `%s'", p);
-             else if (0 == (typefm = type_for_mode (mode,
-                                                    TREE_UNSIGNED (type))))
-               error ("no data type for mode `%s'", p);
-             else
-               {
-                 if (TYPE_PRECISION (typefm) > (TREE_UNSIGNED (type)
-                                                ? TYPE_PRECISION(uintmax_type_node)
-                                                : TYPE_PRECISION(intmax_type_node))
-                     && pedantic)
-                   pedwarn ("type with more precision than %s",
-                            TREE_UNSIGNED (type) ? "uintmax_t" : "intmax_t");
-                 TREE_TYPE (decl) = type = typefm;
-                 DECL_SIZE (decl) = DECL_SIZE_UNIT (decl) = 0;
-                 if (TREE_CODE (decl) != FIELD_DECL)
-                   layout_decl (decl, 0);
-               }
-           }
-         break;
+  return NULL_TREE;
+}
 
-       case A_SECTION:
-         if (targetm.have_named_sections)
-           {
-             if ((TREE_CODE (decl) == FUNCTION_DECL
-                  || TREE_CODE (decl) == VAR_DECL)
-                 && TREE_CODE (TREE_VALUE (args)) == STRING_CST)
-               {
-                 if (TREE_CODE (decl) == VAR_DECL
-                     && current_function_decl != NULL_TREE
-                     && ! TREE_STATIC (decl))
-                   error_with_decl (decl,
-                                    "section attribute cannot be specified for local variables");
-                 /* The decl may have already been given a section attribute
-                    from a previous declaration.  Ensure they match.  */
-                 else if (DECL_SECTION_NAME (decl) != NULL_TREE
-                          && strcmp (TREE_STRING_POINTER (DECL_SECTION_NAME (decl)),
-                                     TREE_STRING_POINTER (TREE_VALUE (args))) != 0)
-                   error_with_decl (*node,
-                                    "section of `%s' conflicts with previous declaration");
-                 else
-                   DECL_SECTION_NAME (decl) = TREE_VALUE (args);
-               }
-             else
-               error_with_decl (*node,
-                                "section attribute not allowed for `%s'");
-           }
-         else
-           error_with_decl (*node,
-                            "section attributes are not supported for this target");
-         break;
+/* Handle a "nocommon" attribute; arguments as in
+   struct attribute_spec.handler.  */
+static tree
+handle_nocommon_attribute (node, name, args, flags, no_add_attrs)
+     tree *node;
+     tree name;
+     tree args ATTRIBUTE_UNUSED;
+     int flags ATTRIBUTE_UNUSED;
+     bool *no_add_attrs;
+{
+  if (TREE_CODE (*node) == VAR_DECL)
+    DECL_COMMON (*node) = 0;
+  else
+    {
+      warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
+      *no_add_attrs = true;
+    }
 
-       case A_ALIGNED:
-         {
-           tree align_expr
-             = (args ? TREE_VALUE (args)
-                : size_int (BIGGEST_ALIGNMENT / BITS_PER_UNIT));
-           int i;
-
-           /* Strip any NOPs of any kind.  */
-           while (TREE_CODE (align_expr) == NOP_EXPR
-                  || TREE_CODE (align_expr) == CONVERT_EXPR
-                  || TREE_CODE (align_expr) == NON_LVALUE_EXPR)
-             align_expr = TREE_OPERAND (align_expr, 0);
-
-           if (TREE_CODE (align_expr) != INTEGER_CST)
-             {
-               error ("requested alignment is not a constant");
-               continue;
-             }
+  return NULL_TREE;
+}
 
-           if ((i = tree_log2 (align_expr)) == -1)
-             error ("requested alignment is not a power of 2");
-           else if (i > HOST_BITS_PER_INT - 2)
-             error ("requested alignment is too large");
-           else if (is_type)
-             {
-               /* If we have a TYPE_DECL, then copy the type, so that we
-                  don't accidentally modify a builtin type.  See pushdecl.  */
-               if (decl && TREE_TYPE (decl) != error_mark_node
-                   && DECL_ORIGINAL_TYPE (decl) == NULL_TREE)
-                 {
-                   tree tt = TREE_TYPE (decl);
-                   DECL_ORIGINAL_TYPE (decl) = tt;
-                   tt = build_type_copy (tt);
-                   TYPE_NAME (tt) = decl;
-                   TREE_USED (tt) = TREE_USED (decl);
-                   TREE_TYPE (decl) = tt;
-                   type = tt;
-                 }
-
-               TYPE_ALIGN (type) = (1 << i) * BITS_PER_UNIT;
-               TYPE_USER_ALIGN (type) = 1;
-             }
-           else if (TREE_CODE (decl) != VAR_DECL
-                    && TREE_CODE (decl) != FIELD_DECL)
-             error_with_decl (decl,
-                              "alignment may not be specified for `%s'");
-           else
-             {
-               DECL_ALIGN (decl) = (1 << i) * BITS_PER_UNIT;
-               DECL_USER_ALIGN (decl) = 1;
-             }
-         }
-         break;
+/* Handle a "common" attribute; arguments as in
+   struct attribute_spec.handler.  */
+static tree
+handle_common_attribute (node, name, args, flags, no_add_attrs)
+     tree *node;
+     tree name;
+     tree args ATTRIBUTE_UNUSED;
+     int flags ATTRIBUTE_UNUSED;
+     bool *no_add_attrs;
+{
+  if (TREE_CODE (*node) == VAR_DECL)
+    DECL_COMMON (*node) = 1;
+  else
+    {
+      warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
+      *no_add_attrs = true;
+    }
 
-       case A_FORMAT:
-         decl_handle_format_attribute (decl, args);
-         break;
+  return NULL_TREE;
+}
 
-       case A_FORMAT_ARG:
-         decl_handle_format_arg_attribute (decl, args);
-         break;
+/* Handle a "noreturn" attribute; arguments as in
+   struct attribute_spec.handler.  */
+static tree
+handle_noreturn_attribute (node, name, args, flags, no_add_attrs)
+     tree *node;
+     tree name;
+     tree args ATTRIBUTE_UNUSED;
+     int flags ATTRIBUTE_UNUSED;
+     bool *no_add_attrs;
+{
+  tree type = TREE_TYPE (*node);
+
+  /* See FIXME comment in c_common_attribute_table.  */
+  if (TREE_CODE (*node) == FUNCTION_DECL)
+    TREE_THIS_VOLATILE (*node) = 1;
+  else if (TREE_CODE (type) == POINTER_TYPE
+          && TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE)
+    TREE_TYPE (*node)
+      = build_pointer_type (build_type_variant (TREE_TYPE (type),
+                                               TREE_READONLY (TREE_TYPE (type)), 1));
+  else
+    {
+      warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
+      *no_add_attrs = true;
+    }
 
-       case A_WEAK:
-         declare_weak (decl);
-         break;
+  return NULL_TREE;
+}
 
-       case A_ALIAS:
-         if ((TREE_CODE (decl) == FUNCTION_DECL && DECL_INITIAL (decl))
-             || (TREE_CODE (decl) != FUNCTION_DECL && ! DECL_EXTERNAL (decl)))
-           error_with_decl (decl,
-                            "`%s' defined both normally and as an alias");
-         else if (decl_function_context (decl) == 0)
-           {
-             tree id;
+/* Handle a "unused" attribute; arguments as in
+   struct attribute_spec.handler.  */
+static tree
+handle_unused_attribute (node, name, args, flags, no_add_attrs)
+     tree *node;
+     tree name;
+     tree args ATTRIBUTE_UNUSED;
+     int flags;
+     bool *no_add_attrs;
+{
+  if (DECL_P (*node))
+    {
+      tree decl = *node;
+
+      if (TREE_CODE (decl) == PARM_DECL
+         || TREE_CODE (decl) == VAR_DECL
+         || TREE_CODE (decl) == FUNCTION_DECL
+         || TREE_CODE (decl) == LABEL_DECL
+         || TREE_CODE (decl) == TYPE_DECL)
+       TREE_USED (decl) = 1;
+      else
+       {
+         warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
+         *no_add_attrs = true;
+       }
+    }
+  else
+    {
+      if (!(flags & (int) ATTR_FLAG_TYPE_IN_PLACE))
+       *node = build_type_copy (*node);
+      TREE_USED (*node) = 1;
+    }
 
-             id = TREE_VALUE (args);
-             if (TREE_CODE (id) != STRING_CST)
-               {
-                 error ("alias arg not a string");
-                 break;
-               }
-             id = get_identifier (TREE_STRING_POINTER (id));
-             /* This counts as a use of the object pointed to.  */
-             TREE_USED (id) = 1;
+  return NULL_TREE;
+}
 
-             if (TREE_CODE (decl) == FUNCTION_DECL)
-               DECL_INITIAL (decl) = error_mark_node;
-             else
-               DECL_EXTERNAL (decl) = 0;
-             assemble_alias (decl, id);
-           }
-         else
-           warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
-         break;
+/* Handle a "const" attribute; arguments as in
+   struct attribute_spec.handler.  */
+static tree
+handle_const_attribute (node, name, args, flags, no_add_attrs)
+     tree *node;
+     tree name;
+     tree args ATTRIBUTE_UNUSED;
+     int flags ATTRIBUTE_UNUSED;
+     bool *no_add_attrs;
+{
+  tree type = TREE_TYPE (*node);
+
+  /* See FIXME comment on noreturn in c_common_attribute_table.  */
+  if (TREE_CODE (*node) == FUNCTION_DECL)
+    TREE_READONLY (*node) = 1;
+  else if (TREE_CODE (type) == POINTER_TYPE
+          && TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE)
+    TREE_TYPE (*node)
+      = build_pointer_type (build_type_variant (TREE_TYPE (type), 1,
+                                               TREE_THIS_VOLATILE (TREE_TYPE (type))));
+  else
+    {
+      warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
+      *no_add_attrs = true;
+    }
 
-       case A_NO_CHECK_MEMORY_USAGE:
-         if (TREE_CODE (decl) != FUNCTION_DECL)
-           {
-             error_with_decl (decl,
-                              "`%s' attribute applies only to functions",
-                              IDENTIFIER_POINTER (name));
-           }
-         else if (DECL_INITIAL (decl))
-           {
-             error_with_decl (decl,
-                              "can't set `%s' attribute after definition",
-                              IDENTIFIER_POINTER (name));
-           }
-         else
-           DECL_NO_CHECK_MEMORY_USAGE (decl) = 1;
-         break;
+  return NULL_TREE;
+}
 
-       case A_NO_INSTRUMENT_FUNCTION:
-         if (TREE_CODE (decl) != FUNCTION_DECL)
-           {
-             error_with_decl (decl,
-                              "`%s' attribute applies only to functions",
-                              IDENTIFIER_POINTER (name));
-           }
-         else if (DECL_INITIAL (decl))
-           {
-             error_with_decl (decl,
-                              "can't set `%s' attribute after definition",
-                              IDENTIFIER_POINTER (name));
-           }
-         else
-           DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (decl) = 1;
-         break;
+/* Handle a "transparent_union" attribute; arguments as in
+   struct attribute_spec.handler.  */
+static tree
+handle_transparent_union_attribute (node, name, args, flags, no_add_attrs)
+     tree *node;
+     tree name;
+     tree args ATTRIBUTE_UNUSED;
+     int flags;
+     bool *no_add_attrs;
+{
+  tree decl = NULL_TREE;
+  tree *type = NULL;
+  int is_type = 0;
+
+  if (DECL_P (*node))
+    {
+      decl = *node;
+      type = &TREE_TYPE (decl);
+      is_type = TREE_CODE (*node) == TYPE_DECL;
+    }
+  else if (TYPE_P (*node))
+    type = node, is_type = 1;
+
+  if (is_type
+      && TREE_CODE (*type) == UNION_TYPE
+      && (decl == 0
+         || (TYPE_FIELDS (*type) != 0
+             && TYPE_MODE (*type) == DECL_MODE (TYPE_FIELDS (*type)))))
+    {
+      if (!(flags & (int) ATTR_FLAG_TYPE_IN_PLACE))
+       *type = build_type_copy (*type);
+      TYPE_TRANSPARENT_UNION (*type) = 1;
+    }
+  else if (decl != 0 && TREE_CODE (decl) == PARM_DECL
+          && TREE_CODE (*type) == UNION_TYPE
+          && TYPE_MODE (*type) == DECL_MODE (TYPE_FIELDS (*type)))
+    DECL_TRANSPARENT_UNION (decl) = 1;
+  else
+    {
+      warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
+      *no_add_attrs = true;
+    }
+
+  return NULL_TREE;
+}
+
+/* Handle a "constructor" attribute; arguments as in
+   struct attribute_spec.handler.  */
+static tree
+handle_constructor_attribute (node, name, args, flags, no_add_attrs)
+     tree *node;
+     tree name;
+     tree args ATTRIBUTE_UNUSED;
+     int flags ATTRIBUTE_UNUSED;
+     bool *no_add_attrs;
+{
+  tree decl = *node;
+  tree type = TREE_TYPE (decl);
+
+  if (TREE_CODE (decl) == FUNCTION_DECL
+      && TREE_CODE (type) == FUNCTION_TYPE
+      && decl_function_context (decl) == 0)
+    {
+      DECL_STATIC_CONSTRUCTOR (decl) = 1;
+      TREE_USED (decl) = 1;
+    }
+  else
+    {
+      warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
+      *no_add_attrs = true;
+    }
+
+  return NULL_TREE;
+}
+
+/* Handle a "destructor" attribute; arguments as in
+   struct attribute_spec.handler.  */
+static tree
+handle_destructor_attribute (node, name, args, flags, no_add_attrs)
+     tree *node;
+     tree name;
+     tree args ATTRIBUTE_UNUSED;
+     int flags ATTRIBUTE_UNUSED;
+     bool *no_add_attrs;
+{
+  tree decl = *node;
+  tree type = TREE_TYPE (decl);
+
+  if (TREE_CODE (decl) == FUNCTION_DECL
+      && TREE_CODE (type) == FUNCTION_TYPE
+      && decl_function_context (decl) == 0)
+    {
+      DECL_STATIC_DESTRUCTOR (decl) = 1;
+      TREE_USED (decl) = 1;
+    }
+  else
+    {
+      warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
+      *no_add_attrs = true;
+    }
+
+  return NULL_TREE;
+}
+
+/* Handle a "mode" attribute; arguments as in
+   struct attribute_spec.handler.  */
+static tree
+handle_mode_attribute (node, name, args, flags, no_add_attrs)
+     tree *node;
+     tree name;
+     tree args;
+     int flags ATTRIBUTE_UNUSED;
+     bool *no_add_attrs;
+{
+  tree decl = *node;
+  tree type = TREE_TYPE (decl);
+
+  *no_add_attrs = true;
+
+  if (TREE_CODE (TREE_VALUE (args)) != IDENTIFIER_NODE)
+    warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
+  else
+    {
+      int j;
+      const char *p = IDENTIFIER_POINTER (TREE_VALUE (args));
+      int len = strlen (p);
+      enum machine_mode mode = VOIDmode;
+      tree typefm;
+
+      if (len > 4 && p[0] == '_' && p[1] == '_'
+         && p[len - 1] == '_' && p[len - 2] == '_')
+       {
+         char *newp = (char *) alloca (len - 1);
+
+         strcpy (newp, &p[2]);
+         newp[len - 4] = '\0';
+         p = newp;
+       }
+
+      /* Give this decl a type with the specified mode.
+        First check for the special modes.  */
+      if (! strcmp (p, "byte"))
+       mode = byte_mode;
+      else if (!strcmp (p, "word"))
+       mode = word_mode;
+      else if (! strcmp (p, "pointer"))
+       mode = ptr_mode;
+      else
+       for (j = 0; j < NUM_MACHINE_MODES; j++)
+         if (!strcmp (p, GET_MODE_NAME (j)))
+           mode = (enum machine_mode) j;
+
+      if (mode == VOIDmode)
+       error ("unknown machine mode `%s'", p);
+      else if (0 == (typefm = type_for_mode (mode,
+                                            TREE_UNSIGNED (type))))
+       error ("no data type for mode `%s'", p);
+      else
+       {
+         if (TYPE_PRECISION (typefm) > (TREE_UNSIGNED (type)
+                                        ? TYPE_PRECISION(uintmax_type_node)
+                                        : TYPE_PRECISION(intmax_type_node))
+             && pedantic)
+           pedwarn ("type with more precision than %s",
+                    TREE_UNSIGNED (type) ? "uintmax_t" : "intmax_t");
+         TREE_TYPE (decl) = type = typefm;
+         DECL_SIZE (decl) = DECL_SIZE_UNIT (decl) = 0;
+         if (TREE_CODE (decl) != FIELD_DECL)
+           layout_decl (decl, 0);
+       }
+    }
 
-        case A_NO_LIMIT_STACK:
-         if (TREE_CODE (decl) != FUNCTION_DECL)
+  return NULL_TREE;
+}
+
+/* Handle a "section" attribute; arguments as in
+   struct attribute_spec.handler.  */
+static tree
+handle_section_attribute (node, name, args, flags, no_add_attrs)
+     tree *node;
+     tree name ATTRIBUTE_UNUSED;
+     tree args;
+     int flags ATTRIBUTE_UNUSED;
+     bool *no_add_attrs;
+{
+  tree decl = *node;
+
+  if (targetm.have_named_sections)
+    {
+      if ((TREE_CODE (decl) == FUNCTION_DECL
+          || TREE_CODE (decl) == VAR_DECL)
+         && TREE_CODE (TREE_VALUE (args)) == STRING_CST)
+       {
+         if (TREE_CODE (decl) == VAR_DECL
+             && current_function_decl != NULL_TREE
+             && ! TREE_STATIC (decl))
            {
              error_with_decl (decl,
-                              "`%s' attribute applies only to functions",
-                              IDENTIFIER_POINTER (name));
+                              "section attribute cannot be specified for local variables");
+             *no_add_attrs = true;
            }
-         else if (DECL_INITIAL (decl))
+         /* The decl may have already been given a section attribute
+            from a previous declaration.  Ensure they match.  */
+         else if (DECL_SECTION_NAME (decl) != NULL_TREE
+                  && strcmp (TREE_STRING_POINTER (DECL_SECTION_NAME (decl)),
+                             TREE_STRING_POINTER (TREE_VALUE (args))) != 0)
            {
-             error_with_decl (decl,
-                              "can't set `%s' attribute after definition",
-                              IDENTIFIER_POINTER (name));
+             error_with_decl (*node,
+                              "section of `%s' conflicts with previous declaration");
+             *no_add_attrs = true;
            }
          else
-           DECL_NO_LIMIT_STACK (decl) = 1;
-         break;
+           DECL_SECTION_NAME (decl) = TREE_VALUE (args);
+       }
+      else
+       {
+         error_with_decl (*node,
+                          "section attribute not allowed for `%s'");
+         *no_add_attrs = true;
+       }
+    }
+  else
+    {
+      error_with_decl (*node,
+                      "section attributes are not supported for this target");
+      *no_add_attrs = true;
+    }
+
+  return NULL_TREE;
+}
+
+/* Handle a "aligned" attribute; arguments as in
+   struct attribute_spec.handler.  */
+static tree
+handle_aligned_attribute (node, name, args, flags, no_add_attrs)
+     tree *node;
+     tree name ATTRIBUTE_UNUSED;
+     tree args;
+     int flags;
+     bool *no_add_attrs;
+{
+  tree decl = NULL_TREE;
+  tree *type = NULL;
+  int is_type = 0;
+  tree align_expr = (args ? TREE_VALUE (args)
+                    : size_int (BIGGEST_ALIGNMENT / BITS_PER_UNIT));
+  int i;
+
+  if (DECL_P (*node))
+    {
+      decl = *node;
+      type = &TREE_TYPE (decl);
+      is_type = TREE_CODE (*node) == TYPE_DECL;
+    }
+  else if (TYPE_P (*node))
+    type = node, is_type = 1;
+
+  /* Strip any NOPs of any kind.  */
+  while (TREE_CODE (align_expr) == NOP_EXPR
+        || TREE_CODE (align_expr) == CONVERT_EXPR
+        || TREE_CODE (align_expr) == NON_LVALUE_EXPR)
+    align_expr = TREE_OPERAND (align_expr, 0);
+
+  if (TREE_CODE (align_expr) != INTEGER_CST)
+    {
+      error ("requested alignment is not a constant");
+      *no_add_attrs = true;
+    }
+  else if ((i = tree_log2 (align_expr)) == -1)
+    {
+      error ("requested alignment is not a power of 2");
+      *no_add_attrs = true;
+    }
+  else if (i > HOST_BITS_PER_INT - 2)
+    {
+      error ("requested alignment is too large");
+      *no_add_attrs = true;
+    }
+  else if (is_type)
+    {
+      /* If we have a TYPE_DECL, then copy the type, so that we
+        don't accidentally modify a builtin type.  See pushdecl.  */
+      if (decl && TREE_TYPE (decl) != error_mark_node
+         && DECL_ORIGINAL_TYPE (decl) == NULL_TREE)
+       {
+         tree tt = TREE_TYPE (decl);
+         *type = build_type_copy (*type);
+         DECL_ORIGINAL_TYPE (decl) = tt;
+         TYPE_NAME (*type) = decl;
+         TREE_USED (*type) = TREE_USED (decl);
+         TREE_TYPE (decl) = *type;
        }
+      else if (!(flags & (int) ATTR_FLAG_TYPE_IN_PLACE))
+       *type = build_type_copy (*type);
+
+      TYPE_ALIGN (*type) = (1 << i) * BITS_PER_UNIT;
+      TYPE_USER_ALIGN (*type) = 1;
+    }
+  else if (TREE_CODE (decl) != VAR_DECL
+          && TREE_CODE (decl) != FIELD_DECL)
+    {
+      error_with_decl (decl,
+                      "alignment may not be specified for `%s'");
+      *no_add_attrs = true;
+    }
+  else
+    {
+      DECL_ALIGN (decl) = (1 << i) * BITS_PER_UNIT;
+      DECL_USER_ALIGN (decl) = 1;
+    }
+
+  return NULL_TREE;
+}
+
+/* Handle a "weak" attribute; arguments as in
+   struct attribute_spec.handler.  */
+static tree
+handle_weak_attribute (node, name, args, flags, no_add_attrs)
+     tree *node;
+     tree name ATTRIBUTE_UNUSED;
+     tree args ATTRIBUTE_UNUSED;
+     int flags ATTRIBUTE_UNUSED;
+     bool *no_add_attrs ATTRIBUTE_UNUSED;
+{
+  declare_weak (*node);
+
+  return NULL_TREE;
+}
+
+/* Handle an "alias" attribute; arguments as in
+   struct attribute_spec.handler.  */
+static tree
+handle_alias_attribute (node, name, args, flags, no_add_attrs)
+     tree *node;
+     tree name;
+     tree args;
+     int flags ATTRIBUTE_UNUSED;
+     bool *no_add_attrs;
+{
+  tree decl = *node;
+
+  if ((TREE_CODE (decl) == FUNCTION_DECL && DECL_INITIAL (decl))
+      || (TREE_CODE (decl) != FUNCTION_DECL && ! DECL_EXTERNAL (decl)))
+    {
+      error_with_decl (decl,
+                      "`%s' defined both normally and as an alias");
+      *no_add_attrs = true;
+    }
+  else if (decl_function_context (decl) == 0)
+    {
+      tree id;
+
+      id = TREE_VALUE (args);
+      if (TREE_CODE (id) != STRING_CST)
+       {
+         error ("alias arg not a string");
+         *no_add_attrs = true;
+         return NULL_TREE;
+       }
+      id = get_identifier (TREE_STRING_POINTER (id));
+      /* This counts as a use of the object pointed to.  */
+      TREE_USED (id) = 1;
+
+      if (TREE_CODE (decl) == FUNCTION_DECL)
+       DECL_INITIAL (decl) = error_mark_node;
+      else
+       DECL_EXTERNAL (decl) = 0;
+      assemble_alias (decl, id);
+    }
+  else
+    {
+      warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
+      *no_add_attrs = true;
+    }
+
+  return NULL_TREE;
+}
+
+/* Handle a "no_instrument_function" attribute; arguments as in
+   struct attribute_spec.handler.  */
+static tree
+handle_no_instrument_function_attribute (node, name, args, flags, no_add_attrs)
+     tree *node;
+     tree name;
+     tree args ATTRIBUTE_UNUSED;
+     int flags ATTRIBUTE_UNUSED;
+     bool *no_add_attrs;
+{
+  tree decl = *node;
+
+  if (TREE_CODE (decl) != FUNCTION_DECL)
+    {
+      error_with_decl (decl,
+                      "`%s' attribute applies only to functions",
+                      IDENTIFIER_POINTER (name));
+      *no_add_attrs = true;
+    }
+  else if (DECL_INITIAL (decl))
+    {
+      error_with_decl (decl,
+                      "can't set `%s' attribute after definition",
+                      IDENTIFIER_POINTER (name));
+      *no_add_attrs = true;
+    }
+  else
+    DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (decl) = 1;
+
+  return NULL_TREE;
+}
+
+/* Handle a "no_check_memory_usage" attribute; arguments as in
+   struct attribute_spec.handler.  */
+static tree
+handle_no_check_memory_usage_attribute (node, name, args, flags, no_add_attrs)
+     tree *node;
+     tree name;
+     tree args ATTRIBUTE_UNUSED;
+     int flags ATTRIBUTE_UNUSED;
+     bool *no_add_attrs;
+{
+  tree decl = *node;
+
+  if (TREE_CODE (decl) != FUNCTION_DECL)
+    {
+      error_with_decl (decl,
+                      "`%s' attribute applies only to functions",
+                      IDENTIFIER_POINTER (name));
+      *no_add_attrs = true;
+    }
+  else if (DECL_INITIAL (decl))
+    {
+      error_with_decl (decl,
+                      "can't set `%s' attribute after definition",
+                      IDENTIFIER_POINTER (name));
+      *no_add_attrs = true;
     }
+  else
+    DECL_NO_CHECK_MEMORY_USAGE (decl) = 1;
+
+  return NULL_TREE;
+}
+
+/* Handle a "malloc" attribute; arguments as in
+   struct attribute_spec.handler.  */
+static tree
+handle_malloc_attribute (node, name, args, flags, no_add_attrs)
+     tree *node;
+     tree name;
+     tree args ATTRIBUTE_UNUSED;
+     int flags ATTRIBUTE_UNUSED;
+     bool *no_add_attrs;
+{
+  if (TREE_CODE (*node) == FUNCTION_DECL)
+    DECL_IS_MALLOC (*node) = 1;
+  /* ??? TODO: Support types.  */
+  else
+    {
+      warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
+      *no_add_attrs = true;
+    }
+
+  return NULL_TREE;
+}
+
+/* Handle a "no_limit_stack" attribute; arguments as in
+   struct attribute_spec.handler.  */
+static tree
+handle_no_limit_stack_attribute (node, name, args, flags, no_add_attrs)
+     tree *node;
+     tree name;
+     tree args ATTRIBUTE_UNUSED;
+     int flags ATTRIBUTE_UNUSED;
+     bool *no_add_attrs;
+{
+  tree decl = *node;
+
+  if (TREE_CODE (decl) != FUNCTION_DECL)
+    {
+      error_with_decl (decl,
+                      "`%s' attribute applies only to functions",
+                      IDENTIFIER_POINTER (name));
+      *no_add_attrs = true;
+    }
+  else if (DECL_INITIAL (decl))
+    {
+      error_with_decl (decl,
+                      "can't set `%s' attribute after definition",
+                      IDENTIFIER_POINTER (name));
+      *no_add_attrs = true;
+    }
+  else
+    DECL_NO_LIMIT_STACK (decl) = 1;
+
+  return NULL_TREE;
+}
+
+/* Handle a "pure" attribute; arguments as in
+   struct attribute_spec.handler.  */
+static tree
+handle_pure_attribute (node, name, args, flags, no_add_attrs)
+     tree *node;
+     tree name;
+     tree args ATTRIBUTE_UNUSED;
+     int flags ATTRIBUTE_UNUSED;
+     bool *no_add_attrs;
+{
+  if (TREE_CODE (*node) == FUNCTION_DECL)
+    DECL_IS_PURE (*node) = 1;
+  /* ??? TODO: Support types.  */
+  else
+    {
+      warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
+      *no_add_attrs = true;
+    }
+
   return NULL_TREE;
 }
 
index 26933b7..6ab2c06 100644 (file)
@@ -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));
index d0beb0f..4652267 100644 (file)
@@ -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.  */
 
index d7ef210..331cd25 100644 (file)
@@ -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
index 0d76c3e..85c2815 100644 (file)
@@ -173,7 +173,7 @@ end ifc
 %type <ttype> declspecs_ts declspecs_nots
 %type <ttype> declspecs_ts_nosa declspecs_nots_nosa
 %type <ttype> declspecs_nosc_ts declspecs_nosc_nots declspecs_nosc declspecs
-%type <ttype> maybe_type_quals_setattrs typespec_nonattr typespec_attr
+%type <ttype> maybe_type_quals_attrs typespec_nonattr typespec_attr
 %type <ttype> typespec_reserved_nonattr typespec_reserved_attr
 %type <ttype> typespec_nonreserved_nonattr
 
@@ -182,7 +182,6 @@ end ifc
 %type <ttype> init maybeasm
 %type <ttype> asm_operands nonnull_asm_operands asm_operand asm_clobbers
 %type <ttype> maybe_attribute attributes attribute attribute_list attrib
-%type <ttype> maybe_setattrs
 %type <ttype> any_word extension
 
 %type <ttype> 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 ($<ttype>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);
 }
index 79c247b..4439368 100644 (file)
@@ -181,13 +181,13 @@ static int unicosmk_need_dex PARAMS ((rtx));
 \f
 /* 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;
index 0fe070b..6875a6f 100644 (file)
@@ -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));
 \f
@@ -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;
 \f
@@ -326,26 +327,40 @@ arc_init_reg_tables ()
    interrupt - for interrupt functions
 */
 
-/* Return nonzero if IDENTIFIER is a valid decl attribute.  */
+const struct attribute_spec arc_attribute_table[] =
+{
+  /* { 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 }
+};
 
-static int
-arc_valid_decl_attribute (type, attributes, identifier, args)
-     tree type ATTRIBUTE_UNUSED;
-     tree attributes ATTRIBUTE_UNUSED;
-     tree identifier;
+/* 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;
 {
-  if (identifier == get_identifier ("__interrupt__")
-      && list_length (args) == 1
-      && TREE_CODE (TREE_VALUE (args)) == STRING_CST)
-    {
-      tree value = TREE_VALUE (args);
+  tree value = TREE_VALUE (args);
 
-      if (!strcmp (TREE_STRING_POINTER (value), "ilink1")
-          || !strcmp (TREE_STRING_POINTER (value), "ilink2"))
-       return 1;
+  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;
 }
 
 \f
@@ -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))
     {
index 1ad558e..fcd90dd 100644 (file)
@@ -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)
 }
 
 \f
-/* 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
+
+     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 }
+};
 
-  return 0;
+/* 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;
 }
 \f
-/* 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  */
-\f
 /* 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
index 29c470e..9e7e95a 100644 (file)
@@ -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;
 
index 5e9c172..ed54cbb 100644 (file)
@@ -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;
 \f
@@ -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;
index 8ae9302..9ded05e 100644 (file)
@@ -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
index 872cdfd..7ed86b2 100644 (file)
@@ -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));
 \f
 /* 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)
     }
 }
 
+/* Table of valid machine attributes.  */
+const struct attribute_spec c4x_attribute_table[] =
+{
+  /* { 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 }
+};
 
-/* 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;
+/* 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 (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;
+  if (TREE_CODE (*node) != FUNCTION_TYPE)
+    {
+      warning ("`%s' attribute only applies to functions",
+              IDENTIFIER_POINTER (name));
+      *no_add_attrs = true;
+    }
+
+  return NULL_TREE;
 }
 
 
index abf2d47..1ab9dc7 100644 (file)
@@ -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
index 57d5661..e94902c 100644 (file)
@@ -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
index c998ac2..34686a6 100644 (file)
@@ -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;
 \f
 /* 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
index d325167..138d96f 100644 (file)
@@ -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
index b6462e1..a81a29b 100644 (file)
@@ -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));
index c89a0ab..028c1ac 100644 (file)
@@ -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
 \f
 /* 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
 }
 \f
-/* 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)
     {
-      tree cst;
+      warning ("`%s' attribute only applies to functions",
+              IDENTIFIER_POINTER (name));
+      *no_add_attrs = true;
+    }
 
-      if (! args || TREE_CODE (args) != TREE_LIST
-         || TREE_CHAIN (args) != NULL_TREE
-         || TREE_VALUE (args) == NULL_TREE)
-       return 0;
+  if (TARGET_64BIT)
+    {
+      warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
+      *no_add_attrs = true;
+    }
 
-      cst = TREE_VALUE (args);
-      if (TREE_CODE (cst) != INTEGER_CST)
-       return 0;
+  return NULL_TREE;
+}
 
-      if (compare_tree_int (cst, REGPARM_MAX) > 0)
-       return 0;
+/* 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;
 
-      return 1;
+      cst = TREE_VALUE (args);
+      if (TREE_CODE (cst) != INTEGER_CST)
+       {
+         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)
index d32224f..e14359d 100644 (file)
@@ -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;
 }
 \f
 /* 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;
     }
 
index 9da4270..9c56f37 100644 (file)
@@ -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));
 
 \f
 /* 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 }
+};
 \f
 /* For ia64, SYMBOL_REF_FLAG set means that it is a function.
 
index a9ca24f..f1ed72d 100644 (file)
@@ -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));
 
 \f
 /* 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.  */
+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 }
+};
 
-static int
-m32r_valid_decl_attribute (type, attributes, identifier, args)
-     tree type ATTRIBUTE_UNUSED;
-     tree attributes ATTRIBUTE_UNUSED;
-     tree identifier;
+
+/* 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;
 {
-  init_idents ();
-
-  if ((identifier == interrupt_ident1
-       || identifier == interrupt_ident2)
-      && list_length (args) == 0)
-    return 1;
+  tree arg;
 
-  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;
+  init_idents ();
+  arg = TREE_VALUE (args);
+
+  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;
+    }
 
-  return 0;
+  return NULL_TREE;
 }
 \f
 /* 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);
 
index 3bd9ce6..da45de0 100644 (file)
@@ -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;
 \f
 /* 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)
 \f
 /* 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
index 095eef3..0a4a2b5 100644 (file)
@@ -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));
 \f
@@ -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;
 \f
@@ -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;
-{
-  if (args != NULL_TREE)
-    return 0;
 
-  if (is_attribute_p ("dllexport", attr))
-    return 1;
+const struct attribute_spec mcore_attribute_table[] =
+{
+  /* { 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 ("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
index b6bd0da..a7e89c2 100644 (file)
@@ -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));
 \f
 /* 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;
 }
 \f
-/* 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
-ns32k_valid_type_attribute_p (type, attributes, identifier, args)
-     tree type;
-     tree attributes ATTRIBUTE_UNUSED;
-     tree identifier;
-     tree args;
-{
-  if (TREE_CODE (type) != FUNCTION_TYPE
-      && TREE_CODE (type) != FIELD_DECL
-      && TREE_CODE (type) != TYPE_DECL)
-    return 0;
+/* Table of machine-specific attributes.  */
 
+const struct attribute_spec ns32k_attribute_table[] =
+{
+  /* { 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;
 }
 
 \f
index c1b1f71..738c8a5 100644 (file)
@@ -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
 \f
 /* 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)
 }
 
 \f
-/* 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
index 29a657b..684cff1 100644 (file)
@@ -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));
 \f
 /* 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;
 }
 
 \f
index ebb9be7..6ecf8ae 100644 (file)
@@ -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;
+#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[] =
+{
+  /* { 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 }
+};
+
+/* 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 (type) != FUNCTION_TYPE)
-    return 0;
-  
-  if (is_attribute_p ("interrupt", identifier))
-    return 1;
+  if (TREE_CODE (*node) != FUNCTION_TYPE)
+    {
+      warning ("`%s' attribute only applies to functions",
+              IDENTIFIER_POINTER (name));
+      *no_add_attrs = true;
+    }
 
-  return 0;
+  return NULL_TREE;
 }
 \f
 struct gcc_target targetm = TARGET_INITIALIZER;
index a6badd1..d5920bc 100644 (file)
@@ -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
index d541a66..84aef1f 100644 (file)
@@ -35,7 +35,7 @@ Boston, MA 02111-1307, USA.  */
 \f
 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));
 \f
 /* 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 (&current_function_decl,
+                  tree_cons (name, NULL_TREE, NULL_TREE), 0);
 }
 
 \f
index 8ce09bf..ea83c15 100644 (file)
@@ -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;
 \f
 /* 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));
 }
 \f
-/* 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;
 }
 
 \f
@@ -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;
     }
 
index 8d0498f..345cef4 100644 (file)
@@ -1,3 +1,43 @@
+2001-09-21  Joseph S. Myers  <jsm28@cam.ac.uk>
+
+       Table-driven attributes.
+       * decl.c: Rename DECL_MACHINE_ATTRIBUTES to DECL_ATTRIBUTES.
+       * decl2.c (cplus_decl_attributes): Only take one attributes
+       parameter.
+       * cp-tree.c (cplus_decl_attributes): Update prototype.
+       * class.c (finish_struct), decl.c (start_decl, start_function),
+       decl2.c (grokfield), friend.c (do_friend), parse.y
+       (parse_bitfield): Update calls to cplus_decl_attributes.
+       * decl.c (grokdeclarator): Take a pointer to a single ordinary
+       attribute list.
+       * decl.h (grokdeclarator): Update prototype.
+       * decl2.c (grokfield): Take a single ordinary attribute list.
+       * friend.c (do_friend): Likewise.
+       * decl.c (shadow_tag, groktypename, start_decl,
+       start_handler_parms, grokdeclarator, grokparms, start_function,
+       start_method), decl2.c (grokfield, grokbitfield, grokoptypename),
+       parse.y (parse_field, parse_bitfield, component_decl_1), pt.c
+       (process_template_parm, do_decl_instantiation): Pass single
+       ordinary attribute lists around.
+       * decl.c (grokdeclarator): Correct handling of nested attributes.
+       Revert the patch
+       1998-10-18  Jason Merrill  <jason@yorick.cygnus.com>
+               * decl.c (grokdeclarator): Embedded attrs bind to the right,
+               not the left.
+       .
+       * cp-tree.h (cp_valid_lang_attribute): Remove declaration
+       (cp_attribute_table): Declare.
+       * decl.c (valid_lang_attribute): Don't define.
+       (lang_attribute_table): Define.
+       (init_decl_processing): Initialize lang_attribute_table instead of
+       valid_lang_attribute.
+       * tree.c (cp_valid_lang_attribute): Remove.
+       (handle_java_interface_attribute, handle_com_interface_attribute,
+       handle_init_priority_attribute): New functions.
+       (cp_attribute_table): New array.
+       * decl2.c (import_export_class): Don't use
+       targetm.valid_type_attribute.
+
 2001-09-15  Gabriel Dos Reis  <gdr@merlin.codesourcery.com>
 
                * Make-lang.in (cp/error.o): Depend on real.h
index 1526a05..0c106c3 100644 (file)
@@ -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.  */
index 04837da..2662356 100644 (file)
@@ -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 *));
index 9244272..60938a7 100644 (file)
@@ -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)
index c5417d1..6f1418a 100644 (file)
@@ -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.  */
index 5c62aca..28236ef 100644 (file)
@@ -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)
 }
 \f
 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
index f7ff984..d6d720c 100644 (file)
@@ -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;
 }
index 3b89022..9801c38 100644 (file)
@@ -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); }
 
index 05ce365..292513f 100644 (file)
@@ -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;
 
index 04e8add..32783ad 100644 (file)
@@ -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))
+  /* { 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 }
+};
+
+/* 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))
     {
-      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;
+      error ("`%s' attribute can only be applied to Java class definitions",
+            IDENTIFIER_POINTER (name));
+      *no_add_attrs = true;
+      return NULL_TREE;
     }
-  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;
-       }
+  if (!(flags & (int) ATTR_FLAG_TYPE_IN_PLACE))
+    *node = build_type_copy (*node);
+  TYPE_JAVA_INTERFACE (*node) = 1;
 
-      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))
+  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))
     {
-      tree initp_expr = (attr_args ? TREE_VALUE (attr_args): NULL_TREE);
-      int pri;
+      warning ("`%s' attribute can only be applied to class definitions",
+              IDENTIFIER_POINTER (name));
+      return NULL_TREE;
+    }
 
-      if (initp_expr)
-       STRIP_NOPS (initp_expr);
+  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;
-       }
+  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;
+    }
 
-      pri = TREE_INT_CST_LOW (initp_expr);
+  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;
-       }
+  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;
+    }
 
-      /* 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 (pri > MAX_INIT_PRIORITY || pri <= 0)
+    {
+      error ("requested init_priority is out of range");
+      *no_add_attrs = true;
+      return NULL_TREE;
+    }
 
-      if (SUPPORTS_INIT_PRIORITY)
-       {
-         DECL_INIT_PRIORITY (decl) = pri;
-         return 1;
-       }
-      else
-       {
-         error ("init_priority attribute is not supported on this platform");
-         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");
     }
 
-  return 0;
+  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
index 9d9c25d..350c9bc 100644 (file)
@@ -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.
-
-@deftypefn {Tree Macro} tree DECL_MACHINE_ATTRIBUTES (tree @var{decl})
+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_ATTRIBUTES (tree @var{decl})
 This macro returns the attributes on the declaration @var{decl}.
 @end deftypefn
 
index 0834496..ea60b57 100644 (file)
@@ -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
index 71e4cd9..721e161 100644 (file)
@@ -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
index 154d47b..80de380 100644 (file)
@@ -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));
index db59935..7887b36 100644 (file)
@@ -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
 \f
 
 /* 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;
index c0550f7..f4476ba 100644 (file)
@@ -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);
 
index 3282b3c..4b298bc 100644 (file)
@@ -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,                   \
index 8d73f49..f7eca62 100644 (file)
@@ -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));
 
index 16d4816..74508a6 100644 (file)
@@ -1,3 +1,8 @@
+2001-09-21  Joseph S. Myers  <jsm28@cam.ac.uk>
+
+       Table-driven attributes.
+       * g++.dg/ext/attrib1.C: New test.
+
 2001-09-20  DJ Delorie  <dj@redhat.com>
 
        * 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 (file)
index 0000000..2bd69e8
--- /dev/null
@@ -0,0 +1,10 @@
+// Test for interpretation of attribute immediately before function name.
+// Origin: Joseph Myers <jsm28@cam.ac.uk>
+// { 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 *, ...);
index 731791c..1741f6a 100644 (file)
@@ -2605,14 +2605,14 @@ build_expr_wfl (node, file, line, col)
   return wfl;
 }
 \f
-/* 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;
-
-  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;
-    }
+  { NULL, 0, 0, false, false, false, NULL }
+};
 
-  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;
index 8ef9156..aee8434 100644 (file)
@@ -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.  */