This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

Table-driven attributes patch


This patch implements table-driven attribute handling, as previously
discussed (e.g.,
<URL:http://gcc.gnu.org/ml/gcc-patches/2001-07/msg00826.html>,
<URL:http://gcc.gnu.org/ml/gcc/2001-07/msg00872.html>).

Because of the way various related issues seemed to be interdependent
on implementation, this patch does more and took longer to finish than
I'd originally intended when I started it:

* c-common attributes are made table-driven; so are the C++ front-end
  ones and all the machine attributes.

* The C front end will handle attributes on nested declarators
  properly; the bug in how the C++ front end handles them noted in
  <URL:http://gcc.gnu.org/ml/gcc/2001-07/msg00106.html> is fixed.
  Documentation is added about the problems with the semantics of
  attributes in C++ and warning of the possible deprecation of nested
  attributes in C++ per
  <URL:http://gcc.gnu.org/ml/gcc/2001-07/msg01607.html>.

* However, useful support for the c-common attributes to be nested is
  not added; for example, doing this for noreturn requires various
  places in the compiler checking TREE_THIS_VOLATILE on decls to
  change to checking the types of those decls (see
  <URL:http://gcc.gnu.org/ml/gcc/2001-07/msg01676.html>), and doing
  this for format and format_arg attributes will require the support
  to be written for the default format and format_arg attributes to be
  added lazily when the relevant decls are created.  (However, once
  this support is done, the fragile use of DECL_ASSEMBLER_NAME in
  format checking can go away, as well as providing a user-demanded
  feature by supporting format attributes on function pointers.)

* Attributes in general, rather than just machine ones, get stored
  with the corresponding decls and types.  DECL_MACHINE_ATTRIBUTES is
  renamed to DECL_ATTRIBUTES.

* Multiple attributes with the same name and different arguments are
  allowed to be applied to the same decl or type.  This is in
  preparation for the handling of format_arg attributes as applying to
  a type rather than a function name or assembler name - multiple
  format_arg attributes is natural for the GNU function ngettext, and
  the latest GNU libc has them; with current GCC this silently falls
  back to considering the last format_arg attribute on a function
  only.

* The various ad hoc cases of some machine attributes only being
  understood in the __-form, or in the non-__ form, are regularised:
  all attributes are understood in both forms after this patch.

There are some points about the existing code I noticed:

* Some code in the c4x back end treats the "naked" attribute as a
  synonym of "interrupt", but c4x_valid_type_attribute_p doesn't
  recognise "naked".

* Various targetm.valid_type_attribute functions check for TYPE_DECL
  and FIELD_DECL - but those tree codes aren't types, and I don't see
  how the functions could ever be called in a case where those codes
  apply.  I've retained the checks, but think they have probably been
  useless all along.

* As discussed in other/1078, which I've sent an update to, many
  target attributes are still undocumented.

Bootstrapped with no regressions on i686-pc-linux-gnu.  In case this
patch counts as a major change, also cross-tested to simulators with
no regressions for powerpc-eabisim and mn10300-elf.  Sanity-checked by
testing it build as far as building cc1 on crosses to alpha-dec-vms,
arc-elf, arm-elf, avr-elf, c4x-elf, h8300-elf, i386-cygwin32,
ia64-elf, m32r-elf, m68hc11-elf, mcore-elf, ns32k-netbsd, sh-elf,
stormy16-elf and v850-elf.  OK to commit?

2001-09-19  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.

cp:
2001-09-19  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.

testsuite:
2001-09-19  Joseph S. Myers  <jsm28@cam.ac.uk>

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

diff -rcpN gcc.orig/Makefile.in gcc/Makefile.in
*** gcc.orig/Makefile.in	Fri Aug 31 19:44:17 2001
--- gcc/Makefile.in	Wed Sep  5 08:12:12 2001
*************** real.o : real.c $(CONFIG_H) $(SYSTEM_H) 
*** 1435,1441 ****
  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)
  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)
--- 1435,1441 ----
  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) $(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 -rcpN gcc.orig/c-common.c gcc/c-common.c
*** gcc.orig/c-common.c	Fri Aug 24 18:20:43 2001
--- gcc/c-common.c	Wed Sep 19 09:55:59 2001
*************** const struct fname_var_t fname_vars[] =
*** 243,252 ****
    {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
--- 243,249 ----
*************** combine_strings (strings)
*** 640,1153 ****
    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;
! {
!   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;
! 
!   sprintf (buf, "__%s__", string);
! 
!   attrtab[attrtab_idx].id = id;
!   attrtab[attrtab_idx].name = get_identifier (buf);
!   attrtab[attrtab_idx].min = min_len;
!   attrtab[attrtab_idx].max = max_len;
!   attrtab[attrtab_idx++].decl_req = decl_req;
! }
  
! /* Initialize attribute table.  */
  
  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);
  }
  
- /* 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).  */
  
  tree
  decl_attributes (node, attributes, flags)
       tree *node, attributes;
!      int flags ATTRIBUTE_UNUSED;
  {
-   tree decl = 0, type = 0;
-   int is_type = 0;
    tree a;
  
!   if (attrtab_idx == 0)
      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);
        int i;
-       enum attrs id;
  
!       for (i = 0; i < attrtab_idx; i++)
! 	if (attrtab[i].name == name)
! 	  break;
! 
!       if (i == attrtab_idx)
! 	{
! 	  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;
  	}
!       else if (attrtab[i].decl_req && decl == 0)
  	{
! 	  warning ("`%s' attribute does not apply to types",
  		   IDENTIFIER_POINTER (name));
  	  continue;
  	}
!       else if (list_length (args) < attrtab[i].min
! 	       || list_length (args) > attrtab[i].max)
  	{
  	  error ("wrong number of arguments specified for `%s' attribute",
  		 IDENTIFIER_POINTER (name));
  	  continue;
  	}
  
!       id = attrtab[i].id;
!       switch (id)
  	{
! 	case A_PACKED:
! 	  if (is_type)
! 	    TYPE_PACKED (type) = 1;
! 	  else if (TREE_CODE (decl) == FIELD_DECL)
! 	    DECL_PACKED (decl) = 1;
! 	  /* We can't set DECL_PACKED for a VAR_DECL, because the bit is
! 	     used for DECL_REGISTER.  It wouldn't mean anything anyway.  */
! 	  else
! 	    warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
! 	  break;
! 
! 	case A_NOCOMMON:
! 	  if (TREE_CODE (decl) == VAR_DECL)
! 	    DECL_COMMON (decl) = 0;
! 	  else
! 	    warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
! 	  break;
! 
! 	case A_COMMON:
! 	  if (TREE_CODE (decl) == VAR_DECL)
! 	    DECL_COMMON (decl) = 1;
! 	  else
! 	    warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
! 	  break;
! 
! 	case A_NORETURN:
! 	  if (TREE_CODE (decl) == FUNCTION_DECL)
! 	    TREE_THIS_VOLATILE (decl) = 1;
! 	  else if (TREE_CODE (type) == POINTER_TYPE
! 		   && TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE)
! 	    TREE_TYPE (decl) = type
! 	      = build_pointer_type
! 		(build_type_variant (TREE_TYPE (type),
! 				     TREE_READONLY (TREE_TYPE (type)), 1));
! 	  else
! 	    warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
! 	  break;
! 
! 	case A_MALLOC:
! 	  if (TREE_CODE (decl) == FUNCTION_DECL)
! 	    DECL_IS_MALLOC (decl) = 1;
! 	  /* ??? TODO: Support types.  */
  	  else
! 	    warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
! 	  break;
  
! 	case A_UNUSED:
! 	  if (is_type)
! 	    if (decl)
! 	      TREE_USED (decl) = 1;
! 	    else
! 	      TREE_USED (type) = 1;
! 	  else if (TREE_CODE (decl) == PARM_DECL
! 		   || TREE_CODE (decl) == VAR_DECL
! 		   || TREE_CODE (decl) == FUNCTION_DECL
! 		   || TREE_CODE (decl) == LABEL_DECL)
! 	    TREE_USED (decl) = 1;
! 	  else
! 	    warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
! 	  break;
  
! 	case A_CONST:
! 	  if (TREE_CODE (decl) == FUNCTION_DECL)
! 	    TREE_READONLY (decl) = 1;
! 	  else if (TREE_CODE (type) == POINTER_TYPE
! 		   && TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE)
! 	    TREE_TYPE (decl) = type
! 	      = build_pointer_type
! 		(build_type_variant (TREE_TYPE (type), 1,
! 				     TREE_THIS_VOLATILE (TREE_TYPE (type))));
! 	  else
! 	    warning ( "`%s' attribute ignored", IDENTIFIER_POINTER (name));
! 	  break;
  
! 	case A_PURE:
! 	  if (TREE_CODE (decl) == FUNCTION_DECL)
! 	    DECL_IS_PURE (decl) = 1;
! 	  /* ??? TODO: Support types.  */
! 	  else
! 	    warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
! 	  break;
  
  
! 	case A_T_UNION:
! 	  if (is_type
! 	      && TREE_CODE (type) == UNION_TYPE
! 	      && (decl == 0
! 		  || (TYPE_FIELDS (type) != 0
! 		      && TYPE_MODE (type) == DECL_MODE (TYPE_FIELDS (type)))))
! 	    TYPE_TRANSPARENT_UNION (type) = 1;
! 	  else if (decl != 0 && TREE_CODE (decl) == PARM_DECL
! 		   && TREE_CODE (type) == UNION_TYPE
! 		   && TYPE_MODE (type) == DECL_MODE (TYPE_FIELDS (type)))
! 	    DECL_TRANSPARENT_UNION (decl) = 1;
  	  else
! 	    warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
! 	  break;
  
! 	case A_CONSTRUCTOR:
! 	  if (TREE_CODE (decl) == FUNCTION_DECL
! 	      && TREE_CODE (type) == FUNCTION_TYPE
! 	      && decl_function_context (decl) == 0)
  	    {
! 	      DECL_STATIC_CONSTRUCTOR (decl) = 1;
! 	      TREE_USED (decl) = 1;
  	    }
- 	  else
- 	    warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
- 	  break;
  
! 	case A_DESTRUCTOR:
! 	  if (TREE_CODE (decl) == FUNCTION_DECL
! 	      && TREE_CODE (type) == FUNCTION_TYPE
! 	      && decl_function_context (decl) == 0)
  	    {
! 	      DECL_STATIC_DESTRUCTOR (decl) = 1;
! 	      TREE_USED (decl) = 1;
  	    }
! 	  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);
  
! 		  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);
! 		}
! 	    }
! 	  break;
  
! 	case A_SECTION:
! 	  if (targetm.have_named_sections)
! 	    {
! 	      if ((TREE_CODE (decl) == FUNCTION_DECL
! 		   || TREE_CODE (decl) == VAR_DECL)
! 		  && TREE_CODE (TREE_VALUE (args)) == STRING_CST)
! 		{
! 		  if (TREE_CODE (decl) == VAR_DECL
! 		      && current_function_decl != NULL_TREE
! 		      && ! TREE_STATIC (decl))
! 		    error_with_decl (decl,
! 				     "section attribute cannot be specified for local variables");
! 		  /* The decl may have already been given a section attribute
! 		     from a previous declaration.  Ensure they match.  */
! 		  else if (DECL_SECTION_NAME (decl) != NULL_TREE
! 			   && strcmp (TREE_STRING_POINTER (DECL_SECTION_NAME (decl)),
! 				      TREE_STRING_POINTER (TREE_VALUE (args))) != 0)
! 		    error_with_decl (*node,
! 				     "section of `%s' conflicts with previous declaration");
! 		  else
! 		    DECL_SECTION_NAME (decl) = TREE_VALUE (args);
! 		}
! 	      else
! 		error_with_decl (*node,
! 				 "section attribute not allowed for `%s'");
! 	    }
! 	  else
! 	    error_with_decl (*node,
! 			     "section attributes are not supported for this target");
! 	  break;
! 
! 	case A_ALIGNED:
! 	  {
! 	    tree align_expr
! 	      = (args ? TREE_VALUE (args)
! 		 : size_int (BIGGEST_ALIGNMENT / BITS_PER_UNIT));
! 	    int i;
! 
! 	    /* Strip any NOPs of any kind.  */
! 	    while (TREE_CODE (align_expr) == NOP_EXPR
! 		   || TREE_CODE (align_expr) == CONVERT_EXPR
! 		   || TREE_CODE (align_expr) == NON_LVALUE_EXPR)
! 	      align_expr = TREE_OPERAND (align_expr, 0);
! 
! 	    if (TREE_CODE (align_expr) != INTEGER_CST)
! 	      {
! 		error ("requested alignment is not a constant");
! 		continue;
! 	      }
! 
! 	    if ((i = tree_log2 (align_expr)) == -1)
! 	      error ("requested alignment is not a power of 2");
! 	    else if (i > HOST_BITS_PER_INT - 2)
! 	      error ("requested alignment is too large");
! 	    else if (is_type)
! 	      {
! 		/* If we have a TYPE_DECL, then copy the type, so that we
! 		   don't accidentally modify a builtin type.  See pushdecl.  */
! 		if (decl && TREE_TYPE (decl) != error_mark_node
! 		    && DECL_ORIGINAL_TYPE (decl) == NULL_TREE)
! 		  {
! 		    tree tt = TREE_TYPE (decl);
! 		    DECL_ORIGINAL_TYPE (decl) = tt;
! 		    tt = build_type_copy (tt);
! 		    TYPE_NAME (tt) = decl;
! 		    TREE_USED (tt) = TREE_USED (decl);
! 		    TREE_TYPE (decl) = tt;
! 		    type = tt;
! 		  }
! 
! 		TYPE_ALIGN (type) = (1 << i) * BITS_PER_UNIT;
! 		TYPE_USER_ALIGN (type) = 1;
! 	      }
! 	    else if (TREE_CODE (decl) != VAR_DECL
! 		     && TREE_CODE (decl) != FIELD_DECL)
! 	      error_with_decl (decl,
! 			       "alignment may not be specified for `%s'");
! 	    else
! 	      {
! 		DECL_ALIGN (decl) = (1 << i) * BITS_PER_UNIT;
! 		DECL_USER_ALIGN (decl) = 1;
! 	      }
! 	  }
! 	  break;
! 
! 	case A_FORMAT:
! 	  decl_handle_format_attribute (decl, args);
! 	  break;
! 
! 	case A_FORMAT_ARG:
! 	  decl_handle_format_arg_attribute (decl, args);
! 	  break;
! 
! 	case A_WEAK:
! 	  declare_weak (decl);
! 	  break;
! 
! 	case A_ALIAS:
! 	  if ((TREE_CODE (decl) == FUNCTION_DECL && DECL_INITIAL (decl))
! 	      || (TREE_CODE (decl) != FUNCTION_DECL && ! DECL_EXTERNAL (decl)))
! 	    error_with_decl (decl,
! 			     "`%s' defined both normally and as an alias");
! 	  else if (decl_function_context (decl) == 0)
! 	    {
! 	      tree id;
  
! 	      id = TREE_VALUE (args);
! 	      if (TREE_CODE (id) != STRING_CST)
! 		{
! 		  error ("alias arg not a string");
! 		  break;
! 		}
! 	      id = get_identifier (TREE_STRING_POINTER (id));
! 	      /* This counts as a use of the object pointed to.  */
! 	      TREE_USED (id) = 1;
  
! 	      if (TREE_CODE (decl) == FUNCTION_DECL)
! 		DECL_INITIAL (decl) = error_mark_node;
! 	      else
! 		DECL_EXTERNAL (decl) = 0;
! 	      assemble_alias (decl, id);
! 	    }
! 	  else
! 	    warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
! 	  break;
  
! 	case A_NO_CHECK_MEMORY_USAGE:
! 	  if (TREE_CODE (decl) != FUNCTION_DECL)
! 	    {
! 	      error_with_decl (decl,
! 			       "`%s' attribute applies only to functions",
! 			       IDENTIFIER_POINTER (name));
! 	    }
! 	  else if (DECL_INITIAL (decl))
! 	    {
! 	      error_with_decl (decl,
! 			       "can't set `%s' attribute after definition",
! 			       IDENTIFIER_POINTER (name));
! 	    }
! 	  else
! 	    DECL_NO_CHECK_MEMORY_USAGE (decl) = 1;
! 	  break;
  
! 	case A_NO_INSTRUMENT_FUNCTION:
! 	  if (TREE_CODE (decl) != FUNCTION_DECL)
! 	    {
! 	      error_with_decl (decl,
! 			       "`%s' attribute applies only to functions",
! 			       IDENTIFIER_POINTER (name));
! 	    }
! 	  else if (DECL_INITIAL (decl))
! 	    {
! 	      error_with_decl (decl,
! 			       "can't set `%s' attribute after definition",
! 			       IDENTIFIER_POINTER (name));
! 	    }
! 	  else
! 	    DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (decl) = 1;
! 	  break;
  
!         case A_NO_LIMIT_STACK:
! 	  if (TREE_CODE (decl) != FUNCTION_DECL)
  	    {
  	      error_with_decl (decl,
! 			       "`%s' attribute applies only to functions",
! 			       IDENTIFIER_POINTER (name));
  	    }
! 	  else if (DECL_INITIAL (decl))
  	    {
! 	      error_with_decl (decl,
! 			       "can't set `%s' attribute after definition",
! 			       IDENTIFIER_POINTER (name));
  	    }
  	  else
! 	    DECL_NO_LIMIT_STACK (decl) = 1;
! 	  break;
  	}
      }
    return NULL_TREE;
  }
  
--- 637,1630 ----
    return value;
  }
  
! /* 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[] =
! {
!   /* { 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 }
! };
  
! /* Default empty table of language attributes.  */
! static const struct attribute_spec default_lang_attribute_table[] =
! {
!   { NULL, 0, 0, false, false, false, NULL }
! };
  
! /* Table of machine-independent attributes for a particular language.  */
! const struct attribute_spec *lang_attribute_table = default_lang_attribute_table;
  
! /* Initialize attribute tables, and make some sanity checks
!    if --enable-checking.  */
  
  static void
  init_attributes ()
  {
! #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;
  }
  
  /* 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
!    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;
  {
    tree a;
+   tree returned_attrs = NULL_TREE;
  
!   if (!attributes_initialized)
      init_attributes ();
  
    (*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;
  
!       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++)
! 	    {
! 	      if (is_attribute_p (attribute_tables[i][j].name, name))
! 		{
! 		  spec = &attribute_tables[i][j];
! 		  break;
! 		}
! 	    }
! 	  if (spec != NULL)
! 	    break;
  	}
! 
!       if (spec == NULL)
  	{
! 	  warning ("`%s' attribute directive ignored",
  		   IDENTIFIER_POINTER (name));
  	  continue;
  	}
!       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;
  	}
  
!       if (spec->decl_required && !DECL_P (*anode))
  	{
! 	  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 does not apply to types",
! 		       IDENTIFIER_POINTER (name));
! 	      continue;
! 	    }
! 	}
  
!       if (spec->type_required && DECL_P (*anode))
! 	{
! 	  anode = &TREE_TYPE (*anode);
! 	}
  
!       if (spec->function_type_required && TREE_CODE (*anode) != FUNCTION_TYPE
! 	  && TREE_CODE (*anode) != METHOD_TYPE)
! 	{
! 	  if (TREE_CODE (*anode) == POINTER_TYPE
! 	      && (TREE_CODE (TREE_TYPE (*anode)) == FUNCTION_TYPE
! 		  || TREE_CODE (TREE_TYPE (*anode)) == METHOD_TYPE))
! 	    {
! 	      if (!(flags & (int) ATTR_FLAG_TYPE_IN_PLACE))
! 		*anode = build_type_copy (*anode);
! 	      anode = &TREE_TYPE (*anode);
! 	    }
! 	  else if (flags & (int) ATTR_FLAG_FUNCTION_NEXT)
! 	    {
! 	      /* Pass on this attribute to be tried again.  */
! 	      returned_attrs = tree_cons (name, args, returned_attrs);
! 	      continue;
! 	    }
  
! 	  if (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;
  
! 	  if (DECL_P (*anode))
! 	    old_attrs = DECL_ATTRIBUTES (*anode);
  	  else
! 	    old_attrs = TYPE_ATTRIBUTES (*anode);
  
! 	  for (a = lookup_attribute (spec->name, old_attrs);
! 	       a != NULL_TREE;
! 	       a = lookup_attribute (spec->name, TREE_CHAIN (a)))
  	    {
! 	      if (simple_cst_equal (TREE_VALUE (a), args) == 1)
! 		break;
  	    }
  
! 	  if (a == NULL_TREE)
  	    {
! 	      /* This attribute isn't already in the list.  */
! 	      if (DECL_P (*anode))
! 		DECL_ATTRIBUTES (*anode) = tree_cons (name, args, old_attrs);
! 	      else if (flags & (int) ATTR_FLAG_TYPE_IN_PLACE)
! 		TYPE_ATTRIBUTES (*anode) = tree_cons (name, args, old_attrs);
! 	      else
! 		*anode = build_type_attribute_variant (*anode,
! 						       tree_cons (name, args,
! 								  old_attrs));
  	    }
! 	}
!     }
  
!   return returned_attrs;
! }
  
! /* Handle a "packed" attribute; arguments as in
!    struct attribute_spec.handler.  */
! static tree
! handle_packed_attribute (node, name, args, flags, no_add_attrs)
!      tree *node;
!      tree name;
!      tree args ATTRIBUTE_UNUSED;
!      int flags;
!      bool *no_add_attrs;
! {
!   tree *type = NULL;
!   if (DECL_P (*node))
!     {
!       if (TREE_CODE (*node) == TYPE_DECL)
! 	type = &TREE_TYPE (*node);
!     }
!   else
!     type = node;
!   if (type)
!     {
!       if (!(flags & (int) ATTR_FLAG_TYPE_IN_PLACE))
! 	*type = build_type_copy (*type);
!       TYPE_PACKED (*type) = 1;
!     }
!   else if (TREE_CODE (*node) == FIELD_DECL)
!     DECL_PACKED (*node) = 1;
!   /* We can't set DECL_PACKED for a VAR_DECL, because the bit is
!      used for DECL_REGISTER.  It wouldn't mean anything anyway.  */
!   else
!     {
!       warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
!       *no_add_attrs = true;
!     }
  
!   return NULL_TREE;
! }
  
