OSDN Git Service

* attribs.c (strip_attrs): Remove.
[pf3gnuchains/gcc-fork.git] / gcc / c-decl.c
index 1c4510a..e358ff6 100644 (file)
@@ -104,6 +104,11 @@ static int enum_overflow;
 
 static location_t current_function_prototype_locus;
 
+/* The argument information structure for the function currently being
+   defined.  */
+
+static GTY(()) tree current_function_arg_info;
+
 /* The current statement tree.  */
 
 static GTY(()) struct stmt_tree_s c_stmt_tree;
@@ -164,6 +169,16 @@ bool c_override_global_bindings_to_false;
    suppress further errors about that identifier in the current
    function.
 
+   The ->type field stores the type of the declaration in this scope;
+   if NULL, the type is the type of the ->decl field.  This is only of
+   relevance for objects with external or internal linkage which may
+   be redeclared in inner scopes, forming composite types that only
+   persist for the duration of those scopes.  In the external scope,
+   this stores the composite of all the types declared for this
+   object, visible or not.  The ->inner_comp field (used only at file
+   scope) stores whether an incomplete array type at file scope was
+   completed at an inner scope to an array size other than 1.
+
    The depth field is copied from the scope structure that holds this
    decl.  It is used to preserve the proper ordering of the ->shadowed
    field (see bind()) and also for a handful of special-case checks.
@@ -176,13 +191,15 @@ bool c_override_global_bindings_to_false;
 struct c_binding GTY((chain_next ("%h.prev")))
 {
   tree decl;                   /* the decl bound */
+  tree type;                   /* the type in this scope */
   tree id;                     /* the identifier it's bound to */
   struct c_binding *prev;      /* the previous decl in this scope */
   struct c_binding *shadowed;  /* the innermost decl shadowed by this one */
   unsigned int depth : 28;      /* depth of this scope */
   BOOL_BITFIELD invisible : 1;  /* normal lookup should ignore this binding */
   BOOL_BITFIELD nested : 1;     /* do not set DECL_CONTEXT when popping */
-  /* two free bits */
+  BOOL_BITFIELD inner_comp : 1; /* incomplete array completed in inner scope */
+  /* one free bit */
 };
 #define B_IN_SCOPE(b1, b2) ((b1)->depth == (b2)->depth)
 #define B_IN_CURRENT_SCOPE(b) ((b)->depth == current_scope->depth)
@@ -383,8 +400,8 @@ static GTY(()) tree static_dtors;
 /* Forward declarations.  */
 static tree lookup_name_in_scope (tree, struct c_scope *);
 static tree c_make_fname_decl (tree, int);
-static tree grokdeclarator (tree, tree, enum decl_context, int, tree *);
-static tree grokparms (tree, int);
+static tree grokdeclarator (tree, tree, enum decl_context, bool, tree *);
+static tree grokparms (tree, bool);
 static void layout_array_type (tree);
 \f
 /* States indicating how grokdeclarator() should handle declspecs marked
@@ -436,6 +453,9 @@ bind (tree name, tree decl, struct c_scope *scope, bool invisible, bool nested)
   b->depth = scope->depth;
   b->invisible = invisible;
   b->nested = nested;
+  b->inner_comp = 0;
+
+  b->type = 0;
 
   b->prev = scope->bindings;
   scope->bindings = b;
@@ -758,6 +778,12 @@ pop_scope (void)
              && scope != external_scope)
            warning ("%Junused variable `%D'", p, p);
 
+         if (b->inner_comp)
+           {
+             error ("%Jtype of array %qD completed incompatibly with"
+                    " implicit initialization", p, p);
+           }
+
          /* Fall through.  */
        case TYPE_DECL:
        case CONST_DECL:
@@ -797,6 +823,8 @@ pop_scope (void)
              if (I_SYMBOL_BINDING (b->id) != b) abort ();
 #endif
              I_SYMBOL_BINDING (b->id) = b->shadowed;
+             if (b->shadowed && b->shadowed->type)
+               TREE_TYPE (b->shadowed->decl) = b->shadowed->type;
            }
          break;
 
