OSDN Git Service

* attribs.c (strip_attrs): Remove.
[pf3gnuchains/gcc-fork.git] / gcc / attribs.c
index 7cb1172..6f11181 100644 (file)
@@ -1,6 +1,6 @@
 /* Functions dealing with attribute handling, used by most front ends.
    Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
-   2002 Free Software Foundation, Inc.
+   2002, 2003, 2004 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -21,168 +21,54 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 
 #include "config.h"
 #include "system.h"
+#include "coretypes.h"
+#include "tm.h"
 #include "tree.h"
 #include "flags.h"
 #include "toplev.h"
 #include "output.h"
 #include "rtl.h"
 #include "ggc.h"
-#include "expr.h"
 #include "tm_p.h"
-#include "obstack.h"
 #include "cpplib.h"
 #include "target.h"
+#include "langhooks.h"
 
-static void init_attributes            PARAMS ((void));
+static void init_attributes (void);
 
-/* Table of the tables of attributes (common, format, language, machine)
+/* Table of the tables of attributes (common, language, format, machine)
    searched.  */
 static const struct attribute_spec *attribute_tables[4];
 
 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_noinline_attribute  PARAMS ((tree *, tree, tree, int,
-                                                bool *));
-static tree handle_used_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_malloc_attribute    PARAMS ((tree *, tree, tree, int,
-                                                bool *));
-static tree handle_no_limit_stack_attribute PARAMS ((tree *, tree, tree, int,
-                                                    bool *));
-static tree handle_pure_attribute      PARAMS ((tree *, tree, tree, int,
-                                                bool *));
-static tree handle_deprecated_attribute        PARAMS ((tree *, tree, tree, int,
-                                                bool *));
-static tree handle_vector_size_attribute PARAMS ((tree *, tree, tree, int,
-                                                 bool *));
-static tree vector_size_helper PARAMS ((tree, tree));
-
-/* 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 },
-  { "noinline",               0, 0, true,  false, false,
-                             handle_noinline_attribute },
-  { "used",                   0, 0, true,  false, false,
-                             handle_used_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, false,  true, false,
-                             handle_mode_attribute },
-  { "section",                1, 1, true,  false, false,
-                             handle_section_attribute },
-  { "aligned",                0, 1, false, false, false,
-                             handle_aligned_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 },
-  { "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 },
-  { "deprecated",             0, 0, false, false, false,
-                             handle_deprecated_attribute },
-  { "vector_size",           1, 1, false, true, false,
-                             handle_vector_size_attribute },
-  { NULL,                     0, 0, false, false, false, NULL }
-};
-
 /* Default empty table of attributes.  */
 static const struct attribute_spec empty_attribute_table[] =
 {
   { NULL, 0, 0, false, false, false, NULL }
 };
 
-/* Table of machine-independent attributes for checking formats, if used.  */
-const struct attribute_spec *format_attribute_table = empty_attribute_table;
-
-/* Table of machine-independent attributes for a particular language.  */
-const struct attribute_spec *lang_attribute_table = empty_attribute_table;
-
-/* Flag saying whether common language attributes are to be supported.  */
-int lang_attribute_common = 1;
-
 /* Initialize attribute tables, and make some sanity checks
    if --enable-checking.  */
 
 static void