! /* Handle a "nocommon" attribute; arguments as in
!    struct attribute_spec.handler.  */
! static tree
! handle_nocommon_attribute (node, name, args, flags, no_add_attrs)
!      tree *node;
!      tree name;
!      tree args ATTRIBUTE_UNUSED;
!      int flags ATTRIBUTE_UNUSED;
!      bool *no_add_attrs;
! {
!   if (TREE_CODE (*node) == VAR_DECL)
!     DECL_COMMON (*node) = 0;
!   else
!     {
!       warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
!       *no_add_attrs = true;
!     }
  
!   return NULL_TREE;
! }
  
! /* Handle a "common" attribute; arguments as in
!    struct attribute_spec.handler.  */
! static tree
! handle_common_attribute (node, name, args, flags, no_add_attrs)
!      tree *node;
!      tree name;
!      tree args ATTRIBUTE_UNUSED;
!      int flags ATTRIBUTE_UNUSED;
!      bool *no_add_attrs;
! {
!   if (TREE_CODE (*node) == VAR_DECL)
!     DECL_COMMON (*node) = 1;
!   else
!     {
!       warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
!       *no_add_attrs = true;
!     }
  
!   return NULL_TREE;
! }
  
! /* Handle a "noreturn" attribute; arguments as in
!    struct attribute_spec.handler.  */
! static tree
! handle_noreturn_attribute (node, name, args, flags, no_add_attrs)
!      tree *node;
!      tree name;
!      tree args ATTRIBUTE_UNUSED;
!      int flags ATTRIBUTE_UNUSED;
!      bool *no_add_attrs;
! {
!   tree type = TREE_TYPE (*node);
  
!   /* See FIXME comment in c_common_attribute_table.  */
!   if (TREE_CODE (*node) == FUNCTION_DECL)
!     TREE_THIS_VOLATILE (*node) = 1;
!   else if (TREE_CODE (type) == POINTER_TYPE
! 	   && TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE)
!     TREE_TYPE (*node)
!       = build_pointer_type (build_type_variant (TREE_TYPE (type),
! 						TREE_READONLY (TREE_TYPE (type)), 1));
!   else
!     {
!       warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
!       *no_add_attrs = true;
!     }
! 
!   return NULL_TREE;
! }
! 
! /* Handle a "unused" attribute; arguments as in
!    struct attribute_spec.handler.  */
! static tree
! handle_unused_attribute (node, name, args, flags, no_add_attrs)
!      tree *node;
!      tree name;
!      tree args ATTRIBUTE_UNUSED;
!      int flags;
!      bool *no_add_attrs;
! {
!   if (DECL_P (*node))
!     {
!       tree decl = *node;
! 
!       if (TREE_CODE (decl) == PARM_DECL
! 	  || TREE_CODE (decl) == VAR_DECL
! 	  || TREE_CODE (decl) == FUNCTION_DECL
! 	  || TREE_CODE (decl) == LABEL_DECL
! 	  || TREE_CODE (decl) == TYPE_DECL)
! 	TREE_USED (decl) = 1;
!       else
! 	{
! 	  warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
! 	  *no_add_attrs = true;
! 	}
!     }
!   else
!     {
!       if (!(flags & (int) ATTR_FLAG_TYPE_IN_PLACE))
! 	*node = build_type_copy (*node);
!       TREE_USED (*node) = 1;
!     }
! 
!   return NULL_TREE;
! }
! 
! /* Handle a "const" attribute; arguments as in
!    struct attribute_spec.handler.  */
! static tree
! handle_const_attribute (node, name, args, flags, no_add_attrs)
!      tree *node;
!      tree name;
!      tree args ATTRIBUTE_UNUSED;
!      int flags ATTRIBUTE_UNUSED;
!      bool *no_add_attrs;
! {
!   tree type = TREE_TYPE (*node);
! 
!   /* See FIXME comment on noreturn in c_common_attribute_table.  */
!   if (TREE_CODE (*node) == FUNCTION_DECL)
!     TREE_READONLY (*node) = 1;
!   else if (TREE_CODE (type) == POINTER_TYPE
! 	   && TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE)
!     TREE_TYPE (*node)
!       = build_pointer_type (build_type_variant (TREE_TYPE (type), 1,
! 						TREE_THIS_VOLATILE (TREE_TYPE (type))));
!   else
!     {
!       warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
!       *no_add_attrs = true;
!     }
  
!   return NULL_TREE;
! }
! 
! /* Handle a "transparent_union" attribute; arguments as in
!    struct attribute_spec.handler.  */
! static tree
! handle_transparent_union_attribute (node, name, args, flags, no_add_attrs)
!      tree *node;
!      tree name;
!      tree args ATTRIBUTE_UNUSED;
!      int flags;
!      bool *no_add_attrs;
! {
!   tree decl = NULL_TREE;
!   tree *type = NULL;
!   int is_type = 0;
! 
!   if (DECL_P (*node))
!     {
!       decl = *node;
!       type = &TREE_TYPE (decl);
!       is_type = TREE_CODE (*node) == TYPE_DECL;
!     }
!   else if (TYPE_P (*node))
!     type = node, is_type = 1;
! 
!   if (is_type
!       && TREE_CODE (*type) == UNION_TYPE
!       && (decl == 0
! 	  || (TYPE_FIELDS (*type) != 0
! 	      && TYPE_MODE (*type) == DECL_MODE (TYPE_FIELDS (*type)))))
!     {
!       if (!(flags & (int) ATTR_FLAG_TYPE_IN_PLACE))
! 	*type = build_type_copy (*type);
!       TYPE_TRANSPARENT_UNION (*type) = 1;
!     }
!   else if (decl != 0 && TREE_CODE (decl) == PARM_DECL
! 	   && TREE_CODE (*type) == UNION_TYPE
! 	   && TYPE_MODE (*type) == DECL_MODE (TYPE_FIELDS (*type)))
!     DECL_TRANSPARENT_UNION (decl) = 1;
!   else
!     {
!       warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
!       *no_add_attrs = true;
!     }
! 
!   return NULL_TREE;
! }
! 
! /* Handle a "constructor" attribute; arguments as in
!    struct attribute_spec.handler.  */
! static tree
! handle_constructor_attribute (node, name, args, flags, no_add_attrs)
!      tree *node;
!      tree name;
!      tree args ATTRIBUTE_UNUSED;
!      int flags ATTRIBUTE_UNUSED;
!      bool *no_add_attrs;
! {
!   tree decl = *node;
!   tree type = TREE_TYPE (decl);
! 
!   if (TREE_CODE (decl) == FUNCTION_DECL
!       && TREE_CODE (type) == FUNCTION_TYPE
!       && decl_function_context (decl) == 0)
!     {
!       DECL_STATIC_CONSTRUCTOR (decl) = 1;
!       TREE_USED (decl) = 1;
!     }
!   else
!     {
!       warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
!       *no_add_attrs = true;
!     }
! 
!   return NULL_TREE;
! }
! 
! /* Handle a "destructor" attribute; arguments as in
!    struct attribute_spec.handler.  */
! static tree
! handle_destructor_attribute (node, name, args, flags, no_add_attrs)
!      tree *node;
!      tree name;
!      tree args ATTRIBUTE_UNUSED;
!      int flags ATTRIBUTE_UNUSED;
!      bool *no_add_attrs;
! {
!   tree decl = *node;
!   tree type = TREE_TYPE (decl);
! 
!   if (TREE_CODE (decl) == FUNCTION_DECL
!       && TREE_CODE (type) == FUNCTION_TYPE
!       && decl_function_context (decl) == 0)
!     {
!       DECL_STATIC_DESTRUCTOR (decl) = 1;
!       TREE_USED (decl) = 1;
!     }
!   else
!     {
!       warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
!       *no_add_attrs = true;
!     }
! 
!   return NULL_TREE;
! }
! 
! /* Handle a "mode" attribute; arguments as in
!    struct attribute_spec.handler.  */
! static tree
! handle_mode_attribute (node, name, args, flags, no_add_attrs)
!      tree *node;
!      tree name;
!      tree args;
!      int flags ATTRIBUTE_UNUSED;
!      bool *no_add_attrs;
! {
!   tree decl = *node;
!   tree type = TREE_TYPE (decl);
! 
!   *no_add_attrs = true;
! 
!   if (TREE_CODE (TREE_VALUE (args)) != IDENTIFIER_NODE)
!     warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
!   else
!     {
!       int j;
!       const char *p = IDENTIFIER_POINTER (TREE_VALUE (args));
!       int len = strlen (p);
!       enum machine_mode mode = VOIDmode;
!       tree typefm;
! 
!       if (len > 4 && p[0] == '_' && p[1] == '_'
! 	  && p[len - 1] == '_' && p[len - 2] == '_')
! 	{
! 	  char *newp = (char *) alloca (len - 1);
! 
! 	  strcpy (newp, &p[2]);
! 	  newp[len - 4] = '\0';
! 	  p = newp;
! 	}
! 
!       /* Give this decl a type with the specified mode.
! 	 First check for the special modes.  */
!       if (! strcmp (p, "byte"))
! 	mode = byte_mode;
!       else if (!strcmp (p, "word"))
! 	mode = word_mode;
!       else if (! strcmp (p, "pointer"))
! 	mode = ptr_mode;
!       else
! 	for (j = 0; j < NUM_MACHINE_MODES; j++)
! 	  if (!strcmp (p, GET_MODE_NAME (j)))
! 	    mode = (enum machine_mode) j;
! 
!       if (mode == VOIDmode)
! 	error ("unknown machine mode `%s'", p);
!       else if (0 == (typefm = type_for_mode (mode,
! 					     TREE_UNSIGNED (type))))
! 	error ("no data type for mode `%s'", p);
!       else
! 	{
! 	  if (TYPE_PRECISION (typefm) > (TREE_UNSIGNED (type)
! 					 ? TYPE_PRECISION(uintmax_type_node)
! 					 : TYPE_PRECISION(intmax_type_node))
! 	      && pedantic)
! 	    pedwarn ("type with more precision than %s",
! 		     TREE_UNSIGNED (type) ? "uintmax_t" : "intmax_t");
! 	  TREE_TYPE (decl) = type = typefm;
! 	  DECL_SIZE (decl) = DECL_SIZE_UNIT (decl) = 0;
! 	  if (TREE_CODE (decl) != FIELD_DECL)
! 	    layout_decl (decl, 0);
! 	}
!     }
! 
!   return NULL_TREE;
! }
! 
! /* Handle a "section" attribute; arguments as in
!    struct attribute_spec.handler.  */
! static tree
! handle_section_attribute (node, name, args, flags, no_add_attrs)
!      tree *node;
!      tree name ATTRIBUTE_UNUSED;
!      tree args;
!      int flags ATTRIBUTE_UNUSED;
!      bool *no_add_attrs;
! {
!   tree decl = *node;
! 
!   if (targetm.have_named_sections)
!     {
!       if ((TREE_CODE (decl) == FUNCTION_DECL
! 	   || TREE_CODE (decl) == VAR_DECL)
! 	  && TREE_CODE (TREE_VALUE (args)) == STRING_CST)
! 	{
! 	  if (TREE_CODE (decl) == VAR_DECL
! 	      && current_function_decl != NULL_TREE
! 	      && ! TREE_STATIC (decl))
  	    {
  	      error_with_decl (decl,
! 			       "section attribute cannot be specified for local variables");
! 	      *no_add_attrs = true;
  	    }
! 	  /* The decl may have already been given a section attribute
! 	     from a previous declaration.  Ensure they match.  */
! 	  else if (DECL_SECTION_NAME (decl) != NULL_TREE
! 		   && strcmp (TREE_STRING_POINTER (DECL_SECTION_NAME (decl)),
! 			      TREE_STRING_POINTER (TREE_VALUE (args))) != 0)
  	    {
! 	      error_with_decl (*node,
! 			       "section of `%s' conflicts with previous declaration");
! 	      *no_add_attrs = true;
  	    }
  	  else
! 	    DECL_SECTION_NAME (decl) = TREE_VALUE (args);
! 	}
!       else
! 	{
! 	  error_with_decl (*node,
! 			   "section attribute not allowed for `%s'");
! 	  *no_add_attrs = true;
! 	}
!     }
!   else
!     {
!       error_with_decl (*node,
! 		       "section attributes are not supported for this target");
!       *no_add_attrs = true;
!     }
! 
!   return NULL_TREE;
! }
! 
! /* Handle a "aligned" attribute; arguments as in
!    struct attribute_spec.handler.  */
! static tree
! handle_aligned_attribute (node, name, args, flags, no_add_attrs)
!      tree *node;
!      tree name ATTRIBUTE_UNUSED;
!      tree args;
!      int flags;
!      bool *no_add_attrs;
! {
!   tree decl = NULL_TREE;
!   tree *type = NULL;
!   int is_type = 0;
!   tree align_expr = (args ? TREE_VALUE (args)
! 		     : size_int (BIGGEST_ALIGNMENT / BITS_PER_UNIT));
!   int i;
! 
!   if (DECL_P (*node))
!     {
!       decl = *node;
!       type = &TREE_TYPE (decl);
!       is_type = TREE_CODE (*node) == TYPE_DECL;
!     }
!   else if (TYPE_P (*node))
!     type = node, is_type = 1;
! 
!   /* Strip any NOPs of any kind.  */
!   while (TREE_CODE (align_expr) == NOP_EXPR
! 	 || TREE_CODE (align_expr) == CONVERT_EXPR
! 	 || TREE_CODE (align_expr) == NON_LVALUE_EXPR)
!     align_expr = TREE_OPERAND (align_expr, 0);
! 
!   if (TREE_CODE (align_expr) != INTEGER_CST)
!     {
!       error ("requested alignment is not a constant");
!       *no_add_attrs = true;
!     }
!   else if ((i = tree_log2 (align_expr)) == -1)
!     {
!       error ("requested alignment is not a power of 2");
!       *no_add_attrs = true;
!     }
!   else if (i > HOST_BITS_PER_INT - 2)
!     {
!       error ("requested alignment is too large");
!       *no_add_attrs = true;
!     }
!   else if (is_type)
!     {
!       /* If we have a TYPE_DECL, then copy the type, so that we
! 	 don't accidentally modify a builtin type.  See pushdecl.  */
!       if (decl && TREE_TYPE (decl) != error_mark_node
! 	  && DECL_ORIGINAL_TYPE (decl) == NULL_TREE)
! 	{
! 	  tree tt = TREE_TYPE (decl);
! 	  *type = build_type_copy (*type);
! 	  DECL_ORIGINAL_TYPE (decl) = tt;
! 	  TYPE_NAME (*type) = decl;
! 	  TREE_USED (*type) = TREE_USED (decl);
! 	  TREE_TYPE (decl) = *type;
! 	}
!       else if (!(flags & (int) ATTR_FLAG_TYPE_IN_PLACE))
! 	*type = build_type_copy (*type);
! 
!       TYPE_ALIGN (*type) = (1 << i) * BITS_PER_UNIT;
!       TYPE_USER_ALIGN (*type) = 1;
!     }
!   else if (TREE_CODE (decl) != VAR_DECL
! 	   && TREE_CODE (decl) != FIELD_DECL)
!     {
!       error_with_decl (decl,
! 		       "alignment may not be specified for `%s'");
!       *no_add_attrs = true;
!     }
!   else
!     {
!       DECL_ALIGN (decl) = (1 << i) * BITS_PER_UNIT;
!       DECL_USER_ALIGN (decl) = 1;
!     }
! 
!   return NULL_TREE;
! }
! 
! /* Handle a "weak" attribute; arguments as in
!    struct attribute_spec.handler.  */
! static tree
! handle_weak_attribute (node, name, args, flags, no_add_attrs)
!      tree *node;
!      tree name ATTRIBUTE_UNUSED;
!      tree args ATTRIBUTE_UNUSED;
!      int flags ATTRIBUTE_UNUSED;
!      bool *no_add_attrs ATTRIBUTE_UNUSED;
! {
!   declare_weak (*node);
! 
!   return NULL_TREE;
! }
! 
! /* Handle an "alias" attribute; arguments as in
!    struct attribute_spec.handler.  */
! static tree
! handle_alias_attribute (node, name, args, flags, no_add_attrs)
!      tree *node;
!      tree name;
!      tree args;
!      int flags ATTRIBUTE_UNUSED;
!      bool *no_add_attrs;
! {
!   tree decl = *node;
! 
!   if ((TREE_CODE (decl) == FUNCTION_DECL && DECL_INITIAL (decl))
!       || (TREE_CODE (decl) != FUNCTION_DECL && ! DECL_EXTERNAL (decl)))
!     {
!       error_with_decl (decl,
! 		       "`%s' defined both normally and as an alias");
!       *no_add_attrs = true;
!     }
!   else if (decl_function_context (decl) == 0)
!     {
!       tree id;
! 
!       id = TREE_VALUE (args);
!       if (TREE_CODE (id) != STRING_CST)
! 	{
! 	  error ("alias arg not a string");
! 	  *no_add_attrs = true;
! 	  return NULL_TREE;
  	}
+       id = get_identifier (TREE_STRING_POINTER (id));
+       /* This counts as a use of the object pointed to.  */
+       TREE_USED (id) = 1;
+ 
+       if (TREE_CODE (decl) == FUNCTION_DECL)
+ 	DECL_INITIAL (decl) = error_mark_node;
+       else
+ 	DECL_EXTERNAL (decl) = 0;
+       assemble_alias (decl, id);
+     }
+   else
+     {
+       warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
+       *no_add_attrs = true;
+     }
+ 
+   return NULL_TREE;
+ }
+ 
+ /* Handle a "no_instrument_function" attribute; arguments as in
+    struct attribute_spec.handler.  */
+ static tree
+ handle_no_instrument_function_attribute (node, name, args, flags, no_add_attrs)
+      tree *node;
+      tree name;
+      tree args ATTRIBUTE_UNUSED;
+      int flags ATTRIBUTE_UNUSED;
+      bool *no_add_attrs;
+ {
+   tree decl = *node;
+ 
+   if (TREE_CODE (decl) != FUNCTION_DECL)
+     {
+       error_with_decl (decl,
+ 		       "`%s' attribute applies only to functions",
+ 		       IDENTIFIER_POINTER (name));
+       *no_add_attrs = true;
      }
+   else if (DECL_INITIAL (decl))
+     {
+       error_with_decl (decl,
+ 		       "can't set `%s' attribute after definition",
+ 		       IDENTIFIER_POINTER (name));
+       *no_add_attrs = true;
+     }
+   else
+     DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (decl) = 1;
+ 
+   return NULL_TREE;
+ }
+ 
+ /* Handle a "no_check_memory_usage" attribute; arguments as in
+    struct attribute_spec.handler.  */
+ static tree
+ handle_no_check_memory_usage_attribute (node, name, args, flags, no_add_attrs)
+      tree *node;
+      tree name;
+      tree args ATTRIBUTE_UNUSED;
+      int flags ATTRIBUTE_UNUSED;
+      bool *no_add_attrs;
+ {
+   tree decl = *node;
+ 
+   if (TREE_CODE (decl) != FUNCTION_DECL)
+     {
+       error_with_decl (decl,
+ 		       "`%s' attribute applies only to functions",
+ 		       IDENTIFIER_POINTER (name));
+       *no_add_attrs = true;
+     }
+   else if (DECL_INITIAL (decl))
+     {
+       error_with_decl (decl,
+ 		       "can't set `%s' attribute after definition",
+ 		       IDENTIFIER_POINTER (name));
+       *no_add_attrs = true;
+     }
+   else
+     DECL_NO_CHECK_MEMORY_USAGE (decl) = 1;
+ 
+   return NULL_TREE;
+ }
+ 
+ /* Handle a "malloc" attribute; arguments as in
+    struct attribute_spec.handler.  */
+ static tree
+ handle_malloc_attribute (node, name, args, flags, no_add_attrs)
+      tree *node;
+      tree name;
+      tree args ATTRIBUTE_UNUSED;
+      int flags ATTRIBUTE_UNUSED;
+      bool *no_add_attrs;
+ {
+   if (TREE_CODE (*node) == FUNCTION_DECL)
+     DECL_IS_MALLOC (*node) = 1;
+   /* ??? TODO: Support types.  */
+   else
+     {
+       warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
+       *no_add_attrs = true;
+     }
+ 
+   return NULL_TREE;
+ }
+ 
+ /* Handle a "no_limit_stack" attribute; arguments as in
+    struct attribute_spec.handler.  */
+ static tree
+ handle_no_limit_stack_attribute (node, name, args, flags, no_add_attrs)
+      tree *node;
+      tree name;
+      tree args ATTRIBUTE_UNUSED;
+      int flags ATTRIBUTE_UNUSED;
+      bool *no_add_attrs;
+ {
+   tree decl = *node;
+ 
+   if (TREE_CODE (decl) != FUNCTION_DECL)
+     {
+       error_with_decl (decl,
+ 		       "`%s' attribute applies only to functions",
+ 		       IDENTIFIER_POINTER (name));
+       *no_add_attrs = true;
+     }
+   else if (DECL_INITIAL (decl))
+     {
+       error_with_decl (decl,
+ 		       "can't set `%s' attribute after definition",
+ 		       IDENTIFIER_POINTER (name));
+       *no_add_attrs = true;
+     }
+   else
+     DECL_NO_LIMIT_STACK (decl) = 1;
+ 
+   return NULL_TREE;
+ }
+ 
+ /* Handle a "pure" attribute; arguments as in
+    struct attribute_spec.handler.  */
+ static tree
+ handle_pure_attribute (node, name, args, flags, no_add_attrs)
+      tree *node;
+      tree name;
+      tree args ATTRIBUTE_UNUSED;
+      int flags ATTRIBUTE_UNUSED;
+      bool *no_add_attrs;
+ {
+   if (TREE_CODE (*node) == FUNCTION_DECL)
+     DECL_IS_PURE (*node) = 1;
+   /* ??? TODO: Support types.  */
+   else
+     {
+       warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
+       *no_add_attrs = true;
+     }
+ 
    return NULL_TREE;
  }
  
diff -rcpN gcc.orig/c-common.h gcc/c-common.h
*** gcc.orig/c-common.h	Wed Sep  5 07:47:51 2001
--- gcc/c-common.h	Wed Sep  5 08:12:12 2001
*************** extern const char *fname_as_string		PARA
*** 503,531 ****
  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 void c_apply_type_quals_to_decl		PARAMS ((int, tree));
  extern tree c_sizeof				PARAMS ((tree));
  extern tree c_alignof				PARAMS ((tree));
--- 503,516 ----
  extern tree fname_decl				PARAMS ((unsigned, tree));
  extern const char *fname_string			PARAMS ((unsigned));
  
  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 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 -rcpN gcc.orig/c-decl.c gcc/c-decl.c