@@ -1325,7 +1353,14 @@ diagnose_mismatched_decls (tree newdecl, tree olddecl,
        {
          if (DECL_EXTERNAL (newdecl))
            {
-             if (warn_traditional)
+             if (!DECL_FILE_SCOPE_P (olddecl))
+               {
+                 error ("%Jextern declaration of %qD follows "
+                        "declaration with no linkage", newdecl, newdecl);
+                 locate_old_decl (olddecl, error);
+                 return false;
+               }
+             else if (warn_traditional)
                {
                  warning ("%Jnon-static declaration of '%D' follows "
                           "static declaration", newdecl, newdecl);
@@ -1347,29 +1382,33 @@ diagnose_mismatched_decls (tree newdecl, tree olddecl,
        }
       /* Two objects with the same name declared at the same block
         scope must both be external references (6.7p3).  */
-      else if (!DECL_FILE_SCOPE_P (newdecl)
-              && DECL_CONTEXT (newdecl) == DECL_CONTEXT (olddecl)
-              && (!DECL_EXTERNAL (newdecl) || !DECL_EXTERNAL (olddecl)))
+      else if (!DECL_FILE_SCOPE_P (newdecl))
        {
          if (DECL_EXTERNAL (newdecl))
-           error ("%Jextern declaration of '%D' follows "
-                  "declaration with no linkage", newdecl, newdecl);
+           {
+             /* Extern with initializer at block scope, which will
+                already have received an error.  */
+           }
          else if (DECL_EXTERNAL (olddecl))
-           error ("%Jdeclaration of '%D' with no linkage follows "
-                  "extern declaration", newdecl, newdecl);
+           {
+             error ("%Jdeclaration of '%D' with no linkage follows "
+                    "extern declaration", newdecl, newdecl);
+             locate_old_decl (olddecl, error);
+           }
          else
-           error ("%Jredeclaration of '%D' with no linkage",
-                  newdecl, newdecl);
+           {
+             error ("%Jredeclaration of '%D' with no linkage",
+                    newdecl, newdecl);
+             locate_old_decl (olddecl, error);
+           }
 
-         locate_old_decl (olddecl, error);
          return false;
        }
     }
 
   /* warnings */
-  /* All decls must agree on a non-default visibility.  */
-  if (DECL_VISIBILITY (newdecl) != VISIBILITY_DEFAULT
-      && DECL_VISIBILITY (olddecl) != VISIBILITY_DEFAULT
+  /* All decls must agree on a visibility.  */
+  if (DECL_VISIBILITY_SPECIFIED (newdecl) && DECL_VISIBILITY_SPECIFIED (olddecl)
       && DECL_VISIBILITY (newdecl) != DECL_VISIBILITY (olddecl))
     {
       warning ("%Jredeclaration of '%D' with different visibility "
@@ -1570,9 +1609,12 @@ merge_decls (tree newdecl, tree olddecl, tree newtype, tree oldtype)
      Currently, it can only be defined in the prototype.  */
   COPY_DECL_ASSEMBLER_NAME (olddecl, newdecl);
 
-  /* If either declaration has a nondefault visibility, use it.  */
-  if (DECL_VISIBILITY (olddecl) != VISIBILITY_DEFAULT)
-    DECL_VISIBILITY (newdecl) = DECL_VISIBILITY (olddecl);
+  /* Use visibility of whichever declaration had it specified */
+  if (DECL_VISIBILITY_SPECIFIED (olddecl))
+    {
+      DECL_VISIBILITY (newdecl) = DECL_VISIBILITY (olddecl);
+      DECL_VISIBILITY_SPECIFIED (newdecl) = 1;
+    }
 
   if (TREE_CODE (newdecl) == FUNCTION_DECL)
     {
@@ -1708,7 +1750,7 @@ merge_decls (tree newdecl, tree olddecl, tree newtype, tree oldtype)
       && (TREE_CODE (olddecl) == FUNCTION_DECL
          || (TREE_CODE (olddecl) == VAR_DECL
              && TREE_STATIC (olddecl))))
-    make_decl_rtl (olddecl, NULL);
+    make_decl_rtl (olddecl);
 }
 
 /* Handle when a new declaration NEWDECL has the same name as an old
@@ -1731,45 +1773,49 @@ duplicate_decls (tree newdecl, tree olddecl)
 }
 
 \f
-/* Check whether decl-node DECL shadows an existing declaration.  */
+/* Check whether decl-node NEW_DECL shadows an existing declaration.  */
 static void
-warn_if_shadowing (tree decl)
+warn_if_shadowing (tree new_decl)
 {
   struct c_binding *b;
 
   /* Shadow warnings wanted?  */
   if (!warn_shadow
       /* No shadow warnings for internally generated vars.  */
-      || DECL_IS_BUILTIN (decl)
+      || DECL_IS_BUILTIN (new_decl)
       /* No shadow warnings for vars made for inlining.  */
-      || DECL_FROM_INLINE (decl)
+      || DECL_FROM_INLINE (new_decl)
       /* Don't warn about the parm names in function declarator
         within a function declarator.  It would be nice to avoid
         warning in any function declarator in a declaration, as
         opposed to a definition, but there is no way to tell
         it's not a definition at this point.  */
-      || (TREE_CODE (decl) == PARM_DECL && current_scope->outer->parm_flag))
+      || (TREE_CODE (new_decl) == PARM_DECL && current_scope->outer->parm_flag))
     return;
 
   /* Is anything being shadowed?  Invisible decls do not count.  */
-  for (b = I_SYMBOL_BINDING (DECL_NAME (decl)); b; b = b->shadowed)
-    if (b->decl && b->decl != decl && !b->invisible)
+  for (b = I_SYMBOL_BINDING (DECL_NAME (new_decl)); b; b = b->shadowed)
+    if (b->decl && b->decl != new_decl && !b->invisible)
       {
-       tree old = b->decl;
+       tree old_decl = b->decl;
 
-       if (TREE_CODE (old) == PARM_DECL)
-         warning ("%Jdeclaration of '%D' shadows a parameter", decl, decl);
-       else if (DECL_FILE_SCOPE_P (old))
+       if (TREE_CODE (old_decl) == PARM_DECL)
+         warning ("%Jdeclaration of '%D' shadows a parameter",
+                  new_decl, new_decl);
+       else if (DECL_FILE_SCOPE_P (old_decl))
          warning ("%Jdeclaration of '%D' shadows a global declaration",
-                  decl, decl);
-       else if (TREE_CODE (old) == FUNCTION_DECL && DECL_BUILT_IN (old))
+                  new_decl, new_decl);
+       else if (TREE_CODE (old_decl) == FUNCTION_DECL
+                && DECL_BUILT_IN (old_decl))
          warning ("%Jdeclaration of '%D' shadows a built-in function",
-                  decl, decl);
+                  new_decl, new_decl);
        else
-         warning ("%Jdeclaration of '%D' shadows a previous local", decl, decl);
+         warning ("%Jdeclaration of '%D' shadows a previous local",
+                  new_decl, new_decl);
 
-       if (TREE_CODE (old) != FUNCTION_DECL || !DECL_BUILT_IN (old))
-         warning ("%Jshadowed declaration is here", old);
+       if (TREE_CODE (old_decl) != FUNCTION_DECL
+           || ! DECL_BUILT_IN (old_decl))
+         warning ("%Jshadowed declaration is here", old_decl);
 
        break;
       }
@@ -1833,7 +1879,7 @@ clone_underlying_type (tree x)
     {
       tree tt = TREE_TYPE (x);
       DECL_ORIGINAL_TYPE (x) = tt;
-      tt = build_type_copy (tt);
+      tt = build_variant_type_copy (tt);
       TYPE_NAME (tt) = x;
       TREE_USED (tt) = TREE_USED (x);
       TREE_TYPE (x) = tt;
@@ -1885,6 +1931,9 @@ pushdecl (tree x)
   b = I_SYMBOL_BINDING (name);
   if (b && B_IN_SCOPE (b, scope))
     {
+      if (TREE_CODE (TREE_TYPE (x)) == ARRAY_TYPE
+         && COMPLETE_TYPE_P (TREE_TYPE (x)))
+       b->inner_comp = false;
       if (duplicate_decls (x, b->decl))
        return b->decl;
       else
@@ -1905,13 +1954,63 @@ pushdecl (tree x)
      have compatible type; otherwise, the behavior is undefined.)  */
   if (DECL_EXTERNAL (x) || scope == file_scope)
     {
+      tree type = TREE_TYPE (x);
+      tree vistype = 0;
+      tree visdecl = 0;
+      bool type_saved = false;
+      if (b && !B_IN_EXTERNAL_SCOPE (b)
+         && (TREE_CODE (b->decl) == FUNCTION_DECL
+             || TREE_CODE (b->decl) == VAR_DECL)
+         && DECL_FILE_SCOPE_P (b->decl))
+       {
+         visdecl = b->decl;
+         vistype = TREE_TYPE (visdecl);
+       }
       if (warn_nested_externs
          && scope != file_scope
          && !DECL_IN_SYSTEM_HEADER (x))
        warning ("nested extern declaration of '%D'", x);
 
       while (b && !B_IN_EXTERNAL_SCOPE (b))
-       b = b->shadowed;
+       {
+         /* If this decl might be modified, save its type.  This is
+            done here rather than when the decl is first bound
+            because the type may change after first binding, through
+            being completed or through attributes being added.  If we
+            encounter multiple such decls, only the first should have
+            its type saved; the others will already have had their
+            proper types saved and the types will not have changed as
+            their scopes will not have been re-entered.  */
+         if (DECL_FILE_SCOPE_P (b->decl) && !type_saved)
+           {
+             b->type = TREE_TYPE (b->decl);
+             type_saved = true;
+           }
+         if (B_IN_FILE_SCOPE (b)
+             && TREE_CODE (b->decl) == VAR_DECL
+             && TREE_STATIC (b->decl)
+             && TREE_CODE (TREE_TYPE (b->decl)) == ARRAY_TYPE
+             && !TYPE_DOMAIN (TREE_TYPE (b->decl))
+             && TREE_CODE (type) == ARRAY_TYPE
+             && TYPE_DOMAIN (type)
+             && TYPE_MAX_VALUE (TYPE_DOMAIN (type))
+             && !integer_zerop (TYPE_MAX_VALUE (TYPE_DOMAIN (type))))
+           {
+             /* Array type completed in inner scope, which should be
+                diagnosed if the completion does not have size 1 and
+                it does not get completed in the file scope.  */
+             b->inner_comp = true;
+           }
+         b = b->shadowed;
+       }
+
+      /* If a matching external declaration has been found, set its
+        type to the composite of all the types of that declaration.
+        After the consistency checks, it will be reset to the
+        composite of the visible types only.  */
+      if (b && (TREE_PUBLIC (x) || same_translation_unit_p (x, b->decl))
+         && b->type)
+       TREE_TYPE (b->decl) = b->type;
 
       /* The point of the same_translation_unit_p check here is,
         we want to detect a duplicate decl for a construct like
@@ -1922,13 +2021,34 @@ pushdecl (tree x)
          && (TREE_PUBLIC (x) || same_translation_unit_p (x, b->decl))
          && duplicate_decls (x, b->decl))
        {
+         tree thistype;
+         thistype = (vistype ? composite_type (vistype, type) : type);
+         b->type = TREE_TYPE (b->decl);
+         if (TREE_CODE (b->decl) == FUNCTION_DECL && DECL_BUILT_IN (b->decl))
+           thistype
+             = build_type_attribute_variant (thistype,
+                                             TYPE_ATTRIBUTES (b->type));
+         TREE_TYPE (b->decl) = thistype;
          bind (name, b->decl, scope, /*invisible=*/false, /*nested=*/true);
          return b->decl;
        }
       else if (TREE_PUBLIC (x))
        {
-         bind (name, x, external_scope, /*invisible=*/true, /*nested=*/false);
-         nested = true;
+         if (visdecl && !b && duplicate_decls (x, visdecl))
+           {
+             /* An external declaration at block scope referring to a
+                visible entity with internal linkage.  The composite
+                type will already be correct for this scope, so we
+                just need to fall through to make the declaration in
+                this scope.  */
+             nested = true;
+           }
+         else
+           {
+             bind (name, x, external_scope, /*invisible=*/true,
+                   /*nested=*/false);
+             nested = true;
+           }
        }
     }
   /* Similarly, a declaration of a function with static linkage at
@@ -2046,7 +2166,16 @@ implicit_decl_warning (tree id, tree olddecl)
 tree
 implicitly_declare (tree functionid)
 {
-  tree decl = lookup_name_in_scope (functionid, external_scope);
+  struct c_binding *b;
+  tree decl = 0;
+  for (b = I_SYMBOL_BINDING (functionid); b; b = b->shadowed)
+    {
+      if (B_IN_SCOPE (b, external_scope))
+       {
+         decl = b->decl;
+         break;
+       }
+    }
 
   if (decl)
     {
@@ -2063,15 +2192,41 @@ implicitly_declare (tree functionid)
        }
       else
        {
+         tree newtype = default_function_type;
+         if (b->type)
+           TREE_TYPE (decl) = b->type;
          /* Implicit declaration of a function already declared
             (somehow) in a different scope, or as a built-in.
             If this is the first time this has happened, warn;
-            then recycle the old declaration.  */
+            then recycle the old declaration but with the new type.  */
          if (!C_DECL_IMPLICIT (decl))
            {
              implicit_decl_warning (functionid, decl);
              C_DECL_IMPLICIT (decl) = 1;
            }
+         if (DECL_BUILT_IN (decl))
+           {
+             newtype = build_type_attribute_variant (newtype,
+                                                     TYPE_ATTRIBUTES
+                                                     (TREE_TYPE (decl)));
+             if (!comptypes (newtype, TREE_TYPE (decl)))
+               {
+                 warning ("incompatible implicit declaration of built-in"
+                          " function %qD", decl);
+                 newtype = TREE_TYPE (decl);
+               }
+           }
+         else
+           {
+             if (!comptypes (newtype, TREE_TYPE (decl)))
+               {
+                 error ("incompatible implicit declaration of function %qD",
+                        decl);
+                 locate_old_decl (decl, error);
+               }
+           }
+         b->type = TREE_TYPE (decl);
+         TREE_TYPE (decl) = newtype;
          bind (functionid, decl, current_scope,
                /*invisible=*/false, /*nested=*/true);
          return decl;
@@ -2090,7 +2245,7 @@ implicitly_declare (tree functionid)
   decl = pushdecl (decl);
 
   /* No need to call objc_check_decl here - it's a function type.  */
-  rest_of_decl_compilation (decl, NULL, 0, 0);
+  rest_of_decl_compilation (decl, 0, 0);
 
   /* Write a record describing this implicit function declaration
      to the prototypes file (if requested).  */
@@ -2394,7 +2549,7 @@ c_init_decl_processing (void)
   input_location.line = 0;
 #endif
 
-  build_common_tree_nodes (flag_signed_char);
+  build_common_tree_nodes (flag_signed_char, false);
 
   c_common_nodes_and_builtins ();
 
@@ -2525,12 +2680,10 @@ shadow_tag (tree declspecs)
   shadow_tag_warned (declspecs, 0);
 }
 
+/* WARNED is 1 if we have done a pedwarn, 2 if we have done a warning,
+   but no pedwarn.  */
 void
 shadow_tag_warned (tree declspecs, int warned)
-
-
-     /* 1 => we have done a pedwarn.  2 => we have done a warning, but
-       no pedwarn.  */
 {
   int found_tag = 0;
   tree link;
@@ -2599,17 +2752,18 @@ shadow_tag_warned (tree declspecs, int warned)
 /* Construct an array declarator.  EXPR is the expression inside [], or
    NULL_TREE.  QUALS are the type qualifiers inside the [] (to be applied
    to the pointer to which a parameter array is converted).  STATIC_P is
-   nonzero if "static" is inside the [], zero otherwise.  VLA_UNSPEC_P
-   is nonzero is the array is [*], a VLA of unspecified length which is
+   true if "static" is inside the [], false otherwise.  VLA_UNSPEC_P
+   is true if the array is [*], a VLA of unspecified length which is
    nevertheless a complete type (not currently implemented by GCC),
-   zero otherwise.  The declarator is constructed as an ARRAY_REF
+   false otherwise.  The declarator is constructed as an ARRAY_REF
    (to be decoded by grokdeclarator), whose operand 0 is what's on the
-   left of the [] (filled by in set_array_declarator_type) and operand 1
+   left of the [] (filled by in set_array_declarator_inner) and operand 1
    is the expression inside; whose TREE_TYPE is the type qualifiers and
    which has TREE_STATIC set if "static" is used.  */
 
 tree
-build_array_declarator (tree expr, tree quals, int static_p, int vla_unspec_p)
+build_array_declarator (tree expr, tree quals, bool static_p,
+                       bool vla_unspec_p)
 {
   tree decl;
   decl = build_nt (ARRAY_REF, NULL_TREE, expr, NULL_TREE, NULL_TREE);
@@ -2629,13 +2783,13 @@ build_array_declarator (tree expr, tree quals, int static_p, int vla_unspec_p)
 
 /* Set the type of an array declarator.  DECL is the declarator, as
    constructed by build_array_declarator; TYPE is what appears on the left
-   of the [] and goes in operand 0.  ABSTRACT_P is nonzero if it is an
-   abstract declarator, zero otherwise; this is used to reject static and
+   of the [] and goes in operand 0.  ABSTRACT_P is true if it is an
+   abstract declarator, false otherwise; this is used to reject static and
    type qualifiers in abstract declarators, where they are not in the
    C99 grammar.  */
 
 tree
-set_array_declarator_type (tree decl, tree type, int abstract_p)
+set_array_declarator_inner (tree decl, tree type, bool abstract_p)
 {
   TREE_OPERAND (decl, 0) = type;
   if (abstract_p && (TREE_TYPE (decl) != NULL_TREE || TREE_STATIC (decl)))
@@ -2643,6 +2797,85 @@ set_array_declarator_type (tree decl, tree type, int abstract_p)
   return decl;
 }
 \f
+/* 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 (tree specs_attrs, tree *declspecs, tree *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);
+         else
+           {
+             TREE_CHAIN (a) = TREE_PURPOSE (t);
+             a = TREE_PURPOSE (t);
+           }
+         /* 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;
+}
+
 /* Decode a "typename", such as "int **", returning a ..._TYPE node.  */
 
 tree
@@ -2655,7 +2888,7 @@ groktypename (tree type_name)
 
   split_specs_attrs (TREE_PURPOSE (type_name), &specs, &attrs);
 
-  type_name = grokdeclarator (TREE_VALUE (type_name), specs, TYPENAME, 0,
+  type_name = grokdeclarator (TREE_VALUE (type_name), specs, TYPENAME, false,
                             NULL);
 
   /* Apply attributes.  */
@@ -2673,7 +2906,7 @@ groktypename_in_parm_context (tree type_name)
     return type_name;
   return grokdeclarator (TREE_VALUE (type_name),
                         TREE_PURPOSE (type_name),
-                        PARM, 0, NULL);
+                        PARM, false, NULL);
 }
 
 /* Decode a declarator in an ordinary declaration or data definition.
@@ -2692,7 +2925,7 @@ groktypename_in_parm_context (tree type_name)
    grokfield and not through here.  */
 
 tree
-start_decl (tree declarator, tree declspecs, int initialized, tree attributes)
+start_decl (tree declarator, tree declspecs, bool initialized, tree attributes)
 {
   tree decl;
   tree tem;
@@ -2868,8 +3101,8 @@ finish_decl (tree decl, tree init, tree asmspec_tree)
     store_init_value (decl, init);
 
   if (c_dialect_objc () && (TREE_CODE (decl) == VAR_DECL
-                   || TREE_CODE (decl) == FUNCTION_DECL
-                   || TREE_CODE (decl) == FIELD_DECL))
+                           || TREE_CODE (decl) == FUNCTION_DECL
+                           || TREE_CODE (decl) == FIELD_DECL))
     objc_check_decl (decl);
 
   /* Deduce size of array from initialization, if not already known.  */
@@ -2910,7 +3143,7 @@ finish_decl (tree decl, tree init, tree asmspec_tree)
         in the array, because we start counting at zero.  Therefore,
         warn only if the value is less than zero.  */
       else if (pedantic && TYPE_DOMAIN (type) != 0
-             && tree_int_cst_sgn (TYPE_MAX_VALUE (TYPE_DOMAIN (type))) < 0)
+              && tree_int_cst_sgn (TYPE_MAX_VALUE (TYPE_DOMAIN (type))) < 0)
        error ("%Jzero or negative size array '%D'", decl, decl);
 
       layout_decl (decl, 0);