-init_attributes ()
+init_attributes (void)
 {
-#ifdef ENABLE_CHECKING
-  int i;
-#endif
+  size_t i;
 
-  attribute_tables[0]
-    = lang_attribute_common ? c_common_attribute_table : empty_attribute_table;
-  attribute_tables[1] = lang_attribute_table;
-  attribute_tables[2] = format_attribute_table;
+  attribute_tables[0] = lang_hooks.common_attribute_table;
+  attribute_tables[1] = lang_hooks.attribute_table;
+  attribute_tables[2] = lang_hooks.format_attribute_table;
   attribute_tables[3] = targetm.attribute_table;
 
+  /* Translate NULL pointers to pointers to the empty table.  */
+  for (i = 0; i < ARRAY_SIZE (attribute_tables); i++)
+    if (attribute_tables[i] == NULL)
+      attribute_tables[i] = empty_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++)
+  for (i = 0; i < ARRAY_SIZE (attribute_tables); i++)
     {
       int j;
 
@@ -191,56 +77,47 @@ init_attributes ()
          /* 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 ();
+         
+         gcc_assert (!(name[0] == '_' && name[1] == '_'
+                       && name[len - 1] == '_' && name[len - 2] == '_'));
+         
          /* 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 ();
+         gcc_assert (attribute_tables[i][j].min_length >= 0);
+         
+         gcc_assert (attribute_tables[i][j].max_length == -1
+                     || (attribute_tables[i][j].max_length
+                         >= attribute_tables[i][j].min_length));
+         
          /* An attribute cannot require both a DECL and a TYPE.  */
-         if (attribute_tables[i][j].decl_required
-             && attribute_tables[i][j].type_required)
-           abort ();
+         gcc_assert (!attribute_tables[i][j].decl_required
+                     || !attribute_tables[i][j].type_required);
+         
          /* 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 ();
+         gcc_assert (!attribute_tables[i][j].function_type_required
+                     || attribute_tables[i][j].type_required);
        }
     }
 
   /* Check that each name occurs just once in each table.  */
-  for (i = 0;
-       i < (int) (sizeof (attribute_tables) / sizeof (attribute_tables[0]));
-       i++)
+  for (i = 0; i < ARRAY_SIZE (attribute_tables); 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 ();
+         gcc_assert (strcmp (attribute_tables[i][j].name,
+                             attribute_tables[i][k].name));
     }
   /* Check that no name occurs in more than one table.  */
-  for (i = 0;
-       i < (int) (sizeof (attribute_tables) / sizeof (attribute_tables[0]));
-       i++)
+  for (i = 0; i < ARRAY_SIZE (attribute_tables); i++)
     {
-      int j, k, l;
+      size_t j, k, l;
 
-      for (j = i + 1;
-          j < ((int) (sizeof (attribute_tables)
-                      / sizeof (attribute_tables[0])));
-          j++)
+      for (j = i + 1; j < ARRAY_SIZE (attribute_tables); j++)
        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 ();
+           gcc_assert (strcmp (attribute_tables[i][k].name,
+                               attribute_tables[j][l].name));
     }
 #endif
 
@@ -254,16 +131,10 @@ init_attributes ()
    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).  If
-   ATTR_FLAG_BUILT_IN is not set and *NODE is a DECL, then also consider
-   whether there might be some default attributes to apply to this DECL;
-   if so, decl_attributes will be called recursively with those attributes
-   and ATTR_FLAG_BUILT_IN set.  */
+   a decl attribute to the declaration rather than to its type).  */
 
 tree