*** gcc.orig/c-decl.c	Fri Aug 31 19:44:17 2001
--- gcc/c-decl.c	Tue Sep 18 15:14:57 2001
*************** duplicate_decls (newdecl, olddecl, diffe
*** 1404,1410 ****
    int errmsg = 0;
  
    if (DECL_P (olddecl))
!     DECL_MACHINE_ATTRIBUTES (newdecl)
        = (*targetm.merge_decl_attributes) (olddecl, newdecl);
  
    if (TREE_CODE (newtype) == ERROR_MARK
--- 1404,1410 ----
    int errmsg = 0;
  
    if (DECL_P (olddecl))
!     DECL_ATTRIBUTES (newdecl)
        = (*targetm.merge_decl_attributes) (olddecl, newdecl);
  
    if (TREE_CODE (newtype) == ERROR_MARK
*************** duplicate_decls (newdecl, olddecl, diffe
*** 2030,2036 ****
  
    /* NEWDECL contains the merged attribute lists.
       Update OLDDECL to be the same.  */
!   DECL_MACHINE_ATTRIBUTES (olddecl) = DECL_MACHINE_ATTRIBUTES (newdecl);
  
    return 1;
  }
--- 2030,2036 ----
  
    /* NEWDECL contains the merged attribute lists.
       Update OLDDECL to be the same.  */
!   DECL_ATTRIBUTES (olddecl) = DECL_ATTRIBUTES (newdecl);
  
    return 1;
  }
*************** grokdeclarator (declarator, declspecs, d
*** 3872,3880 ****
    enum tree_code innermost_code = ERROR_MARK;
    int bitfield = 0;
    int size_varies = 0;
!   tree decl_machine_attr = NULL_TREE;
    tree array_ptr_quals = NULL_TREE;
    int array_parm_static = 0;
  
    if (decl_context == BITFIELD)
      bitfield = 1, decl_context = FIELD;
--- 3872,3881 ----
    enum tree_code innermost_code = ERROR_MARK;
    int bitfield = 0;
    int size_varies = 0;
!   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;
*************** grokdeclarator (declarator, declspecs, d
*** 3898,3903 ****
--- 3899,3908 ----
  	  decl = TREE_OPERAND (decl, 0);
  	  break;
  
+ 	case TREE_LIST:
+ 	  decl = TREE_VALUE (decl);
+ 	  break;
+ 
  	case IDENTIFIER_NODE:
  	  name = IDENTIFIER_POINTER (decl);
  	  decl = 0;
*************** grokdeclarator (declarator, declspecs, d
*** 3979,3985 ****
        else if (TREE_CODE (id) == TYPE_DECL)
  	{
  	  type = TREE_TYPE (id);
! 	  decl_machine_attr = DECL_MACHINE_ATTRIBUTES (id);
  	  typedef_decl = id;
  	}
        /* Built-in types come as identifiers.  */
--- 3984,3990 ----
        else if (TREE_CODE (id) == TYPE_DECL)
  	{
  	  type = TREE_TYPE (id);
! 	  decl_attr = DECL_ATTRIBUTES (id);
  	  typedef_decl = id;
  	}
        /* Built-in types come as identifiers.  */
*************** grokdeclarator (declarator, declspecs, d
*** 4292,4297 ****
--- 4297,4303 ----
        /* 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).
*************** grokdeclarator (declarator, declspecs, d
*** 4313,4319 ****
  	  array_parm_static = 0;
  	}
  
!       if (TREE_CODE (declarator) == ARRAY_REF)
  	{
  	  register tree itype = NULL_TREE;
  	  register tree size = TREE_OPERAND (declarator, 1);
--- 4319,4348 ----
  	  array_parm_static = 0;
  	}
  
!       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);
*************** grokdeclarator (declarator, declspecs, d
*** 4657,4662 ****
--- 4686,4692 ----
        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;
      }
  
*************** grokdeclarator (declarator, declspecs, d
*** 4687,4692 ****
--- 4717,4723 ----
  	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;
      }
  
*************** grokdeclarator (declarator, declspecs, d
*** 4711,4717 ****
       or a FUNCTION_DECL, depending on DECL_CONTEXT and TYPE.  */
  
    {
!     register tree decl;
  
      if (decl_context == PARM)
        {
--- 4742,4748 ----
       or a FUNCTION_DECL, depending on DECL_CONTEXT and TYPE.  */
  
    {
!     tree decl;
  
      if (decl_context == PARM)
        {
*************** grokdeclarator (declarator, declspecs, d
*** 4860,4866 ****
  	  pedwarn ("invalid storage class for function `%s'", name);
  
  	decl = build_decl (FUNCTION_DECL, declarator, type);
! 	decl = build_decl_attribute_variant (decl, decl_machine_attr);
  
  	if (pedantic && type_quals && ! DECL_IN_SYSTEM_HEADER (decl))
  	  pedwarn ("ISO C forbids qualified function types");
--- 4891,4897 ----
  	  pedwarn ("invalid storage class for function `%s'", name);
  
  	decl = build_decl (FUNCTION_DECL, declarator, type);
! 	decl = build_decl_attribute_variant (decl, decl_attr);
  
  	if (pedantic && type_quals && ! DECL_IN_SYSTEM_HEADER (decl))
  	  pedwarn ("ISO C forbids qualified function types");
*************** grokdeclarator (declarator, declspecs, d
*** 4953,4958 ****
--- 4984,4991 ----
      if (C_TYPE_FIELDS_VOLATILE (TREE_TYPE (decl)))
        mark_addressable (decl);
  
+     decl_attributes (&decl, returned_attrs, 0);
+ 
      return decl;
    }
  }
*************** finish_struct (t, fieldlist, attributes)
*** 5341,5347 ****
  
    TYPE_SIZE (t) = 0;
  
!   decl_attributes (&t, attributes, 0);
  
    /* Nameless union parm types are useful as GCC extension.  */
    if (! (TREE_CODE (t) == UNION_TYPE && TYPE_NAME (t) == 0) && !pedantic)
--- 5374,5380 ----
  
    TYPE_SIZE (t) = 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)
*************** finish_enum (enumtype, values, attribute
*** 5705,5711 ****
    if (in_parm_level_p ())
      warning ("enum defined inside parms");
  
!   decl_attributes (&enumtype, attributes, 0);
  
    /* Calculate the maximum value of any enumerator in this type.  */
  
--- 5738,5744 ----
    if (in_parm_level_p ())
      warning ("enum defined inside parms");
  
!   decl_attributes (&enumtype, attributes, (int) ATTR_FLAG_TYPE_IN_PLACE);
  
    /* Calculate the maximum value of any enumerator in this type.  */
  
diff -rcpN gcc.orig/c-format.c gcc/c-format.c
*** gcc.orig/c-format.c	Mon Aug 27 07:45:05 2001
--- gcc/c-format.c	Wed Sep  5 08:12:12 2001
*************** static void record_function_format	PARAM
*** 82,95 ****
  						 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;
  {
    tree type = TREE_TYPE (decl);
    tree format_type_id = TREE_VALUE (args);
    tree format_num_expr = TREE_VALUE (TREE_CHAIN (args));
--- 82,98 ----
  						 int, int));
  static void record_international_format	PARAMS ((tree, tree, int));
  
! /* 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));
*************** decl_handle_format_attribute (decl, args
*** 104,116 ****
      {
        error_with_decl (decl,
  		       "argument format specified for non-function `%s'");
!       return;
      }
  
    if (TREE_CODE (format_type_id) != IDENTIFIER_NODE)
      {
        error ("unrecognized format specifier");
!       return;
      }
    else
      {
--- 107,121 ----
      {
        error_with_decl (decl,
  		       "argument format specified for non-function `%s'");
!       *no_add_attrs = true;
!       return NULL_TREE;
      }
  
    if (TREE_CODE (format_type_id) != IDENTIFIER_NODE)
      {
        error ("unrecognized format specifier");
!       *no_add_attrs = true;
!       return NULL_TREE;
      }
    else
      {
*************** decl_handle_format_attribute (decl, args
*** 121,127 ****
        if (format_type == format_type_error)
  	{
  	  warning ("`%s' is an unrecognized format function type", p);
! 	  return;
  	}
      }
  
--- 126,133 ----
        if (format_type == format_type_error)
  	{
  	  warning ("`%s' is an unrecognized format function type", p);
! 	  *no_add_attrs = true;
! 	  return NULL_TREE;
  	}
      }
  
*************** decl_handle_format_attribute (decl, args
*** 143,149 ****
        || TREE_INT_CST_HIGH (first_arg_num_expr) != 0)
      {
        error ("format string has invalid operand number");
!       return;
      }
  
    format_num = TREE_INT_CST_LOW (format_num_expr);
--- 149,156 ----
        || TREE_INT_CST_HIGH (first_arg_num_expr) != 0)
      {
        error ("format string has invalid operand number");
!       *no_add_attrs = true;
!       return NULL_TREE;
      }
  
    format_num = TREE_INT_CST_LOW (format_num_expr);
*************** decl_handle_format_attribute (decl, args
*** 151,157 ****
    if (first_arg_num != 0 && first_arg_num <= format_num)
      {
        error ("format string arg follows the args to be formatted");
!       return;
      }
  
    /* If a parameter list is specified, verify that the format_num
--- 158,165 ----
    if (first_arg_num != 0 && first_arg_num <= format_num)
      {
        error ("format string arg follows the args to be formatted");
!       *no_add_attrs = true;
!       return NULL_TREE;
      }
  
    /* If a parameter list is specified, verify that the format_num
*************** decl_handle_format_attribute (decl, args
*** 170,176 ****
  	      != char_type_node))
  	{
  	  error ("format string arg not a string type");
! 	  return;
  	}
  
        else if (first_arg_num != 0)
--- 178,185 ----
  	      != char_type_node))
  	{
  	  error ("format string arg not a string type");
! 	  *no_add_attrs = true;
! 	  return NULL_TREE;
  	}
  
        else if (first_arg_num != 0)
*************** decl_handle_format_attribute (decl, args
*** 183,189 ****
  	  if (arg_num != first_arg_num)
  	    {
  	      error ("args to be formatted is not '...'");
! 	      return;
  	    }
  	}
      }
--- 192,199 ----
  	  if (arg_num != first_arg_num)
  	    {
  	      error ("args to be formatted is not '...'");
! 	      *no_add_attrs = true;
! 	      return NULL_TREE;
  	    }
  	}
      }
*************** decl_handle_format_attribute (decl, args
*** 191,212 ****
    if (format_type == strftime_format_type && first_arg_num != 0)
      {
        error ("strftime formats cannot format arguments");
!       return;
      }
  
    record_function_format (DECL_NAME (decl), DECL_ASSEMBLER_NAME (decl),
  			  format_type, format_num, first_arg_num);
  }
  
  
! /* 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;
  {
    tree type = TREE_TYPE (decl);
    tree format_num_expr = TREE_VALUE (args);
    unsigned HOST_WIDE_INT format_num;
--- 201,227 ----
    if (format_type == strftime_format_type && first_arg_num != 0)
      {
        error ("strftime formats cannot format arguments");
!       *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 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;
*************** decl_handle_format_arg_attribute (decl, 
*** 217,223 ****
      {
        error_with_decl (decl,
  		       "argument format specified for non-function `%s'");
!       return;
      }
  
    /* Strip any conversions from the first arg number and verify it
--- 232,239 ----
      {
        error_with_decl (decl,
  		       "argument format specified for non-function `%s'");
!       *no_add_attrs = true;
!       return NULL_TREE;
      }
  
    /* Strip any conversions from the first arg number and verify it
*************** decl_handle_format_arg_attribute (decl, 
*** 231,237 ****
        || TREE_INT_CST_HIGH (format_num_expr) != 0)
      {
        error ("format string has invalid operand number");
!       return;
      }
  
    format_num = TREE_INT_CST_LOW (format_num_expr);
--- 247,254 ----
        || TREE_INT_CST_HIGH (format_num_expr) != 0)
      {
        error ("format string has invalid operand number");
!       *no_add_attrs = true;
!       return NULL_TREE;
      }
  
    format_num = TREE_INT_CST_LOW (format_num_expr);
*************** decl_handle_format_arg_attribute (decl, 
*** 252,258 ****
  	      != char_type_node))
  	{
  	  error ("format string arg not a string type");
! 	  return;
  	}
      }
  
--- 269,276 ----
  	      != char_type_node))
  	{
  	  error ("format string arg not a string type");
! 	  *no_add_attrs = true;
! 	  return NULL_TREE;
  	}
      }
  
*************** decl_handle_format_arg_attribute (decl, 
*** 261,271 ****
  	  != char_type_node))
      {
        error ("function does not return string type");
!       return;
      }
  
    record_international_format (DECL_NAME (decl), DECL_ASSEMBLER_NAME (decl),
  			       format_num);
  }
  
  typedef struct function_format_info
--- 279,291 ----
  	  != char_type_node))
      {
        error ("function does not return string type");
!       *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 -rcpN gcc.orig/c-parse.in gcc/c-parse.in
*** gcc.orig/c-parse.in	Wed Aug 22 20:36:04 2001
--- gcc/c-parse.in	Tue Sep 11 21:21:12 2001
*************** end ifc
*** 173,179 ****
  %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> typespec_reserved_nonattr typespec_reserved_attr
  %type <ttype> typespec_nonreserved_nonattr
  
--- 173,179 ----
  %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_attrs typespec_nonattr typespec_attr
  %type <ttype> typespec_reserved_nonattr typespec_reserved_attr
  %type <ttype> typespec_nonreserved_nonattr
  
*************** end ifc
*** 182,188 ****
  %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
--- 182,187 ----
*************** setspecs: /* empty */
*** 847,875 ****
  		  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
  	;
  
  decl:
--- 846,856 ----
  		  all_prefix_attributes = prefix_attributes; }
  	;
  
  /* Possibly attributes after a comma, which should reset all_prefix_attributes
     to prefix_attributes with these ones chained on the front.  */
  maybe_resetattrs:
! 	  maybe_attribute
! 		{ all_prefix_attributes = chainon ($1, prefix_attributes); }
  	;
  
  decl:
*************** declspecs:
*** 1347,1364 ****
  	| 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:
  	  /* 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; }
  	;
  
  /* A type specifier (but not a type qualifier).
--- 1328,1339 ----
  	| declspecs_sc_ts_sa_ea
  	;
  
! /* A (possibly empty) sequence of type qualifiers and attributes.  */
! maybe_type_quals_attrs:
  	  /* empty */
  		{ $$ = NULL_TREE; }
  	| declspecs_nosc_nots
! 		{ $$ = $1; }
  	;
  
  /* A type specifier (but not a type qualifier).
*************** declarator:
*** 1669,1676 ****
  /* A declarator that is allowed only after an explicit typespec.  */
  
  after_type_declarator:
! 	  '(' maybe_setattrs after_type_declarator ')'
! 		{ $$ = $3; }
  	| after_type_declarator '(' parmlist_or_identifiers  %prec '.'
  		{ $$ = build_nt (CALL_EXPR, $1, $3, NULL_TREE); }
  /*	| after_type_declarator '(' error ')'  %prec '.'
--- 1644,1651 ----
  /* A declarator that is allowed only after an explicit typespec.  */
  
  after_type_declarator:
! 	  '(' 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 '.'
*************** after_type_declarator:
*** 1678,1684 ****
  		  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
  		{ $$ = make_pointer_declarator ($2, $3); }
  	| TYPENAME
  ifobjc
--- 1653,1659 ----
  		  poplevel (0, 0, 0); }  */
  	| after_type_declarator array_declarator  %prec '.'
  		{ $$ = set_array_declarator_type ($2, $1, 0); }
! 	| '*' maybe_type_quals_attrs after_type_declarator  %prec UNARY
  		{ $$ = make_pointer_declarator ($2, $3); }
  	| TYPENAME
  ifobjc
*************** parm_declarator_nostarttypename:
*** 1717,1728 ****
  		  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
  		{ $$ = make_pointer_declarator ($2, $3); }
! 	| '*' maybe_type_quals_setattrs parm_declarator_nostarttypename  %prec UNARY
  		{ $$ = make_pointer_declarator ($2, $3); }
! 	| '(' maybe_setattrs parm_declarator_nostarttypename ')'
! 		{ $$ = $3; }
  	;
  
  /* A declarator allowed whether or not there has been
--- 1692,1703 ----
  		  poplevel (0, 0, 0); }  */
  	| parm_declarator_nostarttypename array_declarator  %prec '.'
  		{ $$ = set_array_declarator_type ($2, $1, 0); }
! 	| '*' maybe_type_quals_attrs parm_declarator_starttypename  %prec UNARY
  		{ $$ = make_pointer_declarator ($2, $3); }
! 	| '*' maybe_type_quals_attrs parm_declarator_nostarttypename  %prec UNARY
  		{ $$ = make_pointer_declarator ($2, $3); }
! 	| '(' maybe_attribute parm_declarator_nostarttypename ')'
! 		{ $$ = $2 ? tree_cons ($2, $3, NULL_TREE) : $3; }
  	;
  
  /* A declarator allowed whether or not there has been
*************** notype_declarator:
*** 1734,1742 ****
  /*	| 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
  		{ $$ = make_pointer_declarator ($2, $3); }
  	| notype_declarator array_declarator  %prec '.'
  		{ $$ = set_array_declarator_type ($2, $1, 0); }
--- 1709,1717 ----
  /*	| notype_declarator '(' error ')'  %prec '.'
  		{ $$ = build_nt (CALL_EXPR, $1, NULL_TREE, NULL_TREE);
  		  poplevel (0, 0, 0); }  */
! 	| '(' 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); }
*************** absdcl1:  /* a nonempty absolute declara
*** 1991,2010 ****
  
  absdcl1_noea:
  	  direct_absdcl1
! 	| '*' maybe_type_quals_setattrs absdcl1_noea
  		{ $$ = make_pointer_declarator ($2, $3); }
  	;
  
  absdcl1_ea:
! 	  '*' maybe_type_quals_setattrs
  		{ $$ = make_pointer_declarator ($2, NULL_TREE); }
! 	| '*' maybe_type_quals_setattrs absdcl1_ea
  		{ $$ = make_pointer_declarator ($2, $3); }
  	;
  
  direct_absdcl1:
! 	  '(' maybe_setattrs absdcl1 ')'
! 		{ $$ = $3; }
  	| direct_absdcl1 '(' parmlist
  		{ $$ = build_nt (CALL_EXPR, $1, $3, NULL_TREE); }
  	| direct_absdcl1 array_declarator
--- 1966,1985 ----
  
  absdcl1_noea:
  	  direct_absdcl1
! 	| '*' maybe_type_quals_attrs absdcl1_noea
  		{ $$ = make_pointer_declarator ($2, $3); }
  	;
  
  absdcl1_ea:
! 	  '*' maybe_type_quals_attrs
  		{ $$ = make_pointer_declarator ($2, NULL_TREE); }
! 	| '*' maybe_type_quals_attrs absdcl1_ea
  		{ $$ = make_pointer_declarator ($2, $3); }
  	;
  
  direct_absdcl1:
! 	  '(' 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
*************** yyprint (file, yychar, yyl)
*** 3906,3920 ****
  
  /* 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.
  
!    We return an INDIRECT_REF whose "contents" are TARGET
!    and whose type is the modifier list.  */
  
  tree
! make_pointer_declarator (type_quals, target)
!      tree type_quals, target;
  {
!   return build1 (INDIRECT_REF, type_quals, target);
  }
--- 3881,3901 ----
  
  /* Return something to represent absolute declarators containing a *.
     TARGET is the absolute declarator that the * contains.
!    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 (inside a TREE_LIST,
!    if attributes are present) and whose type is the modifier list.  */
  
  tree
! make_pointer_declarator (type_quals_attrs, target)
!      tree type_quals_attrs, 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 -rcpN gcc.orig/config/alpha/alpha.c gcc/config/alpha/alpha.c
*** gcc.orig/config/alpha/alpha.c	Wed Sep  5 07:47:53 2001
--- gcc/config/alpha/alpha.c	Tue Sep 11 21:44:49 2001
*************** static int alpha_variable_issue
*** 155,167 ****
  
  /* Initialize the GCC target structure.  */
  #if TARGET_ABI_OPEN_VMS
! static int vms_valid_decl_attribute_p PARAMS ((tree, tree, tree, tree));
  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_SECTION_TYPE_FLAGS
  # define TARGET_SECTION_TYPE_FLAGS vms_section_type_flags
  #endif
--- 155,167 ----
  
  /* Initialize the GCC target structure.  */
  #if TARGET_ABI_OPEN_VMS
! 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_ATTRIBUTE_TABLE
! # define TARGET_ATTRIBUTE_TABLE vms_attribute_table
  # undef TARGET_SECTION_TYPE_FLAGS
  # define TARGET_SECTION_TYPE_FLAGS vms_section_type_flags
  #endif
*************** alpha_using_fp ()
*** 4883,4899 ****
  
  #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;
  {
!   if (is_attribute_p ("overlaid", identifier))
!     return (args == NULL_TREE);
!   return 0;
! }
  
  #endif
  
--- 4883,4894 ----
  
  #if TARGET_ABI_OPEN_VMS
  
! const struct attribute_spec vms_attribute_table[] =
  {
!   /* { 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
  
*************** vms_section_type_flags (decl, name, relo
*** 6888,6895 ****
  {
    unsigned int flags = default_section_type_flags (decl, name, reloc);
  
!   if (decl && DECL_MACHINE_ATTRIBUTES (decl)
!       && lookup_attribute ("overlaid", DECL_MACHINE_ATTRIBUTES (decl)))
      flags |= SECTION_VMS_OVERLAY;
  
    return flags;
--- 6883,6890 ----
  {
    unsigned int flags = default_section_type_flags (decl, name, reloc);
  
!   if (decl && DECL_ATTRIBUTES (decl)
!       && lookup_attribute ("overlaid", DECL_ATTRIBUTES (decl)))
      flags |= SECTION_VMS_OVERLAY;
  
    return flags;
diff -rcpN gcc.orig/config/arc/arc.c gcc/config/arc/arc.c
*** gcc.orig/config/arc/arc.c	Thu Jul 12 13:51:31 2001
--- gcc/config/arc/arc.c	Tue Sep 11 21:45:11 2001
*************** static int current_insn_set_cc_p;
*** 87,93 ****
  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));
  static void arc_output_function_prologue PARAMS ((FILE *, HOST_WIDE_INT));
  static void arc_output_function_epilogue PARAMS ((FILE *, HOST_WIDE_INT));
  
--- 87,94 ----
  static void record_cc_ref PARAMS ((rtx));
  static void arc_init_reg_tables PARAMS ((void));
  static int get_arc_condition_code PARAMS ((rtx));
! 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));
  
*************** static void arc_output_function_epilogue
*** 96,103 ****
  #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
  
  struct gcc_target targetm = TARGET_INITIALIZER;
  
--- 97,104 ----
  #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_ATTRIBUTE_TABLE
! #define TARGET_ATTRIBUTE_TABLE arc_attribute_table
  
  struct gcc_target targetm = TARGET_INITIALIZER;
  
*************** arc_init_reg_tables ()
*** 326,351 ****
     interrupt - for interrupt functions
  */
  
! /* Return nonzero if IDENTIFIER is a valid decl attribute.  */
  
! static int
! arc_valid_decl_attribute (type, attributes, identifier, args)
!      tree type ATTRIBUTE_UNUSED;
!      tree attributes ATTRIBUTE_UNUSED;
!      tree identifier;
       tree args;
  {
!   if (identifier == get_identifier ("__interrupt__")
!       && list_length (args) == 1
!       && TREE_CODE (TREE_VALUE (args)) == STRING_CST)
!     {
!       tree value = TREE_VALUE (args);
  
!       if (!strcmp (TREE_STRING_POINTER (value), "ilink1")
! 	   || !strcmp (TREE_STRING_POINTER (value), "ilink2"))
! 	return 1;
      }
!   return 0;
  }
  
  
--- 327,366 ----
     interrupt - for interrupt functions
  */
  
! 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 }
! };
  
! /* Handle an "interrupt" attribute; arguments as in
!    struct attribute_spec.handler.  */
! static tree
! arc_handle_interrupt_attribute (node, name, args, flags, no_add_attrs)
!      tree *node ATTRIBUTE_UNUSED;
!      tree name;
       tree args;
+      int flags ATTRIBUTE_UNUSED;
+      bool *no_add_attrs;
  {
!   tree value = TREE_VALUE (args);
  
!   if (TREE_CODE (value) != STRING_CST)
!     {
!       warning ("argument of `%s' attribute is not a string constant",
! 	       IDENTIFIER_POINTER (name));
!       *no_add_attrs = true;
      }
!   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;
  }
  
  
*************** arc_compute_function_type (decl)
*** 956,962 ****
    fn_type = ARC_FUNCTION_NORMAL;
  
    /* Now see if this is an interrupt handler.  */
!   for (a = DECL_MACHINE_ATTRIBUTES (current_function_decl);
         a;
         a = TREE_CHAIN (a))
      {
--- 971,977 ----
    fn_type = ARC_FUNCTION_NORMAL;
  
    /* Now see if this is an interrupt handler.  */
!   for (a = DECL_ATTRIBUTES (current_function_decl);
         a;
         a = TREE_CHAIN (a))
      {
diff -rcpN gcc.orig/config/arm/arm.c gcc/config/arm/arm.c
*** gcc.orig/config/arm/arm.c	Fri Aug 31 19:44:17 2001
--- gcc/config/arm/arm.c	Wed Sep 19 12:49:03 2001
*************** static int       current_file_function_o
*** 103,112 ****
  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 void	 arm_output_function_epilogue	PARAMS ((FILE *,
  							 HOST_WIDE_INT));
  static void	 arm_output_function_prologue	PARAMS ((FILE *,
--- 103,111 ----
  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 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 *,
*************** static int	 arm_adjust_cost		PARAMS ((rt
*** 130,145 ****
  #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_ASM_FUNCTION_PROLOGUE
  #define TARGET_ASM_FUNCTION_PROLOGUE arm_output_function_prologue
--- 129,136 ----
  #define TARGET_MERGE_DECL_ATTRIBUTES merge_dllimport_decl_attributes
  #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
*************** arm_compute_func_type ()
*** 845,851 ****
    if (current_function_needs_context)
      type |= ARM_FT_NESTED;
  
!   attr = DECL_MACHINE_ATTRIBUTES (current_function_decl);
    
    a = lookup_attribute ("naked", attr);
    if (a != NULL_TREE)
--- 836,842 ----
    if (current_function_needs_context)
      type |= ARM_FT_NESTED;
  
!   attr = DECL_ATTRIBUTES (current_function_decl);
    
    a = lookup_attribute ("naked", attr);
    if (a != NULL_TREE)
*************** arm_pr_long_calls_off (pfile)
*** 1909,1947 ****
  }
  
  
! /* 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;
  {
!   if (   TREE_CODE (type) != FUNCTION_TYPE
!       && TREE_CODE (type) != METHOD_TYPE
!       && TREE_CODE (type) != FIELD_DECL
!       && TREE_CODE (type) != TYPE_DECL)
!     return 0;
! 
    /* 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);
!   
    /* 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);
!   
    /* 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);
  
!   return 0;
  }
  
  /* Return 0 if the attributes for two types are incompatible, 1 if they
--- 1900,2019 ----
  }
  
  
! /* Table of machine attributes.  */
! const struct attribute_spec arm_attribute_table[] =
  {
!   /* { 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.  */
!   { "long_call",    0, 0, false, true,  true,  NULL },
    /* Whereas these functions are always known to reside within the 26 bit
       addressing range.  */
!   { "short_call",   0, 0, false, true,  true,  NULL },
    /* Interrupt Service Routines have special prologue and epilogue requirements.  */ 
!   { "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 }
! };
  
! /* 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
*************** multi_register_push (op, mode)
*** 4132,4216 ****
    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,
--- 4204,4209 ----
*************** is_called_in_ARM_mode (func)
*** 9742,9748 ****
      return TRUE;
  
  #ifdef ARM_PE 
!   return lookup_attribute ("interfacearm", DECL_MACHINE_ATTRIBUTES (func)) != NULL_TREE;
  #else
    return FALSE;
  #endif
--- 9735,9741 ----
      return TRUE;
  
  #ifdef ARM_PE 
!   return lookup_attribute ("interfacearm", DECL_ATTRIBUTES (func)) != NULL_TREE;
  #else
    return FALSE;
  #endif
diff -rcpN gcc.orig/config/arm/pe.c gcc/config/arm/pe.c
*** gcc.orig/config/arm/pe.c	Tue Jun 26 19:14:58 2001
--- gcc/config/arm/pe.c	Wed Sep  5 08:12:12 2001
***************
*** 1,5 ****
  /* Routines for GCC for ARM/pe.
!    Copyright (C) 1995, 1996, 2000 Free Software Foundation, Inc.
     Contributed by Doug Evans (dje@cygnus.com).
  
  This file is part of GNU CC.
--- 1,5 ----
  /* Routines for GCC for ARM/pe.
!    Copyright (C) 1995, 1996, 2000, 2001 Free Software Foundation, Inc.
     Contributed by Doug Evans (dje@cygnus.com).
  
  This file is part of GNU CC.
*************** arm_dllexport_p (decl)
*** 45,51 ****
    if (TREE_CODE (decl) != VAR_DECL
        && TREE_CODE (decl) != FUNCTION_DECL)
      return 0;
!   exp = lookup_attribute ("dllexport", DECL_MACHINE_ATTRIBUTES (decl));
    if (exp)
      return 1;
  
--- 45,51 ----
    if (TREE_CODE (decl) != VAR_DECL
        && TREE_CODE (decl) != FUNCTION_DECL)
      return 0;
!   exp = lookup_attribute ("dllexport", DECL_ATTRIBUTES (decl));
    if (exp)
      return 1;
  
*************** arm_dllimport_p (decl)
*** 67,73 ****
    if (TREE_CODE (decl) != VAR_DECL
        && TREE_CODE (decl) != FUNCTION_DECL)
      return 0;
!   imp = lookup_attribute ("dllimport", DECL_MACHINE_ATTRIBUTES (decl));
    if (imp)
      return 1;
  
--- 67,73 ----
    if (TREE_CODE (decl) != VAR_DECL
        && TREE_CODE (decl) != FUNCTION_DECL)
      return 0;
!   imp = lookup_attribute ("dllimport", DECL_ATTRIBUTES (decl));
    if (imp)
      return 1;
  
diff -rcpN gcc.orig/config/avr/avr.c gcc/config/avr/avr.c
*** gcc.orig/config/avr/avr.c	Sat Aug 11 11:44:19 2001
--- gcc/config/avr/avr.c	Wed Sep 19 11:48:35 2001
*************** static int    compare_sign_p       PARAM
*** 58,65 ****
  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 void   avr_output_function_prologue PARAMS ((FILE *, HOST_WIDE_INT));
  static void   avr_output_function_epilogue PARAMS ((FILE *, HOST_WIDE_INT));
  
--- 58,66 ----
  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 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));
  
*************** int avr_case_values_threshold = 30000;
*** 177,187 ****
  #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
  
  struct gcc_target targetm = TARGET_INITIALIZER;
  
--- 178,185 ----
  #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_ATTRIBUTE_TABLE
! #define TARGET_ATTRIBUTE_TABLE avr_attribute_table
  
  struct gcc_target targetm = TARGET_INITIALIZER;
  
*************** avr_naked_function_p (func)
*** 310,316 ****
    if (TREE_CODE (func) != FUNCTION_DECL)
      abort ();
    
!   a = lookup_attribute ("naked", DECL_MACHINE_ATTRIBUTES (func));
    return a != NULL_TREE;
  }
  
--- 308,314 ----
    if (TREE_CODE (func) != FUNCTION_DECL)
      abort ();
    
!   a = lookup_attribute ("naked", DECL_ATTRIBUTES (func));
    return a != NULL_TREE;
  }
  
*************** interrupt_function_p (func)
*** 326,332 ****
    if (TREE_CODE (func) != FUNCTION_DECL)
      return 0;
  
!   a = lookup_attribute ("interrupt", DECL_MACHINE_ATTRIBUTES (func));
    return a != NULL_TREE;
  }
  
--- 324,330 ----
    if (TREE_CODE (func) != FUNCTION_DECL)
      return 0;
  
!   a = lookup_attribute ("interrupt", DECL_ATTRIBUTES (func));
    return a != NULL_TREE;
  }
  
*************** signal_function_p (func)
*** 342,348 ****
    if (TREE_CODE (func) != FUNCTION_DECL)
      return 0;
  
!   a = lookup_attribute ("signal", DECL_MACHINE_ATTRIBUTES (func));
    return a != NULL_TREE;
  }
  
--- 340,346 ----
    if (TREE_CODE (func) != FUNCTION_DECL)
      return 0;
  
!   a = lookup_attribute ("signal", DECL_ATTRIBUTES (func));
    return a != NULL_TREE;
  }
  
*************** class_likely_spilled_p (c)
*** 4665,4718 ****
    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:
     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.  */
  
! static int
! avr_valid_decl_attribute (decl, attributes, attr, args)
!      tree decl;
!      tree attributes ATTRIBUTE_UNUSED;
!      tree attr;
!      tree args ATTRIBUTE_UNUSED;
  {
!   if (is_attribute_p ("interrupt", attr)
!       || is_attribute_p ("signal", attr)
!       || is_attribute_p ("naked", attr))
!     return TREE_CODE (decl) == FUNCTION_DECL;
  
!   if (is_attribute_p ("progmem", attr)
!       && (TREE_STATIC (decl) || DECL_EXTERNAL (decl)))
      {
!       if (DECL_INITIAL (decl) == NULL_TREE && !DECL_EXTERNAL (decl))
  	{
! 	  warning ("Only initialized variables can be placed into "
! 		   "program memory area.");
! 	  return 0;
  	}
-       return 1;
      }
!   return 0;
  }
  
  
  /* Look for attribute `progmem' in DECL
     if found return 1, otherwise 0.  */
--- 4663,4738 ----
    return (c != ALL_REGS && c != ADDW_REGS);
  }
  
! /* 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.
  
!    Only `progmem' attribute valid for type.  */
! 
! const struct attribute_spec avr_attribute_table[] =
  {
!   /* { 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 }
! };
  
! /* 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 (TREE_STATIC (*node) || DECL_EXTERNAL (*node))
  	{
! 	  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 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.  */
*************** avr_progmem_p (decl)
*** 4727,4733 ****
      return 0;
  
    if (NULL_TREE
!       != lookup_attribute ("progmem", DECL_MACHINE_ATTRIBUTES (decl)))
      return 1;
  
    a=decl;
--- 4747,4753 ----
      return 0;
  
    if (NULL_TREE
!       != lookup_attribute ("progmem", DECL_ATTRIBUTES (decl)))
      return 1;
  
    a=decl;
diff -rcpN gcc.orig/config/avr/avr.h gcc/config/avr/avr.h
*** gcc.orig/config/avr/avr.h	Mon Aug 20 17:53:22 2001
--- gcc/config/avr/avr.h	Wed Sep  5 08:12:12 2001
*************** enum reg_class {
*** 1110,1116 ****
     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
     function.
  
     FUNTYPE is a C variable whose value is a tree node that describes
--- 1110,1116 ----
     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_ATTRIBUTES of the
     function.
  
     FUNTYPE is a C variable whose value is a tree node that describes
diff -rcpN gcc.orig/config/c4x/c4x.c gcc/config/c4x/c4x.c
*** gcc.orig/config/c4x/c4x.c	Mon Aug 20 17:53:22 2001
--- gcc/config/c4x/c4x.c	Tue Sep 11 21:46:39 2001
*************** static int c4x_parse_pragma PARAMS ((con
*** 191,204 ****
  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 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_INSERT_ATTRIBUTES
  #define TARGET_INSERT_ATTRIBUTES c4x_insert_attributes
--- 191,205 ----
  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 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_ATTRIBUTE_TABLE
! #define TARGET_ATTRIBUTE_TABLE c4x_attribute_table
  
  #undef TARGET_INSERT_ATTRIBUTES
  #define TARGET_INSERT_ATTRIBUTES c4x_insert_attributes
*************** c4x_insert_attributes (decl, attributes)
*** 4761,4791 ****
      }
  }
  
  
! /* Return nonzero if IDENTIFIER with arguments ARGS is a valid machine
!    specific attribute for TYPE.  The attributes in ATTRIBUTES have
!    previously been assigned to TYPE.  */
! 
! static int
! c4x_valid_type_attribute_p (type, attributes, identifier, args)
!      tree type;
!      tree attributes ATTRIBUTE_UNUSED;
!      tree identifier;
       tree args ATTRIBUTE_UNUSED;
  {
!   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;
  }
  
  
--- 4762,4797 ----
      }
  }
  
+ /* 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 }
+ };
  
! /* Handle an attribute requiring a FUNCTION_TYPE;
!    arguments as in struct attribute_spec.handler.  */
! static tree
! c4x_handle_fntype_attribute (node, name, args, flags, no_add_attrs)
!      tree *node;
!      tree name;
       tree args ATTRIBUTE_UNUSED;
+      int flags ATTRIBUTE_UNUSED;
+      bool *no_add_attrs;
  {
!   if (TREE_CODE (*node) != FUNCTION_TYPE)
!     {
!       warning ("`%s' attribute only applies to functions",
! 	       IDENTIFIER_POINTER (name));
!       *no_add_attrs = true;
!     }
! 
!   return NULL_TREE;
  }
  
  
diff -rcpN gcc.orig/config/d30v/d30v.h gcc/config/d30v/d30v.h
*** gcc.orig/config/d30v/d30v.h	Mon Aug 20 17:53:23 2001
--- gcc/config/d30v/d30v.h	Wed Sep  5 08:12:12 2001
*************** typedef struct d30v_stack {
*** 2272,2278 ****
     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.
  
     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
--- 2272,2278 ----
     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_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 -rcpN gcc.orig/config/fr30/fr30.h gcc/config/fr30/fr30.h
*** gcc.orig/config/fr30/fr30.h	Fri Aug  3 11:42:55 2001
--- gcc/config/fr30/fr30.h	Wed Sep  5 08:12:12 2001
***************
*** 1,7 ****
  /*{{{  Comment.  */ 
  
  /* Definitions of FR30 target. 
!    Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
     Contributed by Cygnus Solutions.
  
  This file is part of GNU CC.
--- 1,7 ----
  /*{{{  Comment.  */ 
  
  /* Definitions of FR30 target. 
!    Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
     Contributed by Cygnus Solutions.
  
  This file is part of GNU CC.
*************** enum reg_class
*** 824,830 ****
     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.
  
     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
--- 824,830 ----
     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_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 -rcpN gcc.orig/config/h8300/h8300.c gcc/config/h8300/h8300.c
*** gcc.orig/config/h8300/h8300.c	Fri Aug 31 10:16:36 2001
--- gcc/config/h8300/h8300.c	Tue Sep 11 21:46:54 2001
*************** static unsigned int compute_saved_regs P
*** 53,59 ****
  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));
  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));
--- 53,62 ----
  static void push PARAMS ((FILE *, int));
  static void pop PARAMS ((FILE *, int));
  static const char *cond_string PARAMS ((enum rtx_code));
! 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));
*************** static const char *const h8_mov_ops[2] =
*** 98,105 ****
  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_ASM_FUNCTION_PROLOGUE
  #define TARGET_ASM_FUNCTION_PROLOGUE h8300_output_function_prologue
--- 101,108 ----
  const char *h8_push_op, *h8_pop_op, *h8_mov_op;
  
  /* Initialize the GCC target structure.  */
! #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
*************** h8300_interrupt_function_p (func)
*** 3094,3100 ****
    if (TREE_CODE (func) != FUNCTION_DECL)
      return 0;
  
!   a = lookup_attribute ("interrupt_handler", DECL_MACHINE_ATTRIBUTES (func));
    return a != NULL_TREE;
  }
  
--- 3097,3103 ----
    if (TREE_CODE (func) != FUNCTION_DECL)
      return 0;
  
!   a = lookup_attribute ("interrupt_handler", DECL_ATTRIBUTES (func));
    return a != NULL_TREE;
  }
  
*************** h8300_os_task_function_p (func)
*** 3110,3116 ****
    if (TREE_CODE (func) != FUNCTION_DECL)
      return 0;
  
!   a = lookup_attribute ("OS_Task", DECL_MACHINE_ATTRIBUTES (func));
    return a != NULL_TREE;
  }
  
--- 3113,3119 ----
    if (TREE_CODE (func) != FUNCTION_DECL)
      return 0;
  
!   a = lookup_attribute ("OS_Task", DECL_ATTRIBUTES (func));
    return a != NULL_TREE;
  }
  
*************** h8300_monitor_function_p (func)
*** 3126,3132 ****
    if (TREE_CODE (func) != FUNCTION_DECL)
      return 0;
  
!   a = lookup_attribute ("monitor", DECL_MACHINE_ATTRIBUTES (func));
    return a != NULL_TREE;
  }
  
--- 3129,3135 ----
    if (TREE_CODE (func) != FUNCTION_DECL)
      return 0;
  
!   a = lookup_attribute ("monitor", DECL_ATTRIBUTES (func));
    return a != NULL_TREE;
  }
  
*************** h8300_funcvec_function_p (func)
*** 3142,3148 ****
    if (TREE_CODE (func) != FUNCTION_DECL)
      return 0;
  
!   a = lookup_attribute ("function_vector", DECL_MACHINE_ATTRIBUTES (func));
    return a != NULL_TREE;
  }
  
--- 3145,3151 ----
    if (TREE_CODE (func) != FUNCTION_DECL)
      return 0;
  
!   a = lookup_attribute ("function_vector", DECL_ATTRIBUTES (func));
    return a != NULL_TREE;
  }
  
*************** h8300_eightbit_data_p (decl)
*** 3158,3164 ****
    if (TREE_CODE (decl) != VAR_DECL)
      return 0;
  
!   a = lookup_attribute ("eightbit_data", DECL_MACHINE_ATTRIBUTES (decl));
    return a != NULL_TREE;
  }
  
--- 3161,3167 ----
    if (TREE_CODE (decl) != VAR_DECL)
      return 0;
  
!   a = lookup_attribute ("eightbit_data", DECL_ATTRIBUTES (decl));
    return a != NULL_TREE;
  }
  