@@ -2926,22 +3159,20 @@ finish_decl (tree decl, tree init, tree asmspec_tree)
          /* Don't give an error if we already gave one earlier.  */
          && TREE_TYPE (decl) != error_mark_node
          && (TREE_STATIC (decl)
-             ?
-               /* A static variable with an incomplete type
-                  is an error if it is initialized.
-                  Also if it is not file scope.
-                  Otherwise, let it through, but if it is not `extern'
-                  then it may cause an error message later.  */
-               (DECL_INITIAL (decl) != 0
+             /* A static variable with an incomplete type
+                is an error if it is initialized.
+                Also if it is not file scope.
+                Otherwise, let it through, but if it is not `extern'
+                then it may cause an error message later.  */
+             ? (DECL_INITIAL (decl) != 0
                 || !DECL_FILE_SCOPE_P (decl))
-             :
-               /* An automatic variable with an incomplete type
-                  is an error.  */
-               !DECL_EXTERNAL (decl)))
-       {
-         error ("%Jstorage size of '%D' isn't known", decl, decl);
-         TREE_TYPE (decl) = error_mark_node;
-       }
+             /* An automatic variable with an incomplete type
+                is an error.  */
+             : !DECL_EXTERNAL (decl)))
+        {
+          error ("%Jstorage size of '%D' isn't known", decl, decl);
+          TREE_TYPE (decl) = error_mark_node;
+        }
 
       if ((DECL_EXTERNAL (decl) || TREE_STATIC (decl))
          && DECL_SIZE (decl) != 0)