-decl_attributes (node, attributes, flags)
-     tree *node, attributes;
-     int flags;
+decl_attributes (tree *node, tree attributes, int flags)
 {
   tree a;
   tree returned_attrs = NULL_TREE;
@@ -271,11 +142,7 @@ decl_attributes (node, attributes, flags)
   if (!attributes_initialized)
     init_attributes ();
 
-  (*targetm.insert_attributes) (*node, &attributes);
-
-  if (DECL_P (*node) && TREE_CODE (*node) == FUNCTION_DECL
-      && !(flags & (int) ATTR_FLAG_BUILT_IN))
-    insert_default_attributes (*node);
+  targetm.insert_attributes (*node, &attributes);
 
   for (a = attributes; a; a = TREE_CHAIN (a))
     {
@@ -284,12 +151,10 @@ decl_attributes (node, attributes, flags)
       tree *anode = node;
       const struct attribute_spec *spec = NULL;
       bool no_add_attrs = 0;
-      int i;
+      tree fn_ptr_tmp = NULL_TREE;
+      size_t i;
 
-      for (i = 0;
-          i < ((int) (sizeof (attribute_tables)
-                      / sizeof (attribute_tables[0])));
-          i++)
+      for (i = 0; i < ARRAY_SIZE (attribute_tables); i++)
        {
          int j;
 
@@ -355,9 +220,18 @@ decl_attributes (node, attributes, flags)
              && (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);
+             /* OK, this is a bit convoluted.  We can't just make a copy
+                of the pointer type and modify its TREE_TYPE, because if
+                we change the attributes of the target type the pointer
+                type needs to have a different TYPE_MAIN_VARIANT.  So we
+                pull out the target type now, frob it as appropriate, and
+                rebuild the pointer type later.
+
+                This would all be simpler if attributes were part of the
+                declarator, grumble grumble.  */
+             fn_ptr_tmp = TREE_TYPE (*anode);
+             anode = &fn_ptr_tmp;
+             flags &= ~(int) ATTR_FLAG_TYPE_IN_PLACE;
            }
          else if (flags & (int) ATTR_FLAG_FUNCTION_NEXT)
            {
@@ -382,7 +256,9 @@ decl_attributes (node, attributes, flags)
 
       /* Layout the decl in case anything changed.  */
       if (spec->type_required && DECL_P (*node)
-         && TREE_CODE (*node) == VAR_DECL)
+         && (TREE_CODE (*node) == VAR_DECL
+             || TREE_CODE (*node) == PARM_DECL
+             || TREE_CODE (*node) == RESULT_DECL))
        {
          /* Force a recalculation of mode and size.  */
          DECL_MODE (*node) = VOIDmode;
@@ -415,1019 +291,47 @@ decl_attributes (node, attributes, flags)
              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);
+               {
+                 TYPE_ATTRIBUTES (*anode) = tree_cons (name, args, old_attrs);
+                 /* If this is the main variant, also push the attributes
+                    out to the other variants.  */
+                 if (*anode == TYPE_MAIN_VARIANT (*anode))
+                   {
+                     tree variant;
+                     for (variant = *anode; variant;
+                          variant = TYPE_NEXT_VARIANT (variant))
+                       {
+                         if (TYPE_ATTRIBUTES (variant) == old_attrs)
+                           TYPE_ATTRIBUTES (variant)
+                             = TYPE_ATTRIBUTES (*anode);
+                         else if (!lookup_attribute
+                                  (spec->name, TYPE_ATTRIBUTES (variant)))
+                           TYPE_ATTRIBUTES (variant) = tree_cons
+                             (name, args, TYPE_ATTRIBUTES (variant));
+                       }
+                   }
+               }
              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 "noinline" attribute; arguments as in
-   struct attribute_spec.handler.  */
-
-static tree
-handle_noinline_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_UNINLINABLE (*node) = 1;
-  else
-    {
-      warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
-      *no_add_attrs = true;
-    }
-
-  return NULL_TREE;
-}
-
-/* Handle a "used" attribute; arguments as in
-   struct attribute_spec.handler.  */
-
-static tree
-handle_used_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)
-    TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (*node))
-      = TREE_USED (*node) = 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
+      if (fn_ptr_tmp)
        {
-         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 type = *node;
-
-  *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;
-       }
-
-      /* Change this type to have 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
-       *node = typefm;
-        /* No need to layout the type here.  The caller should do this.  */
-    }
-
-  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 "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;
-}
-
-/* Handle a "deprecated" attribute; arguments as in
-   struct attribute_spec.handler.  */
-   
-static tree
-handle_deprecated_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_TREE;
-  int warn = 0;
-  const char *what = NULL;
-  
-  if (DECL_P (*node))
-    {
-      tree decl = *node;
-      type = TREE_TYPE (decl);
-      
-      if (TREE_CODE (decl) == TYPE_DECL
-         || TREE_CODE (decl) == PARM_DECL
-         || TREE_CODE (decl) == VAR_DECL
-         || TREE_CODE (decl) == FUNCTION_DECL
-         || TREE_CODE (decl) == FIELD_DECL)
-       TREE_DEPRECATED (decl) = 1;
-      else
-       warn = 1;
-    }
-  else if (TYPE_P (*node))
-    {
-      if (!(flags & (int) ATTR_FLAG_TYPE_IN_PLACE))
-       *node = build_type_copy (*node);
-      TREE_DEPRECATED (*node) = 1;
-      type = *node;
-    }
-  else
-    warn = 1;
-  
-  if (warn)
-    {
-      *no_add_attrs = true;
-      if (type && TYPE_NAME (type))
-       {
-         if (TREE_CODE (TYPE_NAME (type)) == IDENTIFIER_NODE)
-           what = IDENTIFIER_POINTER (TYPE_NAME (*node));
-         else if (TREE_CODE (TYPE_NAME (type)) == TYPE_DECL
-                  && DECL_NAME (TYPE_NAME (type)))
-           what = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (type)));
-       }
-      if (what)
-       warning ("`%s' attribute ignored for `%s'",
-                 IDENTIFIER_POINTER (name), what);
-      else
-       warning ("`%s' attribute ignored", 
-                     IDENTIFIER_POINTER (name));
-    }
-
-  return NULL_TREE;
-}
-
-/* Handle a "vector_size" attribute; arguments as in
-   struct attribute_spec.handler.  */
-
-static tree
-handle_vector_size_attribute (node, name, args, flags, no_add_attrs)
-     tree *node;
-     tree name;
-     tree args;
-     int flags ATTRIBUTE_UNUSED;
-     bool *no_add_attrs;
-{
-  unsigned HOST_WIDE_INT vecsize, nunits;
-  enum machine_mode mode, orig_mode, new_mode;
-  tree type = *node, new_type;
-
-  *no_add_attrs = true;
-
-  if (! host_integerp (TREE_VALUE (args), 1))
-    {
-      warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
-      return NULL_TREE;
-    }
-
-  /* Get the vector size (in bytes).  */
-  vecsize = tree_low_cst (TREE_VALUE (args), 1);
-
-  /* We need to provide for vector pointers, vector arrays, and
-     functions returning vectors.  For example:
-
-       __attribute__((vector_size(16))) short *foo;
-
-     In this case, the mode is SI, but the type being modified is
-     HI, so we need to look further.  */
-
-  while (POINTER_TYPE_P (type)
-        || TREE_CODE (type) == FUNCTION_TYPE
-        || TREE_CODE (type) == ARRAY_TYPE)
-    type = TREE_TYPE (type);
-
-  /* Get the mode of the type being modified.  */
-  orig_mode = TYPE_MODE (type);
-
-  if (TREE_CODE (type) == RECORD_TYPE
-      || (GET_MODE_CLASS (orig_mode) != MODE_FLOAT
-         && GET_MODE_CLASS (orig_mode) != MODE_INT)
-      || ! host_integerp (TYPE_SIZE_UNIT (type), 1))
-    {
-      error ("invalid vector type for attribute `%s'",
-            IDENTIFIER_POINTER (name));
-      return NULL_TREE;
-    }
-
-  /* Calculate how many units fit in the vector.  */
-  nunits = vecsize / tree_low_cst (TYPE_SIZE_UNIT (type), 1);
-
-  /* Find a suitably sized vector.  */
-  new_mode = VOIDmode;
-  for (mode = GET_CLASS_NARROWEST_MODE (GET_MODE_CLASS (orig_mode) == MODE_INT
-                                       ? MODE_VECTOR_INT
-                                       : MODE_VECTOR_FLOAT);
-       mode != VOIDmode;
-       mode = GET_MODE_WIDER_MODE (mode))
-    if (vecsize == GET_MODE_SIZE (mode)
-       && nunits == (unsigned HOST_WIDE_INT) GET_MODE_NUNITS (mode))
-      {
-       new_mode = mode;
-       break;
-      }
-
-  if (new_mode == VOIDmode)
-    error ("no vector mode with the size and type specified could be found");
-  else
-    {
-      new_type = type_for_mode (new_mode, TREE_UNSIGNED (type));
-      if (!new_type)
-       error ("no vector mode with the size and type specified could be found");
-      else
-       /* Build back pointers if needed.  */
-       *node = vector_size_helper (*node, new_type);
-    }
-    
-  return NULL_TREE;
-}
-
-/* HACK.  GROSS.  This is absolutely disgusting.  I wish there was a
-   better way.
-
-   If we requested a pointer to a vector, build up the pointers that
-   we stripped off while looking for the inner type.  Similarly for
-   return values from functions.
-
-   The argument "type" is the top of the chain, and "bottom" is the
-   new type which we will point to.  */
-
-static tree
-vector_size_helper (type, bottom)
-     tree type, bottom;
-{
-  tree inner, outer;
-
-  if (POINTER_TYPE_P (type))
-    {
-      inner = vector_size_helper (TREE_TYPE (type), bottom);
-      outer = build_pointer_type (inner);
-    }
-  else if (TREE_CODE (type) == ARRAY_TYPE)
-    {
-      inner = vector_size_helper (TREE_TYPE (type), bottom);
-      outer = build_array_type (inner, TYPE_VALUES (type));
-    }
-  else if (TREE_CODE (type) == FUNCTION_TYPE)
-    {
-      inner = vector_size_helper (TREE_TYPE (type), bottom);
-      outer = build_function_type (inner, TYPE_VALUES (type));
-    }
-  else
-    return bottom;
-  
-  TREE_READONLY (outer) = TREE_READONLY (type);
-  TREE_THIS_VOLATILE (outer) = TREE_THIS_VOLATILE (type);
-
-  return outer;
-}
-
-/* Split SPECS_ATTRS, a list of declspecs and prefix attributes, into two
-   lists.  SPECS_ATTRS may also be just a typespec (eg: RECORD_TYPE).
-
-   The head of the declspec list is stored in DECLSPECS.
-   The head of the attribute list is stored in PREFIX_ATTRIBUTES.
-
-   Note that attributes in SPECS_ATTRS are stored in the TREE_PURPOSE of
-   the list elements.  We drop the containing TREE_LIST nodes and link the
-   resulting attributes together the way decl_attributes expects them.  */
-
-void
-split_specs_attrs (specs_attrs, declspecs, prefix_attributes)
-     tree specs_attrs;
-     tree *declspecs, *prefix_attributes;
-{
-  tree t, s, a, next, specs, attrs;
-
-  /* This can happen after an __extension__ in pedantic mode.  */
-  if (specs_attrs != NULL_TREE 
-      && TREE_CODE (specs_attrs) == INTEGER_CST)
-    {
-      *declspecs = NULL_TREE;
-      *prefix_attributes = NULL_TREE;
-      return;
-    }
-
-  /* This can happen in c++ (eg: decl: typespec initdecls ';').  */
-  if (specs_attrs != NULL_TREE
-      && TREE_CODE (specs_attrs) != TREE_LIST)
-    {
-      *declspecs = specs_attrs;
-      *prefix_attributes = NULL_TREE;
-      return;
-    }
-
-  /* Remember to keep the lists in the same order, element-wise.  */
-
-  specs = s = NULL_TREE;
-  attrs = a = NULL_TREE;
-  for (t = specs_attrs; t; t = next)
-    {
-      next = TREE_CHAIN (t);
-      /* Declspecs have a non-NULL TREE_VALUE.  */
-      if (TREE_VALUE (t) != NULL_TREE)
-       {
-         if (specs == NULL_TREE)
-           specs = s = t;
-         else
-           {
-             TREE_CHAIN (s) = t;
-             s = t;
-           }
-       }
-      /* The TREE_PURPOSE may also be empty in the case of
-        __attribute__(()).  */
-      else if (TREE_PURPOSE (t) != NULL_TREE)
-       {
-         if (attrs == NULL_TREE)
-           attrs = a = TREE_PURPOSE (t);
+         /* Rebuild the function pointer type and put it in the
+            appropriate place.  */
+         fn_ptr_tmp = build_pointer_type (fn_ptr_tmp);
+         if (DECL_P (*node))
+           TREE_TYPE (*node) = fn_ptr_tmp;
          else
            {
-             TREE_CHAIN (a) = TREE_PURPOSE (t);
-             a = TREE_PURPOSE (t);
+             gcc_assert (TREE_CODE (*node) == POINTER_TYPE);
+             *node = fn_ptr_tmp;
            }
-         /* More attrs can be linked here, move A to the end.  */
-         while (TREE_CHAIN (a) != NULL_TREE)
-           a = TREE_CHAIN (a);
        }
     }
 
-  /* Terminate the lists.  */
-  if (s != NULL_TREE)
-    TREE_CHAIN (s) = NULL_TREE;
-  if (a != NULL_TREE)
-    TREE_CHAIN (a) = NULL_TREE;
-
-  /* All done.  */
-  *declspecs = specs;
-  *prefix_attributes = attrs;
-}
-
-/* Strip attributes from SPECS_ATTRS, a list of declspecs and attributes.
-   This function is used by the parser when a rule will accept attributes
-   in a particular position, but we don't want to support that just yet.
-
-   A warning is issued for every ignored attribute.  */
-
-tree
-strip_attrs (specs_attrs)
-     tree specs_attrs;
-{
-  tree specs, attrs;
-
-  split_specs_attrs (specs_attrs, &specs, &attrs);
-
-  while (attrs)
-    {
-      warning ("`%s' attribute ignored",
-              IDENTIFIER_POINTER (TREE_PURPOSE (attrs)));
-      attrs = TREE_CHAIN (attrs);
-    }
-
-  return specs;
+  return returned_attrs;
 }