*************** h8300_tiny_data_p (decl)
*** 3174,3188 ****
    if (TREE_CODE (decl) != VAR_DECL)
      return 0;
  
!   a = lookup_attribute ("tiny_data", DECL_MACHINE_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:
  
     interrupt_handler: output a prologue and epilogue suitable for an
     interrupt handler.
--- 3177,3187 ----
    if (TREE_CODE (decl) != VAR_DECL)
      return 0;
  
!   a = lookup_attribute ("tiny_data", DECL_ATTRIBUTES (decl));
    return a != NULL_TREE;
  }
  
! /* Supported attributes:
  
     interrupt_handler: output a prologue and epilogue suitable for an
     interrupt handler.
*************** h8300_tiny_data_p (decl)
*** 3196,3242 ****
     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;
  {
!   if (args != NULL_TREE)
!     return 0;
  
!   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)))
      {
        if (DECL_INITIAL (decl) == NULL_TREE)
  	{
  	  warning ("Only initialized variables can be placed into the 8-bit area.");
! 	  return 0;
  	}
!       DECL_SECTION_NAME (decl) = build_string (7, ".eight");
!       return 1;
      }
  
!   if (is_attribute_p ("tiny_data", attr)
!       && (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;
  	}
!       DECL_SECTION_NAME (decl) = build_string (6, ".tiny");
!       return 1;
      }
  
!   return 0;
  }
  
  void
--- 3195,3293 ----
     tiny_data: This variable lives in the tiny data area and can be
     referenced with 16-bit absolute memory references.  */
  