@@ -2961,30 +3192,28 @@ finish_decl (tree decl, tree init, tree asmspec_tree)
      was a normal built-in.  */
   if (TREE_CODE (decl) == FUNCTION_DECL && asmspec)
     {
-      /* ASMSPEC is given, and not the name of a register.  Mark the
-      name with a star so assemble_name won't munge it.  */
-      char *starred = alloca (strlen (asmspec) + 2);
-      starred[0] = '*';
-      strcpy (starred + 1, asmspec);
-
       if (DECL_BUILT_IN_CLASS (decl) == BUILT_IN_NORMAL)
        {
          tree builtin = built_in_decls [DECL_FUNCTION_CODE (decl)];
-         SET_DECL_RTL (builtin, NULL_RTX);
-         change_decl_assembler_name (builtin, get_identifier (starred));
-         if (DECL_FUNCTION_CODE (decl) == BUILT_IN_MEMCPY)
-           init_block_move_fn (starred);
-         else if (DECL_FUNCTION_CODE (decl) == BUILT_IN_MEMSET)
-           init_block_clear_fn (starred);
-       }
-      SET_DECL_RTL (decl, NULL_RTX);
-      change_decl_assembler_name (decl, get_identifier (starred));
+         set_user_assembler_name (builtin, asmspec);
+          if (DECL_FUNCTION_CODE (decl) == BUILT_IN_MEMCPY)
+            init_block_move_fn (asmspec);
+          else if (DECL_FUNCTION_CODE (decl) == BUILT_IN_MEMSET)
+            init_block_clear_fn (asmspec);
+        }
+      set_user_assembler_name (decl, asmspec);
     }
 
   /* If #pragma weak was used, mark the decl weak now.  */
   if (current_scope == file_scope)
     maybe_apply_pragma_weak (decl);
 
