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