! const struct attribute_spec h8300_attribute_table[] =
  {
!   /* { 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 }
! };
! 
  
! /* 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.");
! 	  *no_add_attrs = true;
  	}
!       else
! 	DECL_SECTION_NAME (decl) = build_string (7, ".eight");
!     }
!   else
!     {
!       warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
!       *no_add_attrs = true;
      }
  
!   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.");
! 	  *no_add_attrs = true;
  	}
!       else
! 	DECL_SECTION_NAME (decl) = build_string (6, ".tiny");
!     }
!   else
!     {
!       warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
!       *no_add_attrs = true;
      }
  
!   return NULL_TREE;
  }
  
  void
diff -rcpN gcc.orig/config/i386/cygwin.h gcc/config/i386/cygwin.h
*** gcc.orig/config/i386/cygwin.h	Tue Aug 28 20:33:32 2001
--- gcc/config/i386/cygwin.h	Wed Sep  5 08:12:12 2001
*************** union tree_node;
*** 191,197 ****
     It's also used to handle dllimport override semantics.  */
  #if 0
  #define REDO_SECTION_INFO_P(DECL) \
!   ((DECL_MACHINE_ATTRIBUTES (DECL) != NULL_TREE) \
     || (TREE_CODE (DECL) == VAR_DECL && DECL_VIRTUAL_P (DECL)))
  #else
  #define REDO_SECTION_INFO_P(DECL) 1
--- 191,197 ----
     It's also used to handle dllimport override semantics.  */
  #if 0
  #define REDO_SECTION_INFO_P(DECL) \
!   ((DECL_ATTRIBUTES (DECL) != NULL_TREE) \
     || (TREE_CODE (DECL) == VAR_DECL && DECL_VIRTUAL_P (DECL)))
  #else
  #define REDO_SECTION_INFO_P(DECL) 1
diff -rcpN gcc.orig/config/i386/i386-protos.h gcc/config/i386/i386-protos.h
*** gcc.orig/config/i386/i386-protos.h	Thu Aug 23 17:54:48 2001
--- gcc/config/i386/i386-protos.h	Sun Sep  9 15:12:51 2001
*************** extern int ix86_return_pops_args PARAMS 
*** 173,181 ****
  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 unsigned int i386_pe_section_type_flags PARAMS ((tree, const char *,
  							int));
  extern void i386_pe_asm_named_section PARAMS ((const char *, unsigned int));
--- 173,181 ----
  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 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 -rcpN gcc.orig/config/i386/i386.c gcc/config/i386/i386.c
*** gcc.orig/config/i386/i386.c	Mon Aug 27 07:45:16 2001
--- gcc/config/i386/i386.c	Tue Sep 11 21:47:13 2001
*************** static int ix86_fp_comparison_cost PARAM
*** 620,625 ****
--- 620,628 ----
  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));
*************** static void sco_asm_out_constructor PARA
*** 630,644 ****
  #endif
  
  /* Initialize the GCC target structure.  */
! #undef TARGET_VALID_TYPE_ATTRIBUTE
  #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
--- 633,643 ----
  #endif
  
  /* Initialize the GCC target structure.  */
! #undef TARGET_ATTRIBUTE_TABLE
! #define TARGET_ATTRIBUTE_TABLE ix86_attribute_table
  #ifdef TARGET_DLLIMPORT_DECL_ATTRIBUTES
  #  undef TARGET_MERGE_DECL_ATTRIBUTES
  #  define TARGET_MERGE_DECL_ATTRIBUTES merge_dllimport_decl_attributes
  #endif
  
  #undef TARGET_COMP_TYPE_ATTRIBUTES
*************** optimization_options (level, size)
*** 928,983 ****
  #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;
  {
!   if (TREE_CODE (type) != FUNCTION_TYPE
!       && TREE_CODE (type) != METHOD_TYPE
!       && TREE_CODE (type) != FIELD_DECL
!       && TREE_CODE (type) != TYPE_DECL)
!     return 0;
! 
    /* 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);
! 
    /* Regparm attribute specifies how many integer arguments are to be
       passed in registers.  */
!   if (is_attribute_p ("regparm", identifier))
      {
!       tree cst;
  
!       if (! args || TREE_CODE (args) != TREE_LIST
! 	  || TREE_CHAIN (args) != NULL_TREE
! 	  || TREE_VALUE (args) == NULL_TREE)
! 	return 0;
  
!       cst = TREE_VALUE (args);
!       if (TREE_CODE (cst) != INTEGER_CST)
! 	return 0;
  
!       if (compare_tree_int (cst, REGPARM_MAX) > 0)
! 	return 0;
  
!       return 1;
      }
  
!   return 0;
  }
  
  #if defined (OSF_OS) || defined (TARGET_OSF1ELF)
--- 927,1020 ----
  #endif
  }
  
! /* Table of valid machine attributes.  */
! const struct attribute_spec ix86_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.  */
!   { "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.  */
!   { "regparm",   1, 1, false, true,  true,  ix86_handle_regparm_attribute },
! #ifdef TARGET_DLLIMPORT_DECL_ATTRIBUTES
!   { "dllimport", 1, 1, false, false, false, ix86_handle_dll_attribute },
!   { "dllexport", 1, 1, false, false, false, ix86_handle_dll_attribute },
!   { "shared",    1, 1, true,  false, false, ix86_handle_shared_attribute },
! #endif
!   { NULL,        0, 0, false, false, false, NULL }
! };
! 
! /* Handle a "cdecl" or "stdcall" attribute;
!    arguments as in struct attribute_spec.handler.  */
! static tree
! ix86_handle_cdecl_attribute (node, name, args, flags, no_add_attrs)
!      tree *node;
!      tree name;
!      tree args ATTRIBUTE_UNUSED;
!      int flags ATTRIBUTE_UNUSED;
!      bool *no_add_attrs;
! {
!   if (TREE_CODE (*node) != FUNCTION_TYPE
!       && TREE_CODE (*node) != METHOD_TYPE
!       && TREE_CODE (*node) != FIELD_DECL
!       && TREE_CODE (*node) != TYPE_DECL)
      {
!       warning ("`%s' attribute only applies to functions",
! 	       IDENTIFIER_POINTER (name));
!       *no_add_attrs = true;
!     }
  
!   if (TARGET_64BIT)
!     {
!       warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
!       *no_add_attrs = true;
!     }
  
!   return NULL_TREE;
! }
  
! /* Handle a "regparm" attribute;
!    arguments as in struct attribute_spec.handler.  */
! static tree
! ix86_handle_regparm_attribute (node, name, args, flags, no_add_attrs)
!      tree *node;
!      tree name;
!      tree args;
!      int flags ATTRIBUTE_UNUSED;
!      bool *no_add_attrs;
! {
!   if (TREE_CODE (*node) != FUNCTION_TYPE
!       && TREE_CODE (*node) != METHOD_TYPE
!       && TREE_CODE (*node) != FIELD_DECL
!       && TREE_CODE (*node) != TYPE_DECL)
!     {
!       warning ("`%s' attribute only applies to functions",
! 	       IDENTIFIER_POINTER (name));
!       *no_add_attrs = true;
!     }
!   else
!     {
!       tree cst;
  
!       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 NULL_TREE;
  }
  
  #if defined (OSF_OS) || defined (TARGET_OSF1ELF)
diff -rcpN gcc.orig/config/i386/winnt.c gcc/config/i386/winnt.c
*** gcc.orig/config/i386/winnt.c	Mon Aug 20 17:53:23 2001
--- gcc/config/i386/winnt.c	Wed Sep 19 12:01:27 2001
***************
*** 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.
  
  This file is part of GNU CC.
  
--- 1,6 ----
  /* Subroutines for insn-output.c for Windows NT.
     Contributed by Douglas Rupp (drupp@cs.washington.edu)
!    Copyright (C) 1995, 1997, 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
  
  This file is part of GNU CC.
  
*************** int i386_pe_dllimport_p PARAMS ((tree));
*** 49,99 ****
  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;
       tree args;
  {
!   if (args == NULL_TREE)
      {
!       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;
      }
  
!   return 0;
  }
  
! /* 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;
  {
!   if (args == NULL_TREE
!       && (TREE_CODE (type) == RECORD_TYPE || TREE_CODE (type) == UNION_TYPE))
      {
!       if (is_attribute_p ("dllexport", attr))
! 	return 1;
!       if (is_attribute_p ("dllimport", attr))
! 	return 1;
      }
  
!   return ix86_valid_type_attribute_p (type, attributes, attr, args);
  }
  
  /* Return the type that we should use to determine if DECL is
--- 49,102 ----
  void i386_pe_mark_dllexport PARAMS ((tree));
  void i386_pe_mark_dllimport PARAMS ((tree));
  
! /* 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;
  {
!   /* These attributes may apply to structure and union types being created,
!      but otherwise should pass to the declaration involved.  */
!   if (!DECL_P (*node))
      {
!       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 NULL_TREE;
  }
  
! /* 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 (TREE_CODE (*node) != VAR_DECL)
      {
!       warning ("`%s' attribute only applies to variables",
! 	       IDENTIFIER_POINTER (name));
!       *no_add_attrs = true;
      }
  
!   return NULL_TREE;
  }
  
  /* Return the type that we should use to determine if DECL is
*************** i386_pe_dllexport_p (decl)
*** 132,138 ****
    if (TREE_CODE (decl) != VAR_DECL
        && TREE_CODE (decl) != FUNCTION_DECL)
      return 0;
!   exp = lookup_attribute ("dllexport", DECL_MACHINE_ATTRIBUTES (decl));
    if (exp)
      return 1;
  
--- 135,141 ----
    if (TREE_CODE (decl) != VAR_DECL
        && TREE_CODE (decl) != FUNCTION_DECL)
      return 0;
!   exp = lookup_attribute ("dllexport", DECL_ATTRIBUTES (decl));
    if (exp)
      return 1;
  
*************** i386_pe_dllimport_p (decl)
*** 163,169 ****
    if (TREE_CODE (decl) != VAR_DECL
        && TREE_CODE (decl) != FUNCTION_DECL)
      return 0;
!   imp = lookup_attribute ("dllimport", DECL_MACHINE_ATTRIBUTES (decl));
    if (imp)
      return 1;
  
--- 166,172 ----
    if (TREE_CODE (decl) != VAR_DECL
        && TREE_CODE (decl) != FUNCTION_DECL)
      return 0;
!   imp = lookup_attribute ("dllimport", DECL_ATTRIBUTES (decl));
    if (imp)
      return 1;
  
*************** i386_pe_section_type_flags (decl, name, 
*** 499,505 ****
        flags = SECTION_WRITE;
  
        if (decl && TREE_CODE (decl) == VAR_DECL
! 	  && lookup_attribute ("shared", DECL_MACHINE_ATTRIBUTES (decl)))
  	flags |= SECTION_PE_SHARED;
      }
  
--- 502,508 ----
        flags = SECTION_WRITE;
  
        if (decl && TREE_CODE (decl) == VAR_DECL
! 	  && lookup_attribute ("shared", DECL_ATTRIBUTES (decl)))
  	flags |= SECTION_PE_SHARED;
      }
  
diff -rcpN gcc.orig/config/ia64/ia64.c gcc/config/ia64/ia64.c
*** gcc.orig/config/ia64/ia64.c	Fri Aug 24 18:20:43 2001
--- gcc/config/ia64/ia64.c	Tue Sep 11 21:47:31 2001
*************** static rtx ia64_expand_compare_and_swap 
*** 138,144 ****
  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));
  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 *));
--- 138,144 ----
  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));
! 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 *));
*************** static rtx ia64_cycle_display PARAMS ((i
*** 156,163 ****
  
  
  /* Initialize the GCC target structure.  */
! #undef TARGET_VALID_TYPE_ATTRIBUTE
! #define TARGET_VALID_TYPE_ATTRIBUTE ia64_valid_type_attribute
  
  #undef TARGET_INIT_BUILTINS
  #define TARGET_INIT_BUILTINS ia64_init_builtins
--- 156,163 ----
  
  
  /* Initialize the GCC target structure.  */
! #undef TARGET_ATTRIBUTE_TABLE
! #define TARGET_ATTRIBUTE_TABLE ia64_attribute_table
  
  #undef TARGET_INIT_BUILTINS
  #define TARGET_INIT_BUILTINS ia64_init_builtins
*************** ia64_epilogue_uses (regno)
*** 6740,6768 ****
      }
  }
  
! /* 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;
  {
!   /* 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;
! }
  
  /* For ia64, SYMBOL_REF_FLAG set means that it is a function.
  
--- 6740,6752 ----
      }
  }
  
! /* Table of valid machine attributes.  */
! const struct attribute_spec ia64_attribute_table[] =
  {
!   /* { 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 -rcpN gcc.orig/config/m32r/m32r.c gcc/config/m32r/m32r.c
*** gcc.orig/config/m32r/m32r.c	Mon Aug 20 17:53:26 2001
--- gcc/config/m32r/m32r.c	Tue Sep 11 21:47:48 2001
*************** static int m32r_sched_odd_word_p;
*** 62,69 ****
  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));
  static void  m32r_output_function_prologue PARAMS ((FILE *, HOST_WIDE_INT));
  static void  m32r_output_function_epilogue PARAMS ((FILE *, HOST_WIDE_INT));
  
--- 62,69 ----
  static void  init_reg_tables			PARAMS ((void));
  static void  block_move_call			PARAMS ((rtx, rtx, rtx));
  static int   m32r_is_insn			PARAMS ((rtx));
! 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));
  
*************** static int    m32r_issue_rate	   PARAMS 
*** 76,83 ****
  
  
  /* Initialize the GCC target structure.  */
! #undef TARGET_VALID_DECL_ATTRIBUTE
! #define TARGET_VALID_DECL_ATTRIBUTE m32r_valid_decl_attribute
  
  #undef TARGET_ASM_FUNCTION_PROLOGUE
  #define TARGET_ASM_FUNCTION_PROLOGUE m32r_output_function_prologue
--- 76,83 ----
  
  
  /* Initialize the GCC target structure.  */
! #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
*************** init_reg_tables ()
*** 250,259 ****
  	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;
--- 250,255 ----
*************** static tree large_ident2;
*** 264,275 ****
  static void
  init_idents PARAMS ((void))
  {
!   if (interrupt_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");
--- 260,267 ----
  static void
  init_idents PARAMS ((void))
  {
!   if (small_ident1 == 0)
      {
        small_ident1 = get_identifier ("small");
        small_ident2 = get_identifier ("__small__");
        medium_ident1 = get_identifier ("medium");
*************** init_idents PARAMS ((void))
*** 279,312 ****
      }
  }
  
! /* Return nonzero if IDENTIFIER is a valid decl attribute.  */
  
! static int
! m32r_valid_decl_attribute (type, attributes, identifier, args)
!      tree type ATTRIBUTE_UNUSED;
!      tree attributes ATTRIBUTE_UNUSED;
!      tree identifier;
       tree args;
  {
!   init_idents ();
  
!   if ((identifier == interrupt_ident1
!        || identifier == interrupt_ident2)
!       && list_length (args) == 0)
!     return 1;
  
!   if ((identifier == model_ident1
!        || identifier == model_ident2)
!       && list_length (args) == 1
!       && (TREE_VALUE (args) == small_ident1
! 	  || TREE_VALUE (args) == small_ident2
! 	  || TREE_VALUE (args) == medium_ident1
! 	  || TREE_VALUE (args) == medium_ident2
! 	  || TREE_VALUE (args) == large_ident1
! 	  || TREE_VALUE (args) == large_ident2))
!     return 1;
  
!   return 0;
  }
  
  /* A C statement or statements to switch to the appropriate
--- 271,313 ----
      }
  }
  
! const struct attribute_spec m32r_attribute_table[] =
! {
!   /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
!   { "interrupt", 0, 0, true,  false, false, NULL },
!   { "model",     1, 1, true,  false, false, m32r_handle_model_attribute },
!   { NULL,        0, 0, false, false, false, NULL }
! };
  
! 
! /* Handle an "model" attribute; arguments as in
!    struct attribute_spec.handler.  */
! static tree
! m32r_handle_model_attribute (node, name, args, flags, no_add_attrs)
!      tree *node ATTRIBUTE_UNUSED;
!      tree name;
       tree args;
+      int flags ATTRIBUTE_UNUSED;
+      bool *no_add_attrs;
  {
!   tree arg;
  
!   init_idents ();
!   arg = TREE_VALUE (args);
  
!   if (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 NULL_TREE;
  }
  
  /* A C statement or statements to switch to the appropriate
*************** m32r_encode_section_info (decl)
*** 370,376 ****
      {
      case VAR_DECL :
      case FUNCTION_DECL :
!       model = lookup_attribute ("model", DECL_MACHINE_ATTRIBUTES (decl));
        break;
      case STRING_CST :
      case CONSTRUCTOR :
--- 371,377 ----
      {
      case VAR_DECL :
      case FUNCTION_DECL :
!       model = lookup_attribute ("model", DECL_ATTRIBUTES (decl));
        break;
      case STRING_CST :
      case CONSTRUCTOR :
*************** m32r_compute_function_type (decl)
*** 1747,1753 ****
      return fn_type;
  
    /* Compute function type.  */
!   fn_type = (lookup_attribute ("interrupt", DECL_MACHINE_ATTRIBUTES (current_function_decl)) != NULL_TREE
  	     ? M32R_FUNCTION_INTERRUPT
  	     : M32R_FUNCTION_NORMAL);
  
--- 1748,1754 ----
      return fn_type;
  
    /* Compute function type.  */
!   fn_type = (lookup_attribute ("interrupt", DECL_ATTRIBUTES (current_function_decl)) != NULL_TREE
  	     ? M32R_FUNCTION_INTERRUPT
  	     : M32R_FUNCTION_NORMAL);
  
diff -rcpN gcc.orig/config/m68hc11/m68hc11.c gcc/config/m68hc11/m68hc11.c
*** gcc.orig/config/m68hc11/m68hc11.c	Fri Aug 10 07:30:20 2001
--- gcc/config/m68hc11/m68hc11.c	Tue Sep 11 21:48:09 2001
*************** static rtx m68hc11_expand_compare PARAMS
*** 66,73 ****
  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));
  
  void create_regs_rtx PARAMS ((void));
  static void m68hc11_add_gc_roots PARAMS ((void));
--- 66,73 ----
  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 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));
*************** const char *m68hc11_soft_reg_count;
*** 209,216 ****
  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_ASM_FUNCTION_EPILOGUE
  #define TARGET_ASM_FUNCTION_EPILOGUE m68hc11_output_function_epilogue
--- 209,216 ----
  static int nb_soft_regs;
  
  /* Initialize the GCC target structure.  */
! #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
*************** m68hc11_initialize_trampoline (tramp, fn
*** 1130,1159 ****
  
  /* 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;
  {
!   if (TREE_CODE (type) != FUNCTION_TYPE
!       && TREE_CODE (type) != FIELD_DECL && TREE_CODE (type) != TYPE_DECL)
!     return 0;
  
!   if (TREE_CODE (type) == FUNCTION_TYPE)
!     {
!       if (is_attribute_p ("interrupt", identifier))
! 	return (args == NULL_TREE);
!       if (is_attribute_p ("trap", identifier))
! 	return (args == NULL_TREE);
      }
  
!   return 0;
  }
  
  /* Define this macro if references to a symbol must be treated
--- 1130,1163 ----
  
  /* Declaration of types.  */
  
! const struct attribute_spec m68hc11_attribute_table[] =
  {
!   /* { 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 }
! };
  
! /* 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)
!     {
!       warning ("`%s' attribute only applies to functions",
! 	       IDENTIFIER_POINTER (name));
!       *no_add_attrs = true;
      }
  
!   return NULL_TREE;
  }
  
  /* Define this macro if references to a symbol must be treated
diff -rcpN gcc.orig/config/mcore/mcore.c gcc/config/mcore/mcore.c
*** gcc.orig/config/mcore/mcore.c	Thu Aug 23 17:54:52 2001
--- gcc/config/mcore/mcore.c	Tue Sep 11 21:48:24 2001
*************** static void       mcore_mark_dllexport  
*** 130,137 ****
  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));
  static void	  mcore_asm_named_section      PARAMS ((const char *,
  							unsigned int));
  
--- 130,137 ----
  static void       mcore_mark_dllimport         PARAMS ((tree));
  static int        mcore_dllexport_p            PARAMS ((tree));
  static int        mcore_dllimport_p            PARAMS ((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));
  
*************** static void	  mcore_asm_named_section   
*** 141,148 ****
  #define TARGET_MERGE_DECL_ATTRIBUTES merge_dllimport_decl_attributes
  #endif
  
! #undef TARGET_VALID_DECL_ATTRIBUTE
! #define TARGET_VALID_DECL_ATTRIBUTE mcore_valid_decl_attribute
  
  struct gcc_target targetm = TARGET_INITIALIZER;
  
--- 141,148 ----
  #define TARGET_MERGE_DECL_ATTRIBUTES merge_dllimport_decl_attributes
  #endif
  
! #undef TARGET_ATTRIBUTE_TABLE
! #define TARGET_ATTRIBUTE_TABLE mcore_attribute_table
  
  struct gcc_target targetm = TARGET_INITIALIZER;
  
*************** mcore_dllexport_p (decl)
*** 3387,3393 ****
        && TREE_CODE (decl) != FUNCTION_DECL)
      return 0;
  
!   return lookup_attribute ("dllexport", DECL_MACHINE_ATTRIBUTES (decl)) != 0;
  }
  
  static int
--- 3387,3393 ----
        && TREE_CODE (decl) != FUNCTION_DECL)
      return 0;
  
!   return lookup_attribute ("dllexport", DECL_ATTRIBUTES (decl)) != 0;
  }
  
  static int
*************** mcore_dllimport_p (decl)
*** 3398,3404 ****
        && TREE_CODE (decl) != FUNCTION_DECL)
      return 0;
  
!   return lookup_attribute ("dllimport", DECL_MACHINE_ATTRIBUTES (decl)) != 0;
  }
  
  /* Cover function to implement ENCODE_SECTION_INFO.  */
--- 3398,3404 ----
        && TREE_CODE (decl) != FUNCTION_DECL)
      return 0;
  
!   return lookup_attribute ("dllimport", DECL_ATTRIBUTES (decl)) != 0;
  }
  
  /* Cover function to implement ENCODE_SECTION_INFO.  */
*************** mcore_encode_section_info (decl)
*** 3449,3472 ****
     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;
  
!   if (is_attribute_p ("dllimport", attr))
!     return 1;
!   
!   if (is_attribute_p ("naked", attr) &&
!       TREE_CODE (decl) == FUNCTION_DECL)
      {
        /* PR14310 - don't complain about lack of return statement
  	 in naked functions.  The solution here is a gross hack
--- 3449,3475 ----
     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.  */
  
! 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 }
! };
  
! /* 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
*************** mcore_valid_decl_attribute (decl, attrib
*** 3483,3493 ****
  	}
        else if (saved_warn_return_type_count)
  	saved_warn_return_type_count = 2;
!       
!       return 1;
      }
  
!   return 0;
  }
  
  /* Cover function for UNIQUE_SECTION.  */
--- 3486,3500 ----
  	}
        else if (saved_warn_return_type_count)
  	saved_warn_return_type_count = 2;
!     }
!   else
!     {
!       warning ("`%s' attribute only applies to functions",
! 	       IDENTIFIER_POINTER (name));
!       *no_add_attrs = true;
      }
  