+  /* If this is a variable definition, determine its ELF visibility.  */
+  if (TREE_CODE (decl) == VAR_DECL 
+      && TREE_STATIC (decl) 
+      && !DECL_EXTERNAL (decl))
+    c_determine_visibility (decl);
+
   /* Output the assembler code and/or RTL code for variables and functions,
      unless the type is an undefined structure or union.
      If not, it will get done when the type is completed.  */
@@ -2995,6 +3224,25 @@ finish_decl (tree decl, tree init, tree asmspec_tree)
       if (c_dialect_objc ())
        objc_check_decl (decl);
 
+      if (asmspec) 
+       {
+         /* If this is not a static variable, issue a warning.
+            It doesn't make any sense to give an ASMSPEC for an
+            ordinary, non-register local variable.  Historically,
+            GCC has accepted -- but ignored -- the ASMSPEC in
+            this case.  */
+         if (! DECL_FILE_SCOPE_P (decl)
+             && TREE_CODE (decl) == VAR_DECL
+             && !C_DECL_REGISTER (decl)
+             && !TREE_STATIC (decl))
+           warning ("%Jignoring asm-specifier for non-static local "
+                    "variable '%D'", decl, decl);
+         else if (C_DECL_REGISTER (decl))
+           change_decl_assembler_name (decl, get_identifier (asmspec));
+         else
+           set_user_assembler_name (decl, asmspec);
+       }
+      
       if (DECL_FILE_SCOPE_P (decl))
        {
          if (DECL_INITIAL (decl) == NULL_TREE
@@ -3003,44 +3251,44 @@ finish_decl (tree decl, tree init, tree asmspec_tree)
               when a tentative file-scope definition is seen.
               But at end of compilation, do output code for them.  */
            DECL_DEFER_OUTPUT (decl) = 1;
-         rest_of_decl_compilation (decl, asmspec, true, 0);
+         rest_of_decl_compilation (decl, true, 0);
        }
       else
        {
-         /* This is a local variable.  If there is an ASMSPEC, the
-            user has requested that we handle it specially.  */
-         if (asmspec)
+         /* In conjunction with an ASMSPEC, the `register'
+            keyword indicates that we should place the variable
+            in a particular register.  */
+         if (asmspec && C_DECL_REGISTER (decl))
            {
-             /* In conjunction with an ASMSPEC, the `register'
-                keyword indicates that we should place the variable
-                in a particular register.  */
-             if (C_DECL_REGISTER (decl))
-               {
-                 DECL_HARD_REGISTER (decl) = 1;
-                 /* This cannot be done for a structure with volatile
-                    fields, on which DECL_REGISTER will have been
-                    reset.  */
-                 if (!DECL_REGISTER (decl))
-                   error ("cannot put object with volatile field into register");
-               }
-
-             /* If this is not a static variable, issue a warning.
-                It doesn't make any sense to give an ASMSPEC for an
-                ordinary, non-register local variable.  Historically,
-                GCC has accepted -- but ignored -- the ASMSPEC in
-                this case.  */
-             if (TREE_CODE (decl) == VAR_DECL
-                 && !C_DECL_REGISTER (decl)
-                 && !TREE_STATIC (decl))
-               warning ("%Jignoring asm-specifier for non-static local "
-                         "variable '%D'", decl, decl);
-             else
-               change_decl_assembler_name (decl, get_identifier (asmspec));
+             DECL_HARD_REGISTER (decl) = 1;
+             /* This cannot be done for a structure with volatile
+                fields, on which DECL_REGISTER will have been
+                reset.  */
+             if (!DECL_REGISTER (decl))
+               error ("cannot put object with volatile field into register");
            }
 
          if (TREE_CODE (decl) != FUNCTION_DECL)
-           add_stmt (build_stmt (DECL_EXPR, decl));
+           {
+             /* If we're building a variable sized type, and we might be
+                reachable other than via the top of the current binding
+                level, then create a new BIND_EXPR so that we deallocate
+                the object at the right time.  */
+             /* Note that DECL_SIZE can be null due to errors.  */
+             if (DECL_SIZE (decl)
+                 && !TREE_CONSTANT (DECL_SIZE (decl))
+                 && STATEMENT_LIST_HAS_LABEL (cur_stmt_list))
+               {
+                 tree bind;
+                 bind = build3 (BIND_EXPR, void_type_node, NULL, NULL, NULL);
+                 TREE_SIDE_EFFECTS (bind) = 1;
+                 add_stmt (bind);
+                 BIND_EXPR_BODY (bind) = push_stmt_list ();
+               }
+             add_stmt (build_stmt (DECL_EXPR, decl));
+           }
        }
+  
 
       if (!DECL_FILE_SCOPE_P (decl))
        {
@@ -3068,7 +3316,7 @@ finish_decl (tree decl, tree init, tree asmspec_tree)
          && variably_modified_type_p (TREE_TYPE (decl), NULL_TREE))
        add_stmt (build_stmt (DECL_EXPR, decl));
 
-      rest_of_decl_compilation (decl, NULL, DECL_FILE_SCOPE_P (decl), 0);
+      rest_of_decl_compilation (decl, DECL_FILE_SCOPE_P (decl), 0);
     }
 
   /* At the end of a declaration, throw away any variable type sizes
@@ -3112,6 +3360,20 @@ finish_decl (tree decl, tree init, tree asmspec_tree)
     }
 }
 
+/* Given a parsed parameter declaration, decode it into a PARM_DECL.  */
+
+tree
+grokparm (tree parm)
+{
+  tree decl = grokdeclarator (TREE_VALUE (TREE_PURPOSE (parm)),
+                             TREE_PURPOSE (TREE_PURPOSE (parm)),
+                             PARM, false, NULL);
+
+  decl_attributes (&decl, TREE_VALUE (parm), 0);
+
+  return decl;
+}
+
 /* Given a parsed parameter declaration, decode it into a PARM_DECL
    and push that on the current scope.  */
 
@@ -3122,7 +3384,7 @@ push_parm_decl (tree parm)
 
   decl = grokdeclarator (TREE_VALUE (TREE_PURPOSE (parm)),
                         TREE_PURPOSE (TREE_PURPOSE (parm)),
-                        PARM, 0, NULL);
+                        PARM, false, NULL);
   decl_attributes (&decl, TREE_VALUE (parm), 0);
 
   decl = pushdecl (decl);
@@ -3205,7 +3467,7 @@ build_compound_literal (tree type, tree init)
       DECL_COMDAT (decl) = 1;
       DECL_ARTIFICIAL (decl) = 1;
       pushdecl (decl);
-      rest_of_decl_compilation (decl, NULL, 1, 0);
+      rest_of_decl_compilation (decl, 1, 0);
     }
 
   return complit;
@@ -3229,22 +3491,22 @@ complete_array_type (tree type, tree initial_value, int do_default)
        {
          int eltsize
            = int_size_in_bytes (TREE_TYPE (TREE_TYPE (initial_value)));
-         maxindex = build_int_2 ((TREE_STRING_LENGTH (initial_value)
-                                  / eltsize) - 1, 0);
+         maxindex = build_int_cst (NULL_TREE,
+                                   (TREE_STRING_LENGTH (initial_value)
+                                    / eltsize) - 1);
        }
       else if (TREE_CODE (initial_value) == CONSTRUCTOR)
        {
          tree elts = CONSTRUCTOR_ELTS (initial_value);
-         maxindex = build_int_2 (-1, -1);
+         maxindex = build_int_cst (NULL_TREE, -1);
          for (; elts; elts = TREE_CHAIN (elts))
            {
              if (TREE_PURPOSE (elts))
                maxindex = TREE_PURPOSE (elts);
              else
-               maxindex = fold (build (PLUS_EXPR, integer_type_node,
-                                       maxindex, integer_one_node));
+               maxindex = fold (build2 (PLUS_EXPR, integer_type_node,
+                                        maxindex, integer_one_node));
            }
-         maxindex = copy_node (maxindex);
        }
       else
        {
@@ -3253,14 +3515,14 @@ complete_array_type (tree type, tree initial_value, int do_default)
            value = 1;
 
          /* Prevent further error messages.  */
-         maxindex = build_int_2 (0, 0);
+         maxindex = build_int_cst (NULL_TREE, 0);
        }
     }
 
   if (!maxindex)
     {
       if (do_default)
-       maxindex = build_int_2 (0, 0);
+       maxindex = build_int_cst (NULL_TREE, 0);
       value = 2;
     }
 
@@ -3268,7 +3530,7 @@ complete_array_type (tree type, tree initial_value, int do_default)
     {
       TYPE_DOMAIN (type) = build_index_type (maxindex);
       if (!TREE_TYPE (maxindex))
-       TREE_TYPE (maxindex) = TYPE_DOMAIN (type);
+       abort ();
     }
 
   /* Lay out the type now that we can get the real answer.  */