!   return NULL_TREE;
  }
  
  /* Cover function for UNIQUE_SECTION.  */
*************** mcore_unique_section (decl, reloc)
*** 3530,3536 ****
  int
  mcore_naked_function_p ()
  {
!   return lookup_attribute ("naked", DECL_MACHINE_ATTRIBUTES (current_function_decl)) != NULL_TREE;
  }
  
  static void
--- 3537,3543 ----
  int
  mcore_naked_function_p ()
  {
!   return lookup_attribute ("naked", DECL_ATTRIBUTES (current_function_decl)) != NULL_TREE;
  }
  
  static void
diff -rcpN gcc.orig/config/ns32k/ns32k.c gcc/config/ns32k/ns32k.c
*** gcc.orig/config/ns32k/ns32k.c	Sat Jul  7 15:05:12 2001
--- gcc/config/ns32k/ns32k.c	Wed Sep 19 12:21:26 2001
*************** Boston, MA 02111-1307, USA.  */
*** 37,42 ****
--- 37,43 ----
  #include "tm_p.h"
  #include "target.h"
  #include "target-def.h"
+ #include "toplev.h"
  
  #ifdef OSF_OS
  int ns32k_num_files = 0;
*************** const char *const ns32k_out_reg_names[] 
*** 64,76 ****
  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 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_ASM_FUNCTION_PROLOGUE
  #define TARGET_ASM_FUNCTION_PROLOGUE ns32k_output_function_prologue
--- 65,78 ----
  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 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_ATTRIBUTE_TABLE
! #define TARGET_ATTRIBUTE_TABLE ns32k_attribute_table
  
  #undef TARGET_ASM_FUNCTION_PROLOGUE
  #define TARGET_ASM_FUNCTION_PROLOGUE ns32k_output_function_prologue
*************** symbolic_reference_mentioned_p (op)
*** 1008,1039 ****
    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;
  
    /* Stdcall attribute says callee is responsible for popping arguments
       if they are not variable.  */
!   if (is_attribute_p ("stdcall", identifier))
!     return (args == NULL_TREE);
! 
    /* Cdecl attribute says the callee is a normal C declaration */
!   if (is_attribute_p ("cdecl", identifier))
!     return (args == NULL_TREE);
  
!   return 0;
  }
  
  
--- 1010,1048 ----
    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.  */
!   { "stdcall", 0, 0, false, true,  true,  ns32k_handle_fntype_attribute },
    /* Cdecl attribute says the callee is a normal C declaration */
!   { "cdecl",   0, 0, false, true,  true,  ns32k_handle_fntype_attribute },
!   { NULL,      0, 0, false, false, false, NULL }
! };
  
! /* 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 -rcpN gcc.orig/config/rs6000/rs6000.c gcc/config/rs6000/rs6000.c
*** gcc.orig/config/rs6000/rs6000.c	Tue Aug 28 07:08:07 2001
--- gcc/config/rs6000/rs6000.c	Tue Sep 11 21:48:58 2001
*************** static int constant_pool_expr_1 PARAMS (
*** 127,133 ****
  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 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,
--- 127,134 ----
  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 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,
*************** static char alt_reg_names[][8] =
*** 184,191 ****
  #endif
  
  /* Initialize the GCC target structure.  */
! #undef TARGET_VALID_TYPE_ATTRIBUTE
! #define TARGET_VALID_TYPE_ATTRIBUTE rs6000_valid_type_attribute_p
  
  #undef TARGET_ASM_FUNCTION_PROLOGUE
  #define TARGET_ASM_FUNCTION_PROLOGUE rs6000_output_function_prologue
--- 185,192 ----
  #endif
  
  /* Initialize the GCC target structure.  */
! #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
*************** rs6000_initialize_trampoline (addr, fnad
*** 8124,8151 ****
  }
  
  
! /* 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;
! {
!   if (TREE_CODE (type) != FUNCTION_TYPE
!       && TREE_CODE (type) != FIELD_DECL
!       && TREE_CODE (type) != TYPE_DECL)
!     return 0;
  
!   /* 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);
  
!   return 0;
  }
  
  /* Return a reference suitable for calling a function with the
--- 8125,8158 ----
  }
  
  
! /* Table of valid machine attributes.  */
! const struct attribute_spec rs6000_attribute_table[] =
! {
!   /* { 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 }
! };
  
! /* 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 NULL_TREE;
  }
  
  /* Return a reference suitable for calling a function with the
diff -rcpN gcc.orig/config/sh/sh.c gcc/config/sh/sh.c
*** gcc.orig/config/sh/sh.c	Fri Aug 31 19:44:17 2001
--- gcc/config/sh/sh.c	Wed Sep 19 12:28:06 2001
*************** static int calc_live_regs PARAMS ((int *
*** 154,168 ****
  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));
  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_ASM_FUNCTION_EPILOGUE
  #define TARGET_ASM_FUNCTION_EPILOGUE sh_output_function_epilogue
--- 154,171 ----
  static void mark_use PARAMS ((rtx, rtx *));
  static HOST_WIDE_INT rounded_frame_size PARAMS ((int));
  static rtx mark_constant_pool_use PARAMS ((rtx));
! 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_ATTRIBUTE_TABLE
! #define TARGET_ATTRIBUTE_TABLE sh_attribute_table
  
  #undef TARGET_ASM_FUNCTION_EPILOGUE
  #define TARGET_ASM_FUNCTION_EPILOGUE sh_output_function_epilogue
*************** print_operand (stream, x, code)
*** 269,275 ****
  
  	if ((lookup_attribute
  	     ("interrupt_handler",
! 	      DECL_MACHINE_ATTRIBUTES (current_function_decl)))
  	    != NULL_TREE)
  	  interrupt_handler = 1;
  	else
--- 272,278 ----
  
  	if ((lookup_attribute
  	     ("interrupt_handler",
! 	      DECL_ATTRIBUTES (current_function_decl)))
  	    != NULL_TREE)
  	  interrupt_handler = 1;
  	else
*************** calc_live_regs (count_ptr, live_regs_mas
*** 3952,3958 ****
  
    if ((lookup_attribute
         ("interrupt_handler",
! 	DECL_MACHINE_ATTRIBUTES (current_function_decl)))
        != NULL_TREE)
      interrupt_handler = 1;
    else
--- 3955,3961 ----
  
    if ((lookup_attribute
         ("interrupt_handler",
! 	DECL_ATTRIBUTES (current_function_decl)))
        != NULL_TREE)
      interrupt_handler = 1;
    else
*************** sh_expand_prologue ()
*** 4040,4046 ****
  
    current_function_interrupt
      = lookup_attribute ("interrupt_handler",
! 			DECL_MACHINE_ATTRIBUTES (current_function_decl))
      != NULL_TREE;
  
    /* We have pretend args if we had an object sent partially in registers
--- 4043,4049 ----
  
    current_function_interrupt
      = lookup_attribute ("interrupt_handler",
! 			DECL_ATTRIBUTES (current_function_decl))
      != NULL_TREE;
  
    /* We have pretend args if we had an object sent partially in registers
*************** sh_insert_attributes (node, attributes)
*** 4638,4648 ****
    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:
  
     interrupt_handler -- specifies this function is an interrupt handler.
  
--- 4641,4647 ----
    return;
  }
  
! /* Supported attributes:
  
     interrupt_handler -- specifies this function is an interrupt handler.
  
*************** sh_insert_attributes (node, attributes)
*** 4652,4710 ****
     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;
  {
!   if (TREE_CODE (decl) != FUNCTION_DECL)
!     return 0;
  
!   if (is_attribute_p ("interrupt_handler", attr))
      {
!       return 1;
      }
! 
!   if (is_attribute_p ("sp_switch", attr))
      {
        /* 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;
! 
        /* The argument must be a constant string.  */
!       if (TREE_CODE (TREE_VALUE (args)) != STRING_CST)
! 	return 0;
! 
        sp_switch = gen_rtx_SYMBOL_REF (VOIDmode,
  				      TREE_STRING_POINTER (TREE_VALUE (args)));
-       return 1;
      }
  
!   if (is_attribute_p ("trap_exit", attr))
      {
        /* 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;
! 
        /* The argument must be a constant integer.  */
!       if (TREE_CODE (TREE_VALUE (args)) != INTEGER_CST)
! 	return 0;
! 
        trap_exit = TREE_INT_CST_LOW (TREE_VALUE (args));
-       return 1;
      }
  
!   return 0;
  }
  
  
--- 4651,4760 ----
     trap_exit -- use a trapa to exit an interrupt function instead of
     an rte instruction.  */
  
! const struct attribute_spec sh_attribute_table[] =
  {
!   /* { 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 }
! };
  
! /* 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)
!     {
!       warning ("`%s' attribute only applies to functions",
! 	       IDENTIFIER_POINTER (name));
!       *no_add_attrs = true;
!     }
! 
!   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.  */
!       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.  */
!       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 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.  */
!       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.  */
!       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 NULL_TREE;
  }
  
  
diff -rcpN gcc.orig/config/stormy16/stormy16.c gcc/config/stormy16/stormy16.c
*** gcc.orig/config/stormy16/stormy16.c	Fri Aug 31 19:44:17 2001
--- gcc/config/stormy16/stormy16.c	Sat Sep  8 23:31:34 2001
*************** stormy16_interrupt_function_p ()
*** 1909,1938 ****
    return lookup_attribute ("interrupt", attributes) != NULL_TREE;
  }
  
! /* If defined, a C function which returns nonzero if IDENTIFIER
!    with arguments ARGS is a valid machine specific attribute for TYPE.
!    The attributes in ATTRIBUTES have previously been assigned to TYPE.  */
! #undef TARGET_VALID_TYPE_ATTRIBUTE
! #define TARGET_VALID_TYPE_ATTRIBUTE stormy16_valid_type_attribute
! static int stormy16_valid_type_attribute PARAMS ((tree TYPE,
! 						  tree ATTRIBUTES,
! 						  tree IDENTIFIER,
! 						  tree ARGS));
  
! static int
! stormy16_valid_type_attribute (type, attributes, identifier, args)
!      tree type;
!      tree attributes ATTRIBUTE_UNUSED;
!      tree identifier;
       tree args ATTRIBUTE_UNUSED;
  {
!   if (TREE_CODE (type) != FUNCTION_TYPE)
!     return 0;
!   
!   if (is_attribute_p ("interrupt", identifier))
!     return 1;
  
!   return 0;
  }
  
  struct gcc_target targetm = TARGET_INITIALIZER;
--- 1909,1942 ----
    return lookup_attribute ("interrupt", attributes) != NULL_TREE;
  }
  
! #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 (*node) != FUNCTION_TYPE)
!     {
!       warning ("`%s' attribute only applies to functions",
! 	       IDENTIFIER_POINTER (name));
!       *no_add_attrs = true;
!     }
  
!   return NULL_TREE;
  }
  
  struct gcc_target targetm = TARGET_INITIALIZER;
diff -rcpN gcc.orig/config/stormy16/stormy16.h gcc/config/stormy16/stormy16.h
*** gcc.orig/config/stormy16/stormy16.h	Mon Sep  3 21:07:25 2001
--- gcc/config/stormy16/stormy16.h	Wed Sep  5 08:15:25 2001
*************** enum reg_class
*** 1975,1981 ****
     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.
  
     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
--- 1975,1981 ----
     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_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 -rcpN gcc.orig/config/v850/v850-c.c gcc/config/v850/v850-c.c
*** gcc.orig/config/v850/v850-c.c	Sat Nov 25 00:43:32 2000
--- gcc/config/v850/v850-c.c	Wed Sep 19 12:41:30 2001
*************** Boston, MA 02111-1307, USA.  */
*** 35,41 ****
  
  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));
  
  /* Push a data area onto the stack.  */
  
--- 35,41 ----
  
  static int  pop_data_area          PARAMS ((v850_data_area));
  static int  push_data_area         PARAMS ((v850_data_area));
! static void mark_current_function_as_interrupt PARAMS ((void));
  
  /* Push a data area onto the stack.  */
  
*************** pop_data_area (data_area)
*** 85,91 ****
  
  /* Set the machine specific 'interrupt' attribute on the current function.  */
  
! static int
  mark_current_function_as_interrupt ()
  {
    tree name;
--- 85,91 ----
  
  /* Set the machine specific 'interrupt' attribute on the current function.  */
  
! static void
  mark_current_function_as_interrupt ()
  {
    tree name;
*************** mark_current_function_as_interrupt ()
*** 104,111 ****
        return 0;
      }
    
!   return valid_machine_attribute
!     (name, NULL_TREE, current_function_decl, NULL_TREE);
  }
  
  
--- 104,111 ----
        return 0;
      }
    
!   decl_attributes (&current_function_decl,
! 		   tree_cons (name, NULL_TREE, NULL_TREE), 0);
  }
  
  
diff -rcpN gcc.orig/config/v850/v850.c gcc/config/v850/v850.c
*** gcc.orig/config/v850/v850.c	Thu Jul 26 10:03:41 2001
--- gcc/config/v850/v850.c	Tue Sep 11 21:49:43 2001
*************** static int  const_costs_int          PAR
*** 53,59 ****
  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));
  static void v850_insert_attributes   PARAMS ((tree, tree *));
  
  /* True if the current function has anonymous arguments.  */
--- 53,61 ----
  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));
! 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.  */
*************** static int v850_interrupt_cache_p = FALS
*** 84,91 ****
  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_INSERT_ATTRIBUTES
  #define TARGET_INSERT_ATTRIBUTES v850_insert_attributes
--- 86,93 ----
  static int v850_interrupt_p = FALSE;
  
  /* Initialize the GCC target structure.  */
! #undef TARGET_ATTRIBUTE_TABLE
! #define TARGET_ATTRIBUTE_TABLE v850_attribute_table
  
  #undef TARGET_INSERT_ATTRIBUTES
  #define TARGET_INSERT_ATTRIBUTES v850_insert_attributes
*************** v850_data_area
*** 1978,1990 ****
  v850_get_data_area (decl)
       tree decl;
  {
!   if (lookup_attribute ("sda", DECL_MACHINE_ATTRIBUTES (decl)) != NULL_TREE)
      return DATA_AREA_SDA;
    
!   if (lookup_attribute ("tda", DECL_MACHINE_ATTRIBUTES (decl)) != NULL_TREE)
      return DATA_AREA_TDA;
    
!   if (lookup_attribute ("zda", DECL_MACHINE_ATTRIBUTES (decl)) != NULL_TREE)
      return DATA_AREA_ZDA;
  
    return DATA_AREA_NORMAL;
--- 1980,1992 ----
  v850_get_data_area (decl)
       tree decl;
  {
!   if (lookup_attribute ("sda", DECL_ATTRIBUTES (decl)) != NULL_TREE)
      return DATA_AREA_SDA;
    
!   if (lookup_attribute ("tda", DECL_ATTRIBUTES (decl)) != NULL_TREE)
      return DATA_AREA_TDA;
    
!   if (lookup_attribute ("zda", DECL_ATTRIBUTES (decl)) != NULL_TREE)
      return DATA_AREA_ZDA;
  
    return DATA_AREA_NORMAL;
*************** v850_set_data_area (decl, data_area)
*** 2008,2069 ****
        return;
      }
  
!   DECL_MACHINE_ATTRIBUTES (decl) = tree_cons
!     (name, NULL, DECL_MACHINE_ATTRIBUTES (decl));
  }
  
! /* Return nonzero if ATTR is a valid attribute for DECL.
!    ARGS are the arguments supplied with ATTR.  */
  
! static int
! v850_valid_decl_attribute (decl, unused, attr, args)
!      tree decl;
!      tree unused ATTRIBUTE_UNUSED;
!      tree attr;
!      tree args;
  {
    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;
  
    /* Implement data area attribute.  */
!   if (is_attribute_p ("sda", attr))
      data_area = DATA_AREA_SDA;
!   else if (is_attribute_p ("tda", attr))
      data_area = DATA_AREA_TDA;
!   else if (is_attribute_p ("zda", attr))
      data_area = DATA_AREA_ZDA;
    else
!     return 0;
    
    switch (TREE_CODE (decl))
      {
      case VAR_DECL:
        if (current_function_decl != NULL_TREE)
! 	error_with_decl (decl, "\
  a data area attribute cannot be specified for local variables");
!       
        /* Drop through.  */
  
      case FUNCTION_DECL:
        area = v850_get_data_area (decl);
        if (area != DATA_AREA_NORMAL && data_area != area)
! 	error_with_decl (decl, "\
  data area of '%s' conflicts with previous declaration");
!       
!       return 1;
        
      default:
        break;
      }
!   
!   return 0;
  }
  
  
--- 2010,2101 ----
        return;
      }
  
!   DECL_ATTRIBUTES (decl) = tree_cons
!     (name, NULL, DECL_ATTRIBUTES (decl));
  }
  
! 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 }
! };
  
! /* 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;
!   tree decl = *node;
  
    /* Implement data area attribute.  */
!   if (is_attribute_p ("sda", name))
      data_area = DATA_AREA_SDA;
!   else if (is_attribute_p ("tda", name))
      data_area = DATA_AREA_TDA;
!   else if (is_attribute_p ("zda", name))
      data_area = DATA_AREA_ZDA;
    else
!     abort ();
    
    switch (TREE_CODE (decl))
      {
      case VAR_DECL:
        if (current_function_decl != NULL_TREE)
! 	{
! 	  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, "\
  data area of '%s' conflicts with previous declaration");
! 	  *no_add_attrs = true;
! 	}
!       break;
        
      default:
        break;
      }
! 
!   return NULL_TREE;
  }
  
  
*************** v850_interrupt_function_p (func)
*** 2083,2095 ****
    if (TREE_CODE (func) != FUNCTION_DECL)
      return 0;
  
!   a = lookup_attribute ("interrupt_handler", DECL_MACHINE_ATTRIBUTES (func));
    if (a != NULL_TREE)
      ret = 1;
  
    else
      {
!       a = lookup_attribute ("interrupt", DECL_MACHINE_ATTRIBUTES (func));
        ret = a != NULL_TREE;
      }
  
--- 2115,2127 ----
    if (TREE_CODE (func) != FUNCTION_DECL)
      return 0;
  
!   a = lookup_attribute ("interrupt_handler", DECL_ATTRIBUTES (func));
    if (a != NULL_TREE)
      ret = 1;
  
    else
      {
!       a = lookup_attribute ("interrupt", DECL_ATTRIBUTES (func));
        ret = a != NULL_TREE;
      }
  
diff -rcpN gcc.orig/cp/class.c gcc/cp/class.c
*** gcc.orig/cp/class.c	Fri Aug 31 10:16:37 2001
--- gcc/cp/class.c	Tue Sep 18 15:15:55 2001
*************** finish_struct (t, attributes)
*** 5282,5288 ****
       as necessary.  */
    unreverse_member_declarations (t);
  
!   cplus_decl_attributes (&t, attributes, NULL_TREE, 0);
  
    /* Nadger the current location so that diagnostics point to the start of
       the struct, not the end.  */
--- 5282,5288 ----
       as necessary.  */
    unreverse_member_declarations (t);
  
!   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 -rcpN gcc.orig/cp/cp-tree.h gcc/cp/cp-tree.h
*** gcc.orig/cp/cp-tree.h	Fri Aug 24 18:20:44 2001
--- gcc/cp/cp-tree.h	Wed Sep  5 09:36:21 2001
*************** extern tree grokbitfield			PARAMS ((tree
*** 3733,3739 ****
  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 tree constructor_name_full		PARAMS ((tree));
  extern tree constructor_name			PARAMS ((tree));
  extern void defer_fn            		PARAMS ((tree));
--- 3733,3739 ----
  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, int));
  extern tree constructor_name_full		PARAMS ((tree));
  extern tree constructor_name			PARAMS ((tree));
  extern void defer_fn            		PARAMS ((tree));
*************** extern tree walk_tree_without_duplicates
*** 4207,4213 ****
  							 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 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 *));
--- 4207,4213 ----
  							 walk_tree_fn,
  							 void *));
  extern tree copy_tree_r                         PARAMS ((tree *, int *, void *));
! 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 -rcpN gcc.orig/cp/decl.c gcc/cp/decl.c
*** gcc.orig/cp/decl.c	Wed Sep  5 07:47:53 2001
--- gcc/cp/decl.c	Tue Sep 18 16:00:54 2001
*************** Boston, MA 02111-1307, USA.  */
*** 45,51 ****
  #include "tm_p.h"
  #include "target.h"
  
! extern int (*valid_lang_attribute) PARAMS ((tree, tree, tree, tree));
  
  #ifndef BOOL_TYPE_SIZE
  /* `bool' has size and alignment `1', on all platforms.  */
--- 45,51 ----
  #include "tm_p.h"
  #include "target.h"
  
! extern const struct attribute_spec *lang_attribute_table;
  
  #ifndef BOOL_TYPE_SIZE
  /* `bool' has size and alignment `1', on all platforms.  */
*************** duplicate_decls (newdecl, olddecl)
*** 3438,3444 ****
  
    /* 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)
      = (*targetm.merge_decl_attributes) (olddecl, newdecl);
  
    if (TREE_CODE (newdecl) == TEMPLATE_DECL)
--- 3438,3444 ----
  
    /* Copy all the DECL_... slots specified in the new decl
       except for any that we copy here from the old type.  */
!   DECL_ATTRIBUTES (newdecl)
      = (*targetm.merge_decl_attributes) (olddecl, newdecl);
  
    if (TREE_CODE (newdecl) == TEMPLATE_DECL)
*************** duplicate_decls (newdecl, olddecl)
*** 3746,3752 ****
  
    /* NEWDECL contains the merged attribute lists.
       Update OLDDECL to be the same.  */
!   DECL_MACHINE_ATTRIBUTES (olddecl) = DECL_MACHINE_ATTRIBUTES (newdecl);
  
    return 1;
  }
--- 3746,3752 ----
  
    /* NEWDECL contains the merged attribute lists.
       Update OLDDECL to be the same.  */
!   DECL_ATTRIBUTES (olddecl) = DECL_ATTRIBUTES (newdecl);
  
    return 1;
  }
*************** init_decl_processing ()
*** 6493,6499 ****
    /* Show we use EH for cleanups.  */
    using_eh_for_cleanups ();
  
!   valid_lang_attribute = cp_valid_lang_attribute;
  
    /* Maintain consistency.  Perhaps we should just complain if they
       say -fwritable-strings?  */
--- 6493,6499 ----
    /* Show we use EH for cleanups.  */
    using_eh_for_cleanups ();
  