@@ -3371,7 +3633,7 @@ check_bitfield_type_and_width (tree *type, tree *width, const char *orig_name)
     {
       error ("width of `%s' exceeds its type", name);
       w = max_width;
-      *width = build_int_2 (w, 0);
+      *width = build_int_cst (NULL_TREE, w);
     }
   else
     w = tree_low_cst (*width, 1);
@@ -3405,7 +3667,7 @@ check_bitfield_type_and_width (tree *type, tree *width, const char *orig_name)
      TYPENAME if for a typename (in a cast or sizeof).
       Don't make a DECL node; just return the ..._TYPE node.
      FIELD for a struct or union field; make a FIELD_DECL.
-   INITIALIZED is 1 if the decl has an initializer.
+   INITIALIZED is true if the decl has an initializer.
    WIDTH is non-NULL for bit-fields, and is a pointer to an INTEGER_CST node
    representing the width of the bit-field.
 
@@ -3418,7 +3680,7 @@ check_bitfield_type_and_width (tree *type, tree *width, const char *orig_name)
 
 static tree
 grokdeclarator (tree declarator, tree declspecs,
-               enum decl_context decl_context, int initialized, tree *width)
+               enum decl_context decl_context, bool initialized, tree *width)
 {
   int specbits = 0;
   tree spec;
@@ -4064,9 +4326,9 @@ grokdeclarator (tree declarator, tree declspecs,
                     Do the calculation in index_type, so that if it is
                     a variable the computations will be done in the
                     proper mode.  */
-                 itype = fold (build (MINUS_EXPR, index_type,
-                                      convert (index_type, size),
-                                      convert (index_type, size_one_node)));
+                 itype = fold (build2 (MINUS_EXPR, index_type,
+                                       convert (index_type, size),
+                                       convert (index_type, size_one_node)));
 
                  /* If that overflowed, the array is too big.
                     ??? While a size of INT_MAX+1 technically shouldn't
@@ -4136,12 +4398,17 @@ grokdeclarator (tree declarator, tree declspecs,
        }
       else if (TREE_CODE (declarator) == CALL_EXPR)
        {
-         /* Say it's a definition only for the CALL_EXPR closest to
-            the identifier.  */
-         bool really_funcdef = (funcdef_flag
-                                && (TREE_CODE (TREE_OPERAND (declarator, 0))
-                                    == IDENTIFIER_NODE));
+         /* Say it's a definition only for the declarator closest to
+            the identifier, apart possibly from some attributes.  */
+         bool really_funcdef = false;
          tree arg_types;
+         if (funcdef_flag)
+           {
+             tree t = TREE_OPERAND (declarator, 0);
+             while (TREE_CODE (t) == TREE_LIST)
+               t = TREE_VALUE (t);
+             really_funcdef = (TREE_CODE (t) == IDENTIFIER_NODE);
+           }
 
          /* Declaring a function type.
             Make sure we have a valid type for the function to return.  */
@@ -4476,26 +4743,29 @@ grokdeclarator (tree declarator, tree declspecs,
       }
     else if (TREE_CODE (type) == FUNCTION_TYPE)
       {
-       if (specbits & (1 << (int) RID_AUTO)
-           && (pedantic || current_scope == file_scope))
-         pedwarn ("invalid storage class for function `%s'", name);
-       if (specbits & (1 << (int) RID_REGISTER))
-         error ("invalid storage class for function `%s'", name);
-       if (specbits & (1 << (int) RID_THREAD))
+       if (specbits & (1 << (int) RID_REGISTER)
+           || specbits & (1 << (int) RID_THREAD))
          error ("invalid storage class for function `%s'", name);
-       /* Function declaration not at file scope.
-          Storage classes other than `extern' are not allowed
-          and `extern' makes no difference.  */
-       if (current_scope != file_scope
-           && (specbits & ((1 << (int) RID_STATIC) | (1 << (int) RID_INLINE)))
-           && pedantic)
-         pedwarn ("invalid storage class for function `%s'", name);
+       else if (current_scope != file_scope)
+         {
+           /* Function declaration not at file scope.  Storage
+              classes other than `extern' are not allowed, C99
+              6.7.1p5, and `extern' makes no difference.  However,
+              GCC allows 'auto', perhaps with 'inline', to support
+              nested functions.  */
+           if (specbits & (1 << (int) RID_AUTO))
+             {
+               if (pedantic)
+                 pedwarn ("invalid storage class for function `%s'", name);
+             }
+           if (specbits & (1 << (int) RID_STATIC))
+             error ("invalid storage class for function `%s'", name);
+         }
 
        decl = build_decl (FUNCTION_DECL, declarator, type);
        decl = build_decl_attribute_variant (decl, decl_attr);
 
-       DECL_LANG_SPECIFIC (decl)
-         = GGC_CNEW (struct lang_decl);
+       DECL_LANG_SPECIFIC (decl) = GGC_CNEW (struct lang_decl);
 
        if (pedantic && type_quals && ! DECL_IN_SYSTEM_HEADER (decl))
          pedwarn ("ISO C forbids qualified function types");
@@ -4521,10 +4791,9 @@ grokdeclarator (tree declarator, tree declspecs,
          = !(specbits & ((1 << (int) RID_STATIC) | (1 << (int) RID_AUTO)));
 
        /* For a function definition, record the argument information
-          block in DECL_ARGUMENTS where store_parm_decls will look
-          for it.  */
+          block where store_parm_decls will look for it.  */
        if (funcdef_flag)
-         DECL_ARGUMENTS (decl) = arg_info;
+         current_function_arg_info = arg_info;
 
        if (defaulted_int)
          C_FUNCTION_IMPLICIT_INT (decl) = 1;
@@ -4684,12 +4953,12 @@ grokdeclarator (tree declarator, tree declspecs,
 
    Return a list of arg types to use in the FUNCTION_TYPE for this function.
 
-   FUNCDEF_FLAG is nonzero for a function definition, 0 for
+   FUNCDEF_FLAG is true for a function definition, false for
    a mere declaration.  A nonempty identifier-list gets an error message
-   when FUNCDEF_FLAG is zero.  */
+   when FUNCDEF_FLAG is false.  */
 
 static tree
-grokparms (tree arg_info, int funcdef_flag)
+grokparms (tree arg_info, bool funcdef_flag)
 {
   tree arg_types = ARG_INFO_TYPES (arg_info);
 
@@ -5090,7 +5359,7 @@ grokfield (tree declarator, tree declspecs, tree width)
        }
     }
 
-  value = grokdeclarator (declarator, declspecs, FIELD, 0,
+  value = grokdeclarator (declarator, declspecs, FIELD, false,
                          width ? &width : NULL);
 
   finish_decl (value, NULL_TREE, NULL_TREE);
@@ -5382,7 +5651,7 @@ finish_struct (tree t, tree fieldlist, tree attributes)
          layout_decl (decl, 0);
          if (c_dialect_objc ())
            objc_check_decl (decl);
-         rest_of_decl_compilation (decl, NULL, toplevel, 0);
+         rest_of_decl_compilation (decl, toplevel, 0);
          if (! toplevel)
            expand_decl (decl);
        }
@@ -5681,7 +5950,7 @@ start_function (tree declspecs, tree declarator, tree attributes)
      error message in c_finish_bc_stmt.  */
   c_break_label = c_cont_label = size_zero_node;
 
-  decl1 = grokdeclarator (declarator, declspecs, FUNCDEF, 1, NULL);
+  decl1 = grokdeclarator (declarator, declspecs, FUNCDEF, true, NULL);
 
   /* If the declarator is not suitable for a function definition,
      cause a syntax error.  */
@@ -6152,7 +6421,7 @@ store_parm_decls_oldstyle (tree fndecl, tree arg_info)
         will be a variant of the main variant of the original function
         type.  */
 
-      TREE_TYPE (fndecl) = build_type_copy (TREE_TYPE (fndecl));
+      TREE_TYPE (fndecl) = build_variant_type_copy (TREE_TYPE (fndecl));
 
       TYPE_ACTUAL_ARG_TYPES (TREE_TYPE (fndecl)) = actual;
     }
@@ -6169,16 +6438,18 @@ void
 store_parm_decls (void)
 {
   tree fndecl = current_function_decl;
+  bool proto;
 
   /* The argument information block for FNDECL.  */
-  tree arg_info = DECL_ARGUMENTS (fndecl);
+  tree arg_info = current_function_arg_info;
+  current_function_arg_info = 0;
 
   /* True if this definition is written with a prototype.  Note:
      despite C99 6.7.5.3p14, we can *not* treat an empty argument
      list in a function definition as equivalent to (void) -- an
      empty argument list specifies the function has no parameters,
      but only (void) sets up a prototype for future calls.  */
-  bool proto = ARG_INFO_TYPES (arg_info) != 0;
+  proto = ARG_INFO_TYPES (arg_info) != 0;
 
   if (proto)
     store_parm_decls_newstyle (fndecl, arg_info);
@@ -6331,6 +6602,9 @@ finish_function (void)
       && !targetm.have_ctors_dtors)
     static_dtors = tree_cons (NULL_TREE, fndecl, static_dtors);
 
+  /* Finalize the ELF visibility for the function.  */
+  c_determine_visibility (fndecl);
+
   /* Genericize before inlining.  Delay genericizing nested functions
      until their parent function is genericized.  Since finalizing
      requires GENERIC, delay that as well.  */
@@ -6459,6 +6733,7 @@ c_push_function_context (struct function *f)
   p->x_break_label = c_break_label;
   p->x_cont_label = c_cont_label;
   p->x_switch_stack = c_switch_stack;
+  p->arg_info = current_function_arg_info;
   p->returns_value = current_function_returns_value;
   p->returns_null = current_function_returns_null;
   p->returns_abnormally = current_function_returns_abnormally;
@@ -6487,6 +6762,7 @@ c_pop_function_context (struct function *f)
   c_break_label = p->x_break_label;
   c_cont_label = p->x_cont_label;
   c_switch_stack = p->x_switch_stack;
+  current_function_arg_info = p->arg_info;
   current_function_returns_value = p->returns_value;
   current_function_returns_null = p->returns_null;
   current_function_returns_abnormally = p->returns_abnormally;
@@ -6572,12 +6848,15 @@ identifier_global_value (tree t)
 void
 record_builtin_type (enum rid rid_index, const char *name, tree type)
 {
-  tree id;
+  tree id, decl;
   if (name == 0)
     id = ridpointers[(int) rid_index];
   else
     id = get_identifier (name);
-  pushdecl (build_decl (TYPE_DECL, id, type));
+  decl = build_decl (TYPE_DECL, id, type);
+  pushdecl (decl);
+  if (debug_hooks->type_decl)
+    debug_hooks->type_decl (decl, false);
 }
 
 /* Build the void_list_node (void_type_node having been created).  */
@@ -6588,6 +6867,34 @@ build_void_list_node (void)
   return t;
 }
 
+/* Return a structure for a parameter with the given SPECS, ATTRS and
+   DECLARATOR.  */
+
+tree
+build_c_parm (tree specs, tree attrs, tree declarator)
+{
+  return build_tree_list (build_tree_list (specs, declarator), attrs);
+}
+
+/* Return a declarator with nested attributes.  TARGET is the inner
+   declarator to which these attributes apply.  ATTRS are the
+   attributes.  */
+
+tree
+build_attrs_declarator (tree attrs, tree target)
+{
+  return tree_cons (attrs, target, NULL_TREE);
+}
+
+/* Return a declarator for a function with arguments specified by ARGS
+   and return type specified by TARGET.  */
+
+tree
+build_function_declarator (tree args, tree target)
+{
+  return build_nt (CALL_EXPR, target, args, NULL_TREE);
+}
+
 /* 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
@@ -6604,7 +6911,7 @@ make_pointer_declarator (tree type_quals_attrs, tree target)
   tree itarget = target;
   split_specs_attrs (type_quals_attrs, &quals, &attrs);
   if (attrs != NULL_TREE)
-    itarget = tree_cons (attrs, target, NULL_TREE);
+    itarget = build_attrs_declarator (attrs, target);
   return build1 (INDIRECT_REF, quals, itarget);
 }