!   lang_attribute_table = cp_attribute_table;
  
    /* Maintain consistency.  Perhaps we should just complain if they
       say -fwritable-strings?  */
*************** shadow_tag (declspecs)
*** 6986,6992 ****
        if (TYPE_FIELDS (t))
  	{
  	  tree decl = grokdeclarator (NULL_TREE, declspecs, NORMAL, 0,
! 				      NULL_TREE);
  	  finish_anon_union (decl);
  	}
      }
--- 6986,6992 ----
        if (TYPE_FIELDS (t))
  	{
  	  tree decl = grokdeclarator (NULL_TREE, declspecs, NORMAL, 0,
! 				      NULL);
  	  finish_anon_union (decl);
  	}
      }
*************** groktypename (typename)
*** 7002,7008 ****
      return typename;
    return grokdeclarator (TREE_VALUE (typename),
  			 TREE_PURPOSE (typename),
! 			 TYPENAME, 0, NULL_TREE);
  }
  
  /* Decode a declarator in an ordinary declaration or data definition.
--- 7002,7008 ----
      return typename;
    return grokdeclarator (TREE_VALUE (typename),
  			 TREE_PURPOSE (typename),
! 			 TYPENAME, 0, NULL);
  }
  
  /* Decode a declarator in an ordinary declaration or data definition.
*************** start_decl (declarator, declspecs, initi
*** 7031,7037 ****
    tree context;
    extern int have_extern_spec;
    extern int used_extern_spec;
-   tree attrlist;
  
  #if 0
    /* See code below that used this.  */
--- 7031,7036 ----
*************** start_decl (declarator, declspecs, initi
*** 7046,7058 ****
        used_extern_spec = 1;
      }
  
!   if (attributes || prefix_attributes)
!     attrlist = build_tree_list (attributes, prefix_attributes);
!   else
!     attrlist = NULL_TREE;
  
    decl = grokdeclarator (declarator, declspecs, NORMAL, initialized,
! 			 attrlist);
  
    if (decl == NULL_TREE || TREE_CODE (decl) == VOID_TYPE)
      return NULL_TREE;
--- 7045,7054 ----
        used_extern_spec = 1;
      }
  
!   attributes = chainon (attributes, prefix_attributes);
  
    decl = grokdeclarator (declarator, declspecs, NORMAL, initialized,
! 			 &attributes);
  
    if (decl == NULL_TREE || TREE_CODE (decl) == VOID_TYPE)
      return NULL_TREE;
*************** start_decl (declarator, declspecs, initi
*** 7119,7125 ****
      }
  
    /* Set attributes here so if duplicate decl, will have proper attributes.  */
!   cplus_decl_attributes (&decl, attributes, prefix_attributes, 0);
  
    if (context && COMPLETE_TYPE_P (complete_type (context)))
      {
--- 7115,7121 ----
      }
  
    /* Set attributes here so if duplicate decl, will have proper attributes.  */
!   cplus_decl_attributes (&decl, attributes, 0);
  
    if (context && COMPLETE_TYPE_P (complete_type (context)))
      {
*************** start_handler_parms (declspecs, declarat
*** 8482,8488 ****
    if (declspecs)
      {
        decl = grokdeclarator (declarator, declspecs, CATCHPARM,
! 			     1, NULL_TREE);
        if (decl == NULL_TREE)
  	error ("invalid catch parameter");
      }
--- 8478,8484 ----
    if (declspecs)
      {
        decl = grokdeclarator (declarator, declspecs, CATCHPARM,
! 			     1, NULL);
        if (decl == NULL_TREE)
  	error ("invalid catch parameter");
      }
*************** check_special_function_return_type (sfk,
*** 9425,9432 ****
       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.
  
     In the TYPENAME case, DECLARATOR is really an abstract declarator.
     It may also be so in the PARM case, for a prototype where the
--- 9421,9429 ----
       BITFIELD for a field with specified width.
     INITIALIZED is 1 if the decl has an initializer.
  
!    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
*************** grokdeclarator (declarator, declspecs, d
*** 9464,9470 ****
       tree declarator;
       enum decl_context decl_context;
       int initialized;
!      tree attrlist;
  {
    RID_BIT_TYPE specbits;
    int nclasses = 0;
--- 9461,9467 ----
       tree declarator;
       enum decl_context decl_context;
       int initialized;
!      tree *attrlist;
  {
    RID_BIT_TYPE specbits;
    int nclasses = 0;
*************** grokdeclarator (declarator, declspecs, d
*** 9487,9493 ****
    int bitfield = 0;
  #if 0
    /* See the code below that used this.  */
!   tree decl_machine_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.  */
--- 9484,9490 ----
    int bitfield = 0;
  #if 0
    /* See the code below that used this.  */
!   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.  */
*************** grokdeclarator (declarator, declspecs, d
*** 9506,9513 ****
    tree raises = NULL_TREE;
    int template_count = 0;
    tree in_namespace = NULL_TREE;
!   tree inner_attrs;
!   int ignore_attrs;
  
    RIDBIT_RESET_ALL (specbits);
    if (decl_context == FUNCDEF)
--- 9503,9509 ----
    tree raises = NULL_TREE;
    int template_count = 0;
    tree in_namespace = NULL_TREE;
!   tree returned_attrs = NULL_TREE;
  
    RIDBIT_RESET_ALL (specbits);
    if (decl_context == FUNCDEF)
*************** grokdeclarator (declarator, declspecs, d
*** 9598,9621 ****
  		   cp_finish_decl so we can get the variable
  		   initialized...  */
  
! 		tree attributes, prefix_attributes;
  
  		*next = TREE_OPERAND (decl, 0);
  		init = CALL_DECLARATOR_PARMS (decl);
  
  		if (attrlist)
  		  {
! 		    attributes = TREE_PURPOSE (attrlist);
! 		    prefix_attributes = TREE_VALUE (attrlist);
  		  }
  		else
  		  {
  		    attributes = NULL_TREE;
- 		    prefix_attributes = NULL_TREE;
  		  }
  
  		decl = start_decl (declarator, declspecs, 1,
! 				   attributes, prefix_attributes);
  		decl_type_access_control (decl);
  		if (decl)
  		  {
--- 9594,9615 ----
  		   cp_finish_decl so we can get the variable
  		   initialized...  */
  
! 		tree attributes;
  
  		*next = TREE_OPERAND (decl, 0);
  		init = CALL_DECLARATOR_PARMS (decl);
  
  		if (attrlist)
  		  {
! 		    attributes = *attrlist;
  		  }
  		else
  		  {
  		    attributes = NULL_TREE;
  		  }
  
  		decl = start_decl (declarator, declspecs, 1,
! 				   attributes, NULL_TREE);
  		decl_type_access_control (decl);
  		if (decl)
  		  {
*************** grokdeclarator (declarator, declspecs, d
*** 9953,9959 ****
  	      type = TREE_TYPE (t);
  #if 0
  	      /* See the code below that used this.  */
! 	      decl_machine_attr = DECL_MACHINE_ATTRIBUTES (id);
  #endif
  	      typedef_decl = t;
  	    }
--- 9947,9953 ----
  	      type = TREE_TYPE (t);
  #if 0
  	      /* See the code below that used this.  */
! 	      decl_attr = DECL_ATTRIBUTES (id);
  #endif
  	      typedef_decl = t;
  	    }
*************** grokdeclarator (declarator, declspecs, d
*** 10312,10320 ****
       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)
      {
--- 10306,10311 ----
*************** grokdeclarator (declarator, declspecs, d
*** 10363,10390 ****
  	    }
  	}
  
-       /* 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;
  	    declarator = TREE_VALUE (declarator);
  	  }
  	  break;
  
--- 10354,10383 ----
  	    }
  	}
  
        switch (TREE_CODE (declarator))
  	{
  	case TREE_LIST:
  	  {
  	    /* We encode a declarator with embedded attributes using
! 	       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;
  
*************** grokdeclarator (declarator, declspecs, d
*** 10883,10897 ****
  	}
      }
  
!   /* See the comment for the TREE_LIST case, above.  */
!   if (inner_attrs)
      {
!       if (! ignore_attrs)
! 	decl_attributes (&type, inner_attrs, 0);
!       else if (attrlist)
! 	TREE_VALUE (attrlist) = chainon (inner_attrs, TREE_VALUE (attrlist));
        else
! 	attrlist = build_tree_list (NULL_TREE, inner_attrs);
      }
  
    /* Now TYPE has the actual type.  */
--- 10876,10887 ----
  	}
      }
  
!   if (returned_attrs)
      {
!       if (attrlist)
! 	*attrlist = chainon (returned_attrs, *attrlist);
        else
! 	attrlist = &returned_attrs;
      }
  
    /* Now TYPE has the actual type.  */
*************** friend declaration requires class-key, i
*** 11302,11309 ****
  	      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);
  #endif
  
  	    /* [class.conv.ctor]
--- 11292,11299 ----
  	      return decl;
  #if 0
  	    /* This clobbers the attrs stored in `decl' from `attrlist'.  */
! 	    /* The decl and setting of decl_attr is also turned off.  */
! 	    decl = build_decl_attribute_variant (decl, decl_attr);
  #endif
  
  	    /* [class.conv.ctor]
*************** friend declaration requires class-key, i
*** 11401,11407 ****
                    }
                
                  t = do_friend (ctype, declarator, decl,
!               		       last_function_parms, attrlist, flags, quals,
                		       funcdef_flag);
                }
              if (t && funcdef_flag)
--- 11391,11397 ----
                    }
                
                  t = do_friend (ctype, declarator, decl,
!               		       last_function_parms, *attrlist, flags, quals,
                		       funcdef_flag);
                }
              if (t && funcdef_flag)
*************** grokparms (first_parm)
*** 11838,11844 ****
          break;
  
        decl = grokdeclarator (TREE_VALUE (decl), TREE_PURPOSE (decl),
! 		     PARM, init != NULL_TREE, NULL_TREE);
        if (! decl || TREE_TYPE (decl) == error_mark_node)
          continue;
  
--- 11828,11834 ----
          break;
  
        decl = grokdeclarator (TREE_VALUE (decl), TREE_PURPOSE (decl),
! 		     PARM, init != NULL_TREE, NULL);
        if (! decl || TREE_TYPE (decl) == error_mark_node)
          continue;
  
*************** start_function (declspecs, declarator, a
*** 13269,13275 ****
      }
    else
      {
!       decl1 = grokdeclarator (declarator, declspecs, FUNCDEF, 1, NULL_TREE);
        /* 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;
--- 13259,13265 ----
      }
    else
      {
!       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;
*************** start_function (declspecs, declarator, a
*** 13554,13560 ****
    pushlevel (0);
    current_binding_level->parm_flag = 1;
  
!   cplus_decl_attributes (&decl1, NULL_TREE, attrs, 0);
  
    /* Promote the value to int before returning it.  */
    if (c_promoting_integer_type_p (restype))
--- 13544,13550 ----
    pushlevel (0);
    current_binding_level->parm_flag = 1;
  
!   cplus_decl_attributes (&decl1, attrs, 0);
  
    /* Promote the value to int before returning it.  */
    if (c_promoting_integer_type_p (restype))
*************** start_method (declspecs, declarator, att
*** 14056,14062 ****
       tree declarator, declspecs, attrlist;
  {
    tree fndecl = grokdeclarator (declarator, declspecs, MEMFUNCDEF, 0,
! 				attrlist);
  
    /* Something too ugly to handle.  */
    if (fndecl == NULL_TREE)
--- 14046,14052 ----
       tree declarator, declspecs, attrlist;
  {
    tree fndecl = grokdeclarator (declarator, declspecs, MEMFUNCDEF, 0,
! 				&attrlist);
  
    /* Something too ugly to handle.  */
    if (fndecl == NULL_TREE)
diff -rcpN gcc.orig/cp/decl.h gcc/cp/decl.h
*** gcc.orig/cp/decl.h	Wed Jan 26 20:51:34 2000
--- gcc/cp/decl.h	Wed Sep  5 08:43:53 2001
*************** enum decl_context
*** 31,37 ****
  };
  
  /* We need this in here to get the decl_context definition.  */
! 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.  */
--- 31,37 ----
  };
  
  /* We need this in here to get the decl_context definition.  */
! 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 -rcpN gcc.orig/cp/decl2.c gcc/cp/decl2.c
*** gcc.orig/cp/decl2.c	Wed Sep  5 07:47:55 2001
--- gcc/cp/decl2.c	Wed Sep 19 09:39:03 2001
*************** grokfield (declarator, declspecs, init, 
*** 1531,1537 ****
        && TREE_CHAIN (init) == NULL_TREE)
      init = NULL_TREE;
  
!   value = grokdeclarator (declarator, declspecs, FIELD, init != 0, attrlist);
    if (! value || value == error_mark_node)
      /* friend or constructor went bad.  */
      return value;
--- 1531,1537 ----
        && TREE_CHAIN (init) == NULL_TREE)
      init = NULL_TREE;
  
!   value = grokdeclarator (declarator, declspecs, FIELD, init != 0, &attrlist);
    if (! value || value == error_mark_node)
      /* friend or constructor went bad.  */
      return value;
*************** grokfield (declarator, declspecs, init, 
*** 1628,1635 ****
      value = push_template_decl (value);
  
    if (attrlist)
!     cplus_decl_attributes (&value, TREE_PURPOSE (attrlist),
! 			   TREE_VALUE (attrlist), 0);
  
    if (TREE_CODE (value) == VAR_DECL)
      {
--- 1628,1634 ----
      value = push_template_decl (value);
  
    if (attrlist)
!     cplus_decl_attributes (&value, attrlist, 0);
  
    if (TREE_CODE (value) == VAR_DECL)
      {
*************** grokbitfield (declarator, declspecs, wid
*** 1679,1685 ****
       tree declarator, declspecs, width;
  {
    register tree value = grokdeclarator (declarator, declspecs, BITFIELD,
! 					0, NULL_TREE);
  
    if (! value) return NULL_TREE; /* friends went bad.  */
  
--- 1678,1684 ----
       tree declarator, declspecs, width;
  {
    register tree value = grokdeclarator (declarator, declspecs, BITFIELD,
! 					0, NULL);
  
    if (! value) return NULL_TREE; /* friends went bad.  */
  
*************** tree
*** 1735,1741 ****
  grokoptypename (declspecs, declarator)
       tree declspecs, declarator;
  {
!   tree t = grokdeclarator (declarator, declspecs, TYPENAME, 0, NULL_TREE);
    return mangle_conv_op_name_for_type (t);
  }
  
--- 1734,1740 ----
  grokoptypename (declspecs, declarator)
       tree declspecs, declarator;
  {
!   tree t = grokdeclarator (declarator, declspecs, TYPENAME, 0, NULL);
    return mangle_conv_op_name_for_type (t);
  }
  
*************** grok_function_init (decl, init)
*** 1824,1831 ****
  }
  
  void
! cplus_decl_attributes (decl, attributes, prefix_attributes, flags)
!      tree *decl, attributes, prefix_attributes;
       int flags;
  {
    if (*decl == NULL_TREE || *decl == void_type_node)
--- 1823,1830 ----
  }
  
  void
! cplus_decl_attributes (decl, attributes, flags)
!      tree *decl, attributes;
       int flags;
  {
    if (*decl == NULL_TREE || *decl == void_type_node)
*************** cplus_decl_attributes (decl, attributes,
*** 1834,1840 ****
    if (TREE_CODE (*decl) == TEMPLATE_DECL)
      decl = &DECL_TEMPLATE_RESULT (*decl);
  
!   decl_attributes (decl, chainon (attributes, prefix_attributes), flags);
  
    if (TREE_CODE (*decl) == TYPE_DECL)
      SET_IDENTIFIER_TYPE_VALUE (DECL_NAME (*decl), TREE_TYPE (*decl));
--- 1833,1839 ----
    if (TREE_CODE (*decl) == TEMPLATE_DECL)
      decl = &DECL_TEMPLATE_RESULT (*decl);
  
!   decl_attributes (decl, attributes, flags);
  
    if (TREE_CODE (*decl) == TYPE_DECL)
      SET_IDENTIFIER_TYPE_VALUE (DECL_NAME (*decl), TREE_TYPE (*decl));
*************** import_export_class (ctype)
*** 2371,2387 ****
    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)))
      import_export = -1;
!   else if ((*targetm.valid_type_attribute) (ctype,
! 					    TYPE_ATTRIBUTES (ctype),
! 					    get_identifier ("dllexport"),
! 					    NULL_TREE)
! 	   && lookup_attribute ("dllexport", TYPE_ATTRIBUTES (ctype)))
      import_export = 1;
  
    /* If we got -fno-implicit-templates, we import template classes that
--- 2370,2378 ----
    if (CLASSTYPE_INTERFACE_ONLY (ctype))
      return;
  
!   if (lookup_attribute ("dllimport", TYPE_ATTRIBUTES (ctype)))
      import_export = -1;
!   else if (lookup_attribute ("dllexport", TYPE_ATTRIBUTES (ctype)))
      import_export = 1;
  
    /* If we got -fno-implicit-templates, we import template classes that
diff -rcpN gcc.orig/cp/friend.c gcc/cp/friend.c
*** gcc.orig/cp/friend.c	Fri Jul 13 20:06:43 2001
--- gcc/cp/friend.c	Wed Sep  5 09:38:04 2001
*************** do_friend (ctype, declarator, decl, parm
*** 309,315 ****
       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;
--- 309,314 ----
*************** do_friend (ctype, declarator, decl, parm
*** 435,453 ****
       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);
  
    return decl;
  }
--- 434,441 ----
       handle them in start_decl_1, but since this is a friend decl start_decl_1
       never gets to see it.  */
  
    /* Set attributes here so if duplicate decl, will have proper attributes.  */
!   cplus_decl_attributes (&decl, attrlist, 0);
  
    return decl;
  }
diff -rcpN gcc.orig/cp/parse.y gcc/cp/parse.y
*** gcc.orig/cp/parse.y	Fri Aug 24 18:20:44 2001
--- gcc/cp/parse.y	Wed Sep  5 09:38:19 2001
*************** parse_field (declarator, attributes, asm
*** 164,170 ****
       tree declarator, attributes, asmspec, init;
  {
    tree d = grokfield (declarator, current_declspecs, init, asmspec,
! 		      build_tree_list (attributes, prefix_attributes));
    decl_type_access_control (d);
    return d;
  }
--- 164,170 ----
       tree declarator, attributes, asmspec, init;
  {
    tree d = grokfield (declarator, current_declspecs, init, asmspec,
! 		      chainon (attributes, prefix_attributes));
    decl_type_access_control (d);
    return d;
  }
*************** parse_bitfield (declarator, attributes, 
*** 182,188 ****
       tree declarator, attributes, width;
  {
    tree d = grokbitfield (declarator, current_declspecs, width);
!   cplus_decl_attributes (&d, attributes, prefix_attributes, 0);
    decl_type_access_control (d);
    return d;
  }
--- 182,188 ----
       tree declarator, attributes, width;
  {
    tree d = grokbitfield (declarator, current_declspecs, width);
!   cplus_decl_attributes (&d, chainon (attributes, prefix_attributes), 0);
    decl_type_access_control (d);
    return d;
  }
*************** component_decl_1:
*** 2639,2649 ****
  		  $$ = NULL_TREE; 
  		}
  	| notype_declarator maybeasm maybe_attribute maybe_init
! 		{ $$ = grokfield ($$, NULL_TREE, $4, $2,
! 				  build_tree_list ($3, NULL_TREE)); }
  	| constructor_declarator maybeasm maybe_attribute maybe_init
! 		{ $$ = grokfield ($$, NULL_TREE, $4, $2,
! 				  build_tree_list ($3, NULL_TREE)); }
  	| ':' expr_no_commas
  		{ $$ = grokbitfield (NULL_TREE, NULL_TREE, $2); }
  	| error
--- 2639,2647 ----
  		  $$ = NULL_TREE; 
  		}
  	| notype_declarator maybeasm maybe_attribute maybe_init
! 		{ $$ = grokfield ($$, NULL_TREE, $4, $2, $3); }
  	| constructor_declarator maybeasm maybe_attribute maybe_init
! 		{ $$ = grokfield ($$, NULL_TREE, $4, $2, $3); }
  	| ':' expr_no_commas
  		{ $$ = grokbitfield (NULL_TREE, NULL_TREE, $2); }
  	| error
*************** component_decl_1:
*** 2661,2670 ****
  		{ tree specs, attrs;
  		  split_specs_attrs ($1.t, &specs, &attrs);
  		  $$ = grokfield ($2, specs, $5, $3,
! 				  build_tree_list ($4, attrs)); }
  	| component_constructor_declarator maybeasm maybe_attribute maybe_init
! 		{ $$ = grokfield ($$, NULL_TREE, $4, $2,
! 				  build_tree_list ($3, NULL_TREE)); }
  	| using_decl
  		{ $$ = do_class_using_decl ($1); }
  
--- 2659,2667 ----
  		{ tree specs, attrs;
  		  split_specs_attrs ($1.t, &specs, &attrs);
  		  $$ = grokfield ($2, specs, $5, $3,
! 				  chainon ($4, attrs)); }
  	| component_constructor_declarator maybeasm maybe_attribute maybe_init
! 		{ $$ = grokfield ($$, NULL_TREE, $4, $2, $3); }
  	| using_decl
  		{ $$ = do_class_using_decl ($1); }
  
diff -rcpN gcc.orig/cp/pt.c gcc/cp/pt.c
*** gcc.orig/cp/pt.c	Wed Sep  5 07:47:55 2001
--- gcc/cp/pt.c	Wed Sep  5 09:35:43 2001
*************** process_template_parm (list, next)
*** 1929,1935 ****
        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);
  
        /* [temp.param]
  
--- 1929,1935 ----
        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);
  
        /* [temp.param]
  
*************** void
*** 9357,9363 ****
  do_decl_instantiation (declspecs, declarator, storage)
       tree declspecs, declarator, storage;
  {
!   tree decl = grokdeclarator (declarator, declspecs, NORMAL, 0, NULL_TREE);
    tree result = NULL_TREE;
    int extern_p = 0;
  
--- 9357,9363 ----
  do_decl_instantiation (declspecs, declarator, storage)
       tree declspecs, declarator, storage;
  {
!   tree decl = grokdeclarator (declarator, declspecs, NORMAL, 0, NULL);
    tree result = NULL_TREE;
    int extern_p = 0;
  
diff -rcpN gcc.orig/cp/tree.c gcc/cp/tree.c
*** gcc.orig/cp/tree.c	Mon Aug 27 07:45:26 2001
--- gcc/cp/tree.c	Wed Sep 19 10:13:30 2001
*************** static tree verify_stmt_tree_r PARAMS ((
*** 50,55 ****
--- 50,59 ----
  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.  */
*************** pod_type_p (t)
*** 2182,2289 ****
    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;
! {
!   if (is_attribute_p ("java_interface", attr_name))
!     {
!       if (attr_args != NULL_TREE
! 	  || decl != NULL_TREE
! 	  || ! CLASS_TYPE_P (type)
! 	  || ! TYPE_FOR_JAVA (type))
! 	{
! 	  error ("`java_interface' attribute can only be applied to Java class definitions");
! 	  return 0;
! 	}
!       TYPE_JAVA_INTERFACE (type) = 1;
!       return 1;
      }
!   if (is_attribute_p ("com_interface", attr_name))
!     {
!       static int warned;
!       if (attr_args != NULL_TREE
! 	  || decl != NULL_TREE
! 	  || ! CLASS_TYPE_P (type)
! 	  || type != TYPE_MAIN_VARIANT (type))
! 	{
! 	  warning ("`com_interface' attribute can only be applied to class definitions");
! 	  return 0;
! 	}
  
!       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))
      {
!       tree initp_expr = (attr_args ? TREE_VALUE (attr_args): NULL_TREE);
!       int pri;
  
!       if (initp_expr)
! 	STRIP_NOPS (initp_expr);
  	  
!       if (!initp_expr || TREE_CODE (initp_expr) != INTEGER_CST)
! 	{
! 	  error ("requested init_priority is not an integer constant");
! 	  return 0;
! 	}
  
!       pri = TREE_INT_CST_LOW (initp_expr);
  	
!       type = strip_array_types (type);
  
!       if (decl == NULL_TREE
! 	  || TREE_CODE (decl) != VAR_DECL
! 	  || ! TREE_STATIC (decl)
! 	  || DECL_EXTERNAL (decl)
! 	  || (TREE_CODE (type) != RECORD_TYPE
! 	      && TREE_CODE (type) != UNION_TYPE)
! 	  /* Static objects in functions are initialized the
! 	     first time control passes through that
! 	     function. This is not precise enough to pin down an
! 	     init_priority value, so don't allow it. */
! 	  || current_function_decl) 
! 	{
! 	  error ("can only use init_priority attribute on file-scope definitions of objects of class type");
! 	  return 0;
! 	}
! 
!       if (pri > MAX_INIT_PRIORITY || pri <= 0)
! 	{
! 	  error ("requested init_priority is out of range");
! 	  return 0;
! 	}
  
!       /* Check for init_priorities that are reserved for
! 	 language and runtime support implementations.*/
!       if (pri <= MAX_RESERVED_INIT_PRIORITY)
! 	{
! 	  warning 
! 	    ("requested init_priority is reserved for internal use");
! 	}
  
!       if (SUPPORTS_INIT_PRIORITY)
! 	{
! 	  DECL_INIT_PRIORITY (decl) = pri;
! 	  return 1;
! 	}
!       else
! 	{
! 	  error ("init_priority attribute is not supported on this platform");
! 	  return 0;
! 	}
      }
  
!   return 0;
  }
  
  /* Return a new PTRMEM_CST of the indicated TYPE.  The MEMBER is the
--- 2186,2330 ----
    return 1;
  }
  
! /* Table of valid C++ attributes.  */
! const struct attribute_spec cp_attribute_table[] =
! {
!   /* { 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))
!     {
!       error ("`%s' attribute can only be applied to Java class definitions",
! 	     IDENTIFIER_POINTER (name));
!       *no_add_attrs = true;
!       return NULL_TREE;
      }
!   if (!(flags & (int) ATTR_FLAG_TYPE_IN_PLACE))
!     *node = build_type_copy (*node);
!   TYPE_JAVA_INTERFACE (*node) = 1;
  
!   return NULL_TREE;
! }
! 
! /* Handle a "com_interface" attribute; arguments as in
!    struct attribute_spec.handler.  */
! static tree
! handle_com_interface_attribute (node, name, args, flags, no_add_attrs)
!      tree *node;
!      tree name;
!      tree args ATTRIBUTE_UNUSED;
!      int flags ATTRIBUTE_UNUSED;
!      bool *no_add_attrs;
! {
!   static int warned;
! 
!   *no_add_attrs = true;
! 
!   if (DECL_P (*node)
!       || !CLASS_TYPE_P (*node)
!       || *node != TYPE_MAIN_VARIANT (*node))
      {
!       warning ("`%s' attribute can only be applied to class definitions",
! 	       IDENTIFIER_POINTER (name));
!       return NULL_TREE;
!     }
! 
!   if (!warned++)
!     warning ("`%s' is obsolete; g++ vtables are now COM-compatible by default",
! 	     IDENTIFIER_POINTER (name));
! 
!   return NULL_TREE;
! }
! 
! /* Handle an "init_priority" attribute; arguments as in
!    struct attribute_spec.handler.  */
! static tree
! handle_init_priority_attribute (node, name, args, flags, no_add_attrs)
!      tree *node;
!      tree name;
!      tree args;
!      int flags ATTRIBUTE_UNUSED;
!      bool *no_add_attrs;
! {
!   tree initp_expr = TREE_VALUE (args);
!   tree decl = *node;
!   tree type = TREE_TYPE (decl);
!   int pri;
  
!   STRIP_NOPS (initp_expr);
  	  
!   if (!initp_expr || TREE_CODE (initp_expr) != INTEGER_CST)
!     {
!       error ("requested init_priority is not an integer constant");
!       *no_add_attrs = true;
!       return NULL_TREE;
!     }
  
!   pri = TREE_INT_CST_LOW (initp_expr);
  	
!   type = strip_array_types (type);
  
!   if (decl == NULL_TREE
!       || TREE_CODE (decl) != VAR_DECL
!       || !TREE_STATIC (decl)
!       || DECL_EXTERNAL (decl)
!       || (TREE_CODE (type) != RECORD_TYPE
! 	  && TREE_CODE (type) != UNION_TYPE)
!       /* Static objects in functions are initialized the
! 	 first time control passes through that
! 	 function. This is not precise enough to pin down an
! 	 init_priority value, so don't allow it. */
!       || current_function_decl) 
!     {
!       error ("can only use `%s' attribute on file-scope definitions of objects of class type",
! 	     IDENTIFIER_POINTER (name));
!       *no_add_attrs = true;
!       return NULL_TREE;
!     }
  
!   if (pri > MAX_INIT_PRIORITY || pri <= 0)
!     {
!       error ("requested init_priority is out of range");
!       *no_add_attrs = true;
!       return NULL_TREE;
!     }
  
!   /* Check for init_priorities that are reserved for
!      language and runtime support implementations.*/
!   if (pri <= MAX_RESERVED_INIT_PRIORITY)
!     {
!       warning 
! 	("requested init_priority is reserved for internal use");
      }
  
!   if (SUPPORTS_INIT_PRIORITY)
!     {
!       DECL_INIT_PRIORITY (decl) = pri;
!       return NULL_TREE;
!     }
!   else
!     {
!       error ("`%s' attribute is not supported on this platform",
! 	     IDENTIFIER_POINTER (name));
!       *no_add_attrs = true;
!       return NULL_TREE;
!     }
  }
  
  /* Return a new PTRMEM_CST of the indicated TYPE.  The MEMBER is the
diff -rcpN gcc.orig/doc/c-tree.texi gcc/doc/c-tree.texi
*** gcc.orig/doc/c-tree.texi	Fri Aug  3 11:43:06 2001
--- gcc/doc/c-tree.texi	Wed Sep  5 08:12:12 2001
*************** to the same declaration or type, or @cod
*** 1660,1673 ****
  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})
  This macro returns the attributes on the declaration @var{decl}.
  @end deftypefn
  
--- 1660,1670 ----
  further attributes in the list.
  
  Attributes may be attached to declarations and to types; these
! 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 -rcpN gcc.orig/doc/extend.texi gcc/doc/extend.texi
*** gcc.orig/doc/extend.texi	Mon Aug 20 17:53:29 2001
--- gcc/doc/extend.texi	Mon Sep 10 21:32:38 2001
*************** language.  Some details may vary for C++
*** 2449,2454 ****
--- 2449,2462 ----
  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},
*************** defined is not complete until after the 
*** 2520,2528 ****
  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
  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
--- 2528,2535 ----
  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), 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
*************** ignored.
*** 2597,2607 ****
  
  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
  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
  most sense if you are familiar with the formal specification of
  declarators in the ISO C standard.
  
--- 2604,2614 ----
  
  An attribute specifier list may appear at the start of a nested
  declarator.  At present, there are some limitations in this usage: the
! 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 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.
  
*************** char *__attribute__((aligned(8))) *f;
*** 2642,2649 ****
  
  @noindent
  specifies the type ``pointer to 8-byte-aligned pointer to @code{char}''.
! Note again that this describes intended future semantics, not current
! implementation.
  
  @node Function Prototypes
  @section Prototypes and Old-Style Function Definitions
--- 2649,2674 ----
  
  @noindent
  specifies the type ``pointer to 8-byte-aligned pointer to @code{char}''.
! 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 -rcpN gcc.orig/doc/tm.texi gcc/doc/tm.texi
*** gcc.orig/doc/tm.texi	Fri Aug 31 10:16:46 2001
--- gcc/doc/tm.texi	Tue Sep 18 15:29:25 2001
*************** through the macros defined in the @file{
*** 48,53 ****
--- 48,54 ----
  * 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
  
*************** macros for which the default definition 
*** 70,77 ****
  
  /* @r{Initialize the GCC target structure.}  */
  
! #undef TARGET_VALID_TYPE_ATTRIBUTE
! #define TARGET_VALID_TYPE_ATTRIBUTE @var{machine}_valid_type_attribute_p
  
  struct gcc_target targetm = TARGET_INITIALIZER;
  @end smallexample
--- 71,78 ----
  
  /* @r{Initialize the GCC target structure.}  */
  
! #undef TARGET_COMP_TYPE_ATTRIBUTES
! #define TARGET_COMP_TYPE_ATTRIBUTES @var{machine}_comp_type_attributes
  
  struct gcc_target targetm = TARGET_INITIALIZER;
  @end smallexample
*************** This describes the stack layout and call
*** 2528,2534 ****
  * Caller Saves::
  * Function Entry::
  * Profiling::
! * Inlining and Tail Calls::
  @end menu
  
  @node Frame Layout
--- 2529,2535 ----
  * Caller Saves::
  * Function Entry::
  * Profiling::
! * Tail Calls::
  @end menu
  
  @node Frame Layout
*************** after the function returns.
*** 3222,3228 ****
  @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.
  
  @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
--- 3223,3229 ----
  @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_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
*************** profiling when the frame pointer is omit
*** 4204,4221 ****
  
  @end table
  
! @node Inlining and Tail Calls
! @subsection Permitting inlining and tail calls
! @cindex inlining
  
  @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
--- 4205,4215 ----
  
  @end table
  
! @node Tail Calls
! @subsection Permitting tail calls
! @cindex tail calls
  
  @table @code
  @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
*************** Generate one or more insns to set @var{e
*** 8030,8035 ****
--- 8024,8108 ----
  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
*************** other compilers for the same target.  In
*** 8403,8409 ****
  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.
  
  Preprocessor macros that appear on pragma lines are not expanded.  All
  @samp{#pragma} directives that do not match any registered pragma are
--- 8476,8482 ----
  definition of target-specific pragmas for GCC@.
  
  If the pragma can be implemented by attributes then you should consider
! 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
*************** pack value of zero resets the behaviour 
*** 8483,8556 ****
  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
--- 8556,8562 ----
diff -rcpN gcc.orig/ggc-common.c gcc/ggc-common.c
*** gcc.orig/ggc-common.c	Sat Sep  1 09:49:53 2001
--- gcc/ggc-common.c	Wed Sep  5 08:12:12 2001
*************** ggc_mark_trees ()
*** 374,380 ****
  	  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));
  	  if (DECL_RTL_SET_P (t))
  	    ggc_mark_rtx (DECL_RTL (t));
  	  ggc_mark_rtx (DECL_LIVE_RANGE_RTL (t));
--- 374,380 ----
  	  ggc_mark_tree (DECL_INITIAL (t));
  	  ggc_mark_tree (DECL_ABSTRACT_ORIGIN (t));
  	  ggc_mark_tree (DECL_SECTION_NAME (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 -rcpN gcc.orig/integrate.c gcc/integrate.c
*** gcc.orig/integrate.c	Sat Sep  1 09:49:53 2001
--- gcc/integrate.c	Wed Sep  5 08:12:12 2001
*************** Software Foundation, 59 Temple Place - S
*** 42,47 ****
--- 42,48 ----
  #include "loop.h"
  #include "params.h"
  #include "ggc.h"
+ #include "target.h"
  
  #include "obstack.h"
  #define	obstack_chunk_alloc	xmalloc
*************** extern struct obstack *function_maybeper
*** 63,74 ****
     ? (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.  */
--- 64,69 ----
*************** typedef struct initial_value_struct {
*** 82,87 ****
--- 77,84 ----
    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));
*************** get_label_from_map (map, i)
*** 130,135 ****
--- 127,164 ----
    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
*************** function_cannot_inline_p (fndecl)
*** 250,258 ****
  
    /* 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))
      return N_("function with target specific attribute(s) cannot be inlined");
  
    return NULL;
--- 279,286 ----
  
    /* 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 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 -rcpN gcc.orig/print-tree.c gcc/print-tree.c
*** gcc.orig/print-tree.c	Wed Aug 22 20:36:35 2001
--- gcc/print-tree.c	Wed Sep  5 08:12:12 2001
***************
*** 1,5 ****
  /* Prints out tree in human readable form - GNU C-compiler
!    Copyright (C) 1990, 1991, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000
     Free Software Foundation, Inc.
  
  This file is part of GCC.
--- 1,5 ----
  /* Prints out tree in human readable form - GNU C-compiler
!    Copyright (C) 1990, 1991, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001
     Free Software Foundation, Inc.
  
  This file is part of GCC.
*************** print_node (file, prefix, node, indent)
*** 433,440 ****
  	}
  
        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, "abstract_origin",
  			DECL_ABSTRACT_ORIGIN (node), indent + 4);
  
--- 433,440 ----
  	}
  
        print_node_brief (file, "context", DECL_CONTEXT (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 -rcpN gcc.orig/target-def.h gcc/target-def.h
*** gcc.orig/target-def.h	Fri Aug 31 10:16:31 2001
--- gcc/target-def.h	Wed Sep  5 22:14:16 2001
*************** Foundation, 59 Temple Place - Suite 330,
*** 107,117 ****
  /* 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_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
  
  /* In builtins.c.  */
  #define TARGET_INIT_BUILTINS default_init_builtins
--- 107,117 ----
  /* All in tree.c.  */
  #define TARGET_MERGE_DECL_ATTRIBUTES merge_decl_attributes
  #define TARGET_MERGE_TYPE_ATTRIBUTES merge_type_attributes
! #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
*************** Foundation, 59 Temple Place - Suite 330,
*** 129,139 ****
    TARGET_SCHED,					\
    TARGET_MERGE_DECL_ATTRIBUTES,			\
    TARGET_MERGE_TYPE_ATTRIBUTES,			\
!   TARGET_VALID_DECL_ATTRIBUTE,			\
!   TARGET_VALID_TYPE_ATTRIBUTE,			\
    TARGET_COMP_TYPE_ATTRIBUTES,			\
    TARGET_SET_DEFAULT_TYPE_ATTRIBUTES,		\
    TARGET_INSERT_ATTRIBUTES,			\
    TARGET_INIT_BUILTINS,				\
    TARGET_EXPAND_BUILTIN,			\
    TARGET_SECTION_TYPE_FLAGS,			\
--- 129,139 ----
    TARGET_SCHED,					\
    TARGET_MERGE_DECL_ATTRIBUTES,			\
    TARGET_MERGE_TYPE_ATTRIBUTES,			\
!   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 -rcpN gcc.orig/target.h gcc/target.h
*** gcc.orig/target.h	Fri Aug 31 10:16:31 2001
--- gcc/target.h	Wed Sep  5 22:14:34 2001
*************** struct gcc_target
*** 121,137 ****
    /* 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));
  
    /* Return zero if the attributes on TYPE1 and TYPE2 are incompatible,
       one if they are compatible and two if they are nearly compatible
--- 121,128 ----
    /* Given two types, merge their attributes and return the result.  */
    tree (* merge_type_attributes) PARAMS ((tree, tree));
  
!   /* 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
*************** struct gcc_target
*** 143,148 ****
--- 134,143 ----
  
    /* 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 -rcpN gcc.orig/testsuite/g++.dg/ext/attrib1.C gcc/testsuite/g++.dg/ext/attrib1.C
*** gcc.orig/testsuite/g++.dg/ext/attrib1.C	Thu Jan  1 00:00:00 1970
--- gcc/testsuite/g++.dg/ext/attrib1.C	Tue Sep 18 12:41:08 2001
***************
*** 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 -rcpN gcc.orig/tree.c gcc/tree.c
*** gcc.orig/tree.c	Wed Aug 29 09:24:22 2001
--- gcc/tree.c	Wed Sep  5 22:15:38 2001
*************** build_expr_wfl (node, file, line, col)
*** 2622,2635 ****
    return wfl;
  }
  
! /* Return a declaration like DDECL except that its DECL_MACHINE_ATTRIBUTE
     is ATTRIBUTE.  */
  
  tree
  build_decl_attribute_variant (ddecl, attribute)
       tree ddecl, attribute;
  {
!   DECL_MACHINE_ATTRIBUTES (ddecl) = attribute;
    return ddecl;
  }
  
--- 2622,2635 ----
    return wfl;
  }
  
! /* Return a declaration like DDECL except that its DECL_ATTRIBUTES
     is ATTRIBUTE.  */
  
  tree
  build_decl_attribute_variant (ddecl, attribute)
       tree ddecl, attribute;
  {
!   DECL_ATTRIBUTES (ddecl) = attribute;
    return ddecl;
  }
  
*************** build_type_attribute_variant (ttype, att
*** 2687,2705 ****
    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
--- 2687,2692 ----
*************** default_insert_attributes (decl, attr_pt
*** 2727,2842 ****
  {
  }
  
! /* 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;
  {
!   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;
!     }
! 
!   return 0;
  }
  
  /* Return non-zero if IDENT is a valid name for attribute ATTR,
--- 2714,2733 ----
  {
  }
  
! /* Default value of targetm.attribute_table that is empty.  */
! const struct attribute_spec default_target_attribute_table[] =
  {
!   { NULL, 0, 0, false, false, false, NULL }
! };
  
! /* 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,
*************** is_attribute_p (attr, ident)
*** 2890,2896 ****
  
  /* 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.  */
  
  tree
  lookup_attribute (attr_name, list)
--- 2781,2789 ----
  
  /* 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 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)
*************** merge_attributes (a1, a2)
*** 2932,2950 ****
        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;
! 	      }
  	}
      }
    return attributes;
--- 2825,2853 ----
        else
  	{
  	  /* Pick the longest list, and hang on the other list.  */
  
  	  if (list_length (a1) < list_length (a2))
  	    attributes = a2, a2 = a1;
  
  	  for (; a2 != 0; a2 = TREE_CHAIN (a2))
! 	    {
! 	      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;
*************** tree
*** 2968,2975 ****
  merge_decl_attributes (olddecl, newdecl)
       tree olddecl, newdecl;
  {
!   return merge_attributes (DECL_MACHINE_ATTRIBUTES (olddecl),
! 			   DECL_MACHINE_ATTRIBUTES (newdecl));
  }
  
  #ifdef TARGET_DLLIMPORT_DECL_ATTRIBUTES
--- 2871,2878 ----
  merge_decl_attributes (olddecl, newdecl)
       tree olddecl, newdecl;
  {
!   return merge_attributes (DECL_ATTRIBUTES (olddecl),
! 			   DECL_ATTRIBUTES (newdecl));
  }
  
  #ifdef TARGET_DLLIMPORT_DECL_ATTRIBUTES
*************** merge_dllimport_decl_attributes (old, ne
*** 2991,2998 ****
    tree a;
    int delete_dllimport_p;
  
!   old = DECL_MACHINE_ATTRIBUTES (old);
!   new = DECL_MACHINE_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
--- 2894,2901 ----
    tree a;
    int delete_dllimport_p;
  
!   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
*************** attribute_list_contained (l1, l2)
*** 3368,3375 ****
  
    for (; t2 != 0; t2 = TREE_CHAIN (t2))
      {
!       tree attr
! 	= lookup_attribute (IDENTIFIER_POINTER (TREE_PURPOSE (t2)), l1);
  
        if (attr == 0)
  	return 0;
--- 3271,3285 ----
  
    for (; t2 != 0; t2 = TREE_CHAIN (t2))
      {
!       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 -rcpN gcc.orig/tree.h gcc/tree.h
*** gcc.orig/tree.h	Sat Sep  1 09:49:53 2001
--- gcc/tree.h	Tue Sep 18 15:04:54 2001
***************
*** 1,5 ****
  /* Front-end tree definitions for GNU compiler.
!    Copyright (C) 1989, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000
     Free Software Foundation, Inc.
  
  This file is part of GCC.
--- 1,5 ----
  /* Front-end tree definitions for GNU compiler.
!    Copyright (C) 1989, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001
     Free Software Foundation, Inc.
  
  This file is part of GCC.
*************** struct tree_type
*** 1339,1347 ****
      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 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)
--- 1339,1346 ----
      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 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)
*************** struct tree_decl
*** 1756,1762 ****
    tree abstract_origin;
    tree assembler_name;
    tree section_name;
!   tree machine_attributes;
    rtx rtl;	/* RTL representation for object.  */
    rtx live_range_rtl;
  
--- 1755,1761 ----
    tree abstract_origin;
    tree assembler_name;
    tree section_name;
!   tree attributes;
    rtx rtl;	/* RTL representation for object.  */
    rtx live_range_rtl;
  
*************** extern tree make_tree			PARAMS ((tree, r
*** 2071,2084 ****
  extern tree build_type_attribute_variant PARAMS ((tree, tree));
  extern tree build_decl_attribute_variant PARAMS ((tree, tree));
  
  /* 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 *));
  
  /* Split a list of declspecs and attributes into two.  */
  
--- 2070,2151 ----
  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_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.  */
  

-- 
Joseph S. Myers
jsm28@cam.ac.uk


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]