OSDN Git Service

* gcc.dg/tree-ssa/20030708-1.c: Remove static from test function.
[pf3gnuchains/gcc-fork.git] / gcc / c-decl.c
index 3578862..eececb1 100644 (file)
@@ -16,8 +16,8 @@ for more details.
 
 You should have received a copy of the GNU General Public License
 along with GCC; see the file COPYING.  If not, write to the Free
-Software Foundation, 59 Temple Place - Suite 330, Boston, MA
-02111-1307, USA.  */
+Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301, USA.  */
 
 /* Process declarations and symbol lookup for C front end.
    Also constructs types; the standard scalar types at initialization,
@@ -98,6 +98,14 @@ static int enum_overflow;
 
 static location_t current_function_prototype_locus;
 
+/* Whether this prototype was built-in.  */
+
+static bool current_function_prototype_built_in;
+
+/* The argument type information of this prototype.  */
+
+static tree current_function_prototype_arg_types;
+
 /* The argument information structure for the function currently being
    defined.  */
 
@@ -410,6 +418,31 @@ static tree grokdeclarator (const struct c_declarator *,
 static tree grokparms (struct c_arg_info *, bool);
 static void layout_array_type (tree);
 \f
+/* T is a statement.  Add it to the statement-tree.  This is the
+   C/ObjC version--C++ has a slightly different version of this
+   function.  */
+
+tree
+add_stmt (tree t)
+{
+  enum tree_code code = TREE_CODE (t);
+
+  if (EXPR_P (t) && code != LABEL_EXPR)
+    {
+      if (!EXPR_HAS_LOCATION (t))
+       SET_EXPR_LOCATION (t, input_location);
+    }
+
+  if (code == LABEL_EXPR || code == CASE_LABEL_EXPR)
+    STATEMENT_LIST_HAS_LABEL (cur_stmt_list) = 1;
+
+  /* Add T to the statement-tree.  Non-side-effect statements need to be
+     recorded during statement expressions.  */
+  append_to_statement_list_force (t, &cur_stmt_list);
+
+  return t;
+}
+\f
 /* States indicating how grokdeclarator() should handle declspecs marked
    with __attribute__((deprecated)).  An object declared as
    __attribute__((deprecated)) suppresses warnings of uses of other
@@ -558,15 +591,7 @@ objc_mark_locals_volatile (void *enclosing_blk)
        scope = scope->outer)
     {
       for (b = scope->bindings; b; b = b->prev)
-       {
-         if (TREE_CODE (b->decl) == VAR_DECL
-             || TREE_CODE (b->decl) == PARM_DECL)
-           {
-             C_DECL_REGISTER (b->decl) = 0;
-             DECL_REGISTER (b->decl) = 0;
-             TREE_THIS_VOLATILE (b->decl) = 1;
-           }
-       }
+       objc_volatilize_decl (b->decl);
 
       /* Do not climb up past the current function.  */
       if (scope->function_body)
@@ -776,14 +801,13 @@ pop_scope (void)
 
        case VAR_DECL:
          /* Warnings for unused variables.  */
-         if (warn_unused_variable
-             && !TREE_USED (p)
+         if (!TREE_USED (p)
              && !DECL_IN_SYSTEM_HEADER (p)
              && DECL_NAME (p)
              && !DECL_ARTIFICIAL (p)
              && scope != file_scope
              && scope != external_scope) 
-           warning (0, "%Junused variable %qD", p, p);
+           warning (OPT_Wunused_variable, "%Junused variable %qD", p, p);
 
          if (b->inner_comp)
            {
@@ -1101,16 +1125,16 @@ validate_proto_after_old_defn (tree newdecl, tree newtype, tree oldtype)
    first in a pair of mismatched declarations, using the diagnostic
    function DIAG.  */
 static void
-locate_old_decl (tree decl, void (*diag)(const char *, ...))
+locate_old_decl (tree decl, void (*diag)(const char *, ...) ATTRIBUTE_GCC_CDIAG(1,2))
 {
   if (TREE_CODE (decl) == FUNCTION_DECL && DECL_BUILT_IN (decl))
     ;
   else if (DECL_INITIAL (decl))
-    diag (N_("%Jprevious definition of %qD was here"), decl, decl);
+    diag (G_("%Jprevious definition of %qD was here"), decl, decl);
   else if (C_DECL_IMPLICIT (decl))
-    diag (N_("%Jprevious implicit declaration of %qD was here"), decl, decl);
+    diag (G_("%Jprevious implicit declaration of %qD was here"), decl, decl);
   else
-    diag (N_("%Jprevious declaration of %qD was here"), decl, decl);
+    diag (G_("%Jprevious declaration of %qD was here"), decl, decl);
 }
 
 /* Subroutine of duplicate_decls.  Compare NEWDECL to OLDDECL.
@@ -1154,9 +1178,9 @@ diagnose_mismatched_decls (tree newdecl, tree olddecl,
       else if (TREE_PUBLIC (newdecl))
        warning (0, "%Jbuilt-in function %qD declared as non-function",
                 newdecl, newdecl);
-      else if (warn_shadow)
-       warning (0, "%Jdeclaration of %qD shadows a built-in function",
-                newdecl, newdecl);
+      else
+       warning (OPT_Wshadow, "%Jdeclaration of %qD shadows "
+                "a built-in function", newdecl, newdecl);
       return false;
     }
 
@@ -1270,9 +1294,8 @@ diagnose_mismatched_decls (tree newdecl, tree olddecl,
              || (DECL_INITIAL (newdecl)
                  && !TYPE_ARG_TYPES (TREE_TYPE (newdecl)))))
        {
-         if (warn_shadow)
-           warning (0, "%Jdeclaration of %qD shadows a built-in function",
-                    newdecl, newdecl);
+         warning (OPT_Wshadow, "%Jdeclaration of %qD shadows "
+                  "a built-in function", newdecl, newdecl);
          /* Discard the old built-in function.  */
          return false;
        }
@@ -1368,8 +1391,8 @@ diagnose_mismatched_decls (tree newdecl, tree olddecl,
            }
          else if (warn_traditional)
            {
-             warning (0, "%Jnon-static declaration of %qD follows "
-                      "static declaration", newdecl, newdecl);
+             warning (OPT_Wtraditional, "%Jnon-static declaration of %qD "
+                      "follows static declaration", newdecl, newdecl);
              warned = true;
            }
        }
@@ -1421,8 +1444,8 @@ diagnose_mismatched_decls (tree newdecl, tree olddecl,
                }
              else if (warn_traditional)
                {
-                 warning (0, "%Jnon-static declaration of %qD follows "
-                          "static declaration", newdecl, newdecl);
+                 warning (OPT_Wtraditional, "%Jnon-static declaration of %qD "
+                          "follows static declaration", newdecl, newdecl);
                  warned = true;
                }
            }
@@ -1481,15 +1504,15 @@ diagnose_mismatched_decls (tree newdecl, tree olddecl,
       if (DECL_DECLARED_INLINE_P (newdecl)
          && lookup_attribute ("noinline", DECL_ATTRIBUTES (olddecl)))
        {
-         warning (0, "%Jinline declaration of %qD follows "
+         warning (OPT_Wattributes, "%Jinline declaration of %qD follows "
                   "declaration with attribute noinline", newdecl, newdecl);
          warned = true;
        }
       else if (DECL_DECLARED_INLINE_P (olddecl)
               && lookup_attribute ("noinline", DECL_ATTRIBUTES (newdecl)))
        {
-         warning (0, "%Jdeclaration of %qD with attribute noinline follows "
-                  "inline declaration ", newdecl, newdecl);
+         warning (OPT_Wattributes, "%Jdeclaration of %qD with attribute "
+                  "noinline follows inline declaration ", newdecl, newdecl);
          warned = true;
        }
 
@@ -1553,7 +1576,8 @@ diagnose_mismatched_decls (tree newdecl, tree olddecl,
       && !(TREE_CODE (newdecl) == PARM_DECL
           && TREE_ASM_WRITTEN (olddecl) && !TREE_ASM_WRITTEN (newdecl)))
     {
-      warning (0, "%Jredundant redeclaration of %qD", newdecl, newdecl);
+      warning (OPT_Wredundant_decls, "%Jredundant redeclaration of %qD",
+              newdecl, newdecl);
       warned = true;
     }
 
@@ -1574,6 +1598,10 @@ merge_decls (tree newdecl, tree olddecl, tree newtype, tree oldtype)
 {
   int new_is_definition = (TREE_CODE (newdecl) == FUNCTION_DECL
                           && DECL_INITIAL (newdecl) != 0);
+  int new_is_prototype = (TREE_CODE (newdecl) == FUNCTION_DECL
+                         && TYPE_ARG_TYPES (TREE_TYPE (newdecl)) != 0);
+  int old_is_prototype = (TREE_CODE (olddecl) == FUNCTION_DECL
+                         && TYPE_ARG_TYPES (TREE_TYPE (olddecl)) != 0);
 
   /* For real parm decl following a forward decl, rechain the old decl
      in its new location and clear TREE_ASM_WRITTEN (it's not a
@@ -1647,8 +1675,12 @@ merge_decls (tree newdecl, tree olddecl, tree newtype, tree oldtype)
   if (TREE_DEPRECATED (newdecl))
     TREE_DEPRECATED (olddecl) = 1;
 
-  /* Keep source location of definition rather than declaration.  */
-  if (DECL_INITIAL (newdecl) == 0 && DECL_INITIAL (olddecl) != 0)
+  /* Keep source location of definition rather than declaration and of
+     prototype rather than non-prototype unless that prototype is
+     built-in.  */
+  if ((DECL_INITIAL (newdecl) == 0 && DECL_INITIAL (olddecl) != 0)
+      || (old_is_prototype && !new_is_prototype
+         && !C_DECL_BUILTIN_PROTOTYPE (olddecl)))
     DECL_SOURCE_LOCATION (newdecl) = DECL_SOURCE_LOCATION (olddecl);
 
   /* Merge the unused-warning information.  */
@@ -1764,6 +1796,11 @@ merge_decls (tree newdecl, tree olddecl, tree newtype, tree oldtype)
          DECL_BUILT_IN_CLASS (newdecl) = DECL_BUILT_IN_CLASS (olddecl);
          DECL_FUNCTION_CODE (newdecl) = DECL_FUNCTION_CODE (olddecl);
          C_DECL_DECLARED_BUILTIN (newdecl) = 1;
+         if (new_is_prototype)
+           C_DECL_BUILTIN_PROTOTYPE (newdecl) = 0;
+         else
+           C_DECL_BUILTIN_PROTOTYPE (newdecl)
+             = C_DECL_BUILTIN_PROTOTYPE (olddecl);
        }
 
       /* Also preserve various other info from the definition.  */
@@ -2008,11 +2045,52 @@ pushdecl (tree x)
   b = I_SYMBOL_BINDING (name);
   if (b && B_IN_SCOPE (b, scope))
     {
+      struct c_binding *b_ext, *b_use;
+      tree type = TREE_TYPE (x);
+      tree visdecl = b->decl;
+      tree vistype = TREE_TYPE (visdecl);
       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;
+      b_use = b;
+      b_ext = b;
+      /* If this is an external linkage declaration, we should check
+        for compatibility with the type in the external scope before
+        setting the type at this scope based on the visible
+        information only.  */
+      if (TREE_PUBLIC (x) && TREE_PUBLIC (visdecl))
+       {
+         while (b_ext && !B_IN_EXTERNAL_SCOPE (b_ext))
+           b_ext = b_ext->shadowed;
+         if (b_ext)
+           {
+             b_use = b_ext;
+             if (b_use->type)
+               TREE_TYPE (b_use->decl) = b_use->type;
+           }
+       }
+      if (duplicate_decls (x, b_use->decl))
+       {
+         if (b_use != b)
+           {
+             /* Save the updated type in the external scope and
+                restore the proper type for this scope.  */
+             tree thistype;
+             if (comptypes (vistype, type))
+               thistype = composite_type (vistype, type);
+             else
+               thistype = TREE_TYPE (b_use->decl);
+             b_use->type = TREE_TYPE (b_use->decl);
+             if (TREE_CODE (b_use->decl) == FUNCTION_DECL
+                 && DECL_BUILT_IN (b_use->decl))
+               thistype
+                 = build_type_attribute_variant (thistype,
+                                                 TYPE_ATTRIBUTES
+                                                 (b_use->type));
+             TREE_TYPE (b_use->decl) = thistype;
+           }
+         return b_use->decl;
+       }
       else
        goto skip_external_and_shadow_checks;
     }
@@ -2043,10 +2121,9 @@ pushdecl (tree x)
          visdecl = b->decl;
          vistype = TREE_TYPE (visdecl);
        }
-      if (warn_nested_externs
-         && scope != file_scope
+      if (scope != file_scope
          && !DECL_IN_SYSTEM_HEADER (x))
-       warning (0, "nested extern declaration of %qD", x);
+       warning (OPT_Wnested_externs, "nested extern declaration of %qD", x);
 
       while (b && !B_IN_EXTERNAL_SCOPE (b))
        {
@@ -2099,7 +2176,15 @@ pushdecl (tree x)
          && duplicate_decls (x, b->decl))
        {
          tree thistype;
-         thistype = (vistype ? composite_type (vistype, type) : type);
+         if (vistype)
+           {
+             if (comptypes (vistype, type))
+               thistype = composite_type (vistype, type);
+             else
+               thistype = TREE_TYPE (b->decl);
+           }
+         else
+           thistype = type;
          b->type = TREE_TYPE (b->decl);
          if (TREE_CODE (b->decl) == FUNCTION_DECL && DECL_BUILT_IN (b->decl))
            thistype
@@ -2197,7 +2282,7 @@ pushdecl_top_level (tree x)
 static void
 implicit_decl_warning (tree id, tree olddecl)
 {
-  void (*diag) (const char *, ...);
+  void (*diag) (const char *, ...) ATTRIBUTE_GCC_CDIAG(1,2);
   switch (mesg_implicit_function_declaration)
     {
     case 0: return;
@@ -2206,7 +2291,7 @@ implicit_decl_warning (tree id, tree olddecl)
     default: gcc_unreachable ();
     }
 
-  diag (N_("implicit declaration of function %qE"), id);
+  diag (G_("implicit declaration of function %qE"), id);
   if (olddecl)
     locate_old_decl (olddecl, diag);
 }
@@ -2481,9 +2566,9 @@ define_label (location_t location, tree name)
            /*invisible=*/false, /*nested=*/false);
     }
 
-  if (warn_traditional && !in_system_header && lookup_name (name))
-    warning (0, "%Htraditional C lacks a separate namespace for labels, "
-             "identifier %qE conflicts", &location, name);
+  if (!in_system_header && lookup_name (name))
+    warning (OPT_Wtraditional, "%Htraditional C lacks a separate namespace "
+             "for labels, identifier %qE conflicts", &location, name);
 
   nlist_se = XOBNEW (&parser_obstack, struct c_label_list);
   nlist_se->next = label_context_stack_se->labels_def;
@@ -2706,6 +2791,7 @@ builtin_function (const char *name, tree type, int function_code,
   DECL_LANG_SPECIFIC (decl) = GGC_CNEW (struct lang_decl);
   DECL_BUILT_IN_CLASS (decl) = cl;
   DECL_FUNCTION_CODE (decl) = function_code;
+  C_DECL_BUILTIN_PROTOTYPE (decl) = (TYPE_ARG_TYPES (type) != 0);
   if (library_name)
     SET_DECL_ASSEMBLER_NAME (decl, get_identifier (library_name));
 
@@ -3015,7 +3101,7 @@ start_decl (struct c_declarator *declarator, struct c_declspecs *declspecs,
 
   if (warn_main > 0 && TREE_CODE (decl) != FUNCTION_DECL
       && MAIN_NAME_P (DECL_NAME (decl)))
-    warning (0, "%J%qD is usually a function", decl, decl);
+    warning (OPT_Wmain, "%J%qD is usually a function", decl, decl);
 
   if (initialized)
     /* Is it valid for this decl to have an initializer at all?
@@ -3136,7 +3222,8 @@ start_decl (struct c_declarator *declarator, struct c_declspecs *declspecs,
       && DECL_DECLARED_INLINE_P (decl)
       && DECL_UNINLINABLE (decl)
       && lookup_attribute ("noinline", DECL_ATTRIBUTES (decl)))
-    warning (0, "%Jinline function %qD given attribute noinline", decl, decl);
+    warning (OPT_Wattributes, "%Jinline function %qD given attribute noinline",
+            decl, decl);
 
   /* Add this decl to the current scope.
      TEM may equal DECL or it may be a previous decl of the same name.  */
@@ -3204,11 +3291,13 @@ finish_decl (tree decl, tree init, tree asmspec_tree)
       /* Get the completed type made by complete_array_type.  */
       type = TREE_TYPE (decl);
 
-      if (failure == 1)
-       error ("%Jinitializer fails to determine size of %qD", decl, decl);
-
-      else if (failure == 2)
+      switch (failure)
        {
+       case 1:
+         error ("%Jinitializer fails to determine size of %qD", decl, decl);
+         break;
+
+       case 2:
          if (do_default)
            error ("%Jarray size missing in %qD", decl, decl);
          /* If a `static' var's size isn't known,
@@ -3219,9 +3308,33 @@ finish_decl (tree decl, tree init, tree asmspec_tree)
             and it will get allocated.  */
          else if (!pedantic && TREE_STATIC (decl) && !TREE_PUBLIC (decl))
            DECL_EXTERNAL (decl) = 1;
+         break;
+
+       case 3:
+         error ("%Jzero or negative size array %qD", decl, decl);
+         break;
+
+       case 0:
+         /* For global variables, update the copy of the type that
+            exists in the binding.  */
+         if (TREE_PUBLIC (decl))
+           {
+             struct c_binding *b_ext = I_SYMBOL_BINDING (DECL_NAME (decl));
+             while (b_ext && !B_IN_EXTERNAL_SCOPE (b_ext))
+               b_ext = b_ext->shadowed;
+             if (b_ext)
+               {
+                 if (b_ext->type)
+                   b_ext->type = composite_type (b_ext->type, type);
+                 else
+                   b_ext->type = type;
+               }
+           }
+         break;
+
+       default:
+         gcc_unreachable ();
        }
-      else if (failure == 3)
-       error ("%Jzero or negative size array %qD", decl, decl);
 
       if (DECL_INITIAL (decl))
        TREE_TYPE (DECL_INITIAL (decl)) = type;
@@ -3424,6 +3537,7 @@ finish_decl (tree decl, tree init, tree asmspec_tree)
                = init_one_libfunc (USING_SJLJ_EXCEPTIONS
                                    ? "__gcc_personality_sj0"
                                    : "__gcc_personality_v0");
+             default_init_unwind_resume_libfunc ();
              using_eh_for_cleanups ();
            }
 
@@ -4066,10 +4180,10 @@ grokdeclarator (const struct c_declarator *declarator,
                       - 1.  Do the calculation in index_type, so that
                       if it is a variable the computations will be
                       done in the proper mode.  */
-                   itype = fold (build2 (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
@@ -4078,7 +4192,8 @@ grokdeclarator (const struct c_declarator *declarator,
                       index_type, before the subtraction.  Handling
                       this case seems like an unnecessary
                       complication.  */
-                   if (TREE_OVERFLOW (itype))
+                   if (TREE_CODE (itype) == INTEGER_CST
+                       && TREE_OVERFLOW (itype))
                      {
                        error ("size of array %qs is too large", name);
                        type = error_mark_node;
@@ -4182,8 +4297,9 @@ grokdeclarator (const struct c_declarator *declarator,
                   them for noreturn functions.  */
                if (VOID_TYPE_P (type) && really_funcdef)
                  pedwarn ("function definition has qualified void return type");
-               else if (warn_return_type)
-                 warning (0, "type qualifiers ignored on function return type");
+               else
+                 warning (OPT_Wreturn_type,
+                          "type qualifiers ignored on function return type");
                
                type = c_build_qualified_type (type, type_quals);
              }
@@ -4242,6 +4358,7 @@ grokdeclarator (const struct c_declarator *declarator,
 
   if (TREE_CODE (type) == ARRAY_TYPE
       && COMPLETE_TYPE_P (type)
+      && TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST
       && TREE_OVERFLOW (TYPE_SIZE (type)))
     {
       error ("size of array %qs is too large", name);
@@ -4344,7 +4461,8 @@ grokdeclarator (const struct c_declarator *declarator,
 
            /* We don't yet implement attributes in this context.  */
            if (array_ptr_attrs != NULL_TREE)
-             warning (0, "attributes in parameter array declarator ignored");
+             warning (OPT_Wattributes,
+                      "attributes in parameter array declarator ignored");
 
            size_varies = 0;
          }
@@ -4624,9 +4742,9 @@ grokparms (struct c_arg_info *arg_info, bool funcdef_flag)
 {
   tree arg_types = arg_info->types;
 
-  if (warn_strict_prototypes && arg_types == 0 && !funcdef_flag
-      && !in_system_header)
-    warning (0, "function declaration isn%'t a prototype");
+  if (arg_types == 0 && !funcdef_flag && !in_system_header)
+    warning (OPT_Wstrict_prototypes,
+            "function declaration isn%'t a prototype");
 
   if (arg_types == error_mark_node)
     return 0;  /* don't set TYPE_ARG_TYPES in this case */
@@ -5686,14 +5804,19 @@ start_function (struct c_declspecs *declspecs, struct c_declarator *declarator,
   /* If the declarator is not suitable for a function definition,
      cause a syntax error.  */
   if (decl1 == 0)
-    return 0;
+    {
+      label_context_stack_se = label_context_stack_se->next;
+      label_context_stack_vm = label_context_stack_vm->next;
+      return 0;
+    }
 
   decl_attributes (&decl1, attributes, 0);
 
   if (DECL_DECLARED_INLINE_P (decl1)
       && DECL_UNINLINABLE (decl1)
       && lookup_attribute ("noinline", DECL_ATTRIBUTES (decl1)))
-    warning (0, "%Jinline function %qD given attribute noinline", decl1, decl1);
+    warning (OPT_Wattributes, "%Jinline function %qD given attribute noinline",
+            decl1, decl1);
 
   announce_function (decl1);
 
@@ -5716,14 +5839,53 @@ start_function (struct c_declspecs *declspecs, struct c_declarator *declarator,
   /* If this definition isn't a prototype and we had a prototype declaration
      before, copy the arg type info from that prototype.  */
   old_decl = lookup_name_in_scope (DECL_NAME (decl1), current_scope);
-  if (old_decl != 0 && TREE_CODE (TREE_TYPE (old_decl)) == FUNCTION_TYPE
-      && comptypes (TREE_TYPE (TREE_TYPE (decl1)),
-                   TREE_TYPE (TREE_TYPE (old_decl)))
-      && TYPE_ARG_TYPES (TREE_TYPE (decl1)) == 0)
-    {
-      TREE_TYPE (decl1) = composite_type (TREE_TYPE (old_decl),
-                                         TREE_TYPE (decl1));
-      current_function_prototype_locus = DECL_SOURCE_LOCATION (old_decl);
+  current_function_prototype_locus = UNKNOWN_LOCATION;
+  current_function_prototype_built_in = false;
+  current_function_prototype_arg_types = NULL_TREE;
+  if (TYPE_ARG_TYPES (TREE_TYPE (decl1)) == 0)
+    {
+      if (old_decl != 0 && TREE_CODE (TREE_TYPE (old_decl)) == FUNCTION_TYPE
+         && comptypes (TREE_TYPE (TREE_TYPE (decl1)),
+                       TREE_TYPE (TREE_TYPE (old_decl))))
+       {
+         TREE_TYPE (decl1) = composite_type (TREE_TYPE (old_decl),
+                                             TREE_TYPE (decl1));
+         current_function_prototype_locus = DECL_SOURCE_LOCATION (old_decl);
+         current_function_prototype_built_in
+           = C_DECL_BUILTIN_PROTOTYPE (old_decl);
+         current_function_prototype_arg_types
+           = TYPE_ARG_TYPES (TREE_TYPE (decl1));
+       }
+      if (TREE_PUBLIC (decl1))
+       {
+         /* If there is an external prototype declaration of this
+            function, record its location but do not copy information
+            to this decl.  This may be an invisible declaration
+            (built-in or in a scope which has finished) or simply
+            have more refined argument types than any declaration
+            found above.  */
+         struct c_binding *b;
+         for (b = I_SYMBOL_BINDING (DECL_NAME (decl1)); b; b = b->shadowed)
+           if (B_IN_SCOPE (b, external_scope))
+             break;
+         if (b)
+           {
+             tree ext_decl, ext_type;
+             ext_decl = b->decl;
+             ext_type = b->type ? b->type : TREE_TYPE (ext_decl);
+             if (TREE_CODE (ext_type) == FUNCTION_TYPE
+                 && comptypes (TREE_TYPE (TREE_TYPE (decl1)),
+                               TREE_TYPE (ext_type)))
+               {
+                 current_function_prototype_locus
+                   = DECL_SOURCE_LOCATION (ext_decl);
+                 current_function_prototype_built_in
+                   = C_DECL_BUILTIN_PROTOTYPE (ext_decl);
+                 current_function_prototype_arg_types
+                   = TYPE_ARG_TYPES (ext_type);
+               }
+           }
+       }
     }
 
   /* Optionally warn of old-fashioned def with no previous prototype.  */
@@ -5731,14 +5893,16 @@ start_function (struct c_declspecs *declspecs, struct c_declarator *declarator,
       && old_decl != error_mark_node
       && TYPE_ARG_TYPES (TREE_TYPE (decl1)) == 0
       && C_DECL_ISNT_PROTOTYPE (old_decl))
-    warning (0, "function declaration isn%'t a prototype");
+    warning (OPT_Wstrict_prototypes,
+            "function declaration isn%'t a prototype");
   /* Optionally warn of any global def with no previous prototype.  */
   else if (warn_missing_prototypes
           && old_decl != error_mark_node
           && TREE_PUBLIC (decl1)
           && !MAIN_NAME_P (DECL_NAME (decl1))
           && C_DECL_ISNT_PROTOTYPE (old_decl))
-    warning (0, "%Jno previous prototype for %qD", decl1, decl1);
+    warning (OPT_Wmissing_prototypes, "%Jno previous prototype for %qD",
+            decl1, decl1);
   /* Optionally warn of any def with no previous prototype
      if the function has already been used.  */
   else if (warn_missing_prototypes
@@ -5746,14 +5910,16 @@ start_function (struct c_declspecs *declspecs, struct c_declarator *declarator,
           && old_decl != error_mark_node
           && TREE_USED (old_decl)
           && TYPE_ARG_TYPES (TREE_TYPE (old_decl)) == 0)
-    warning (0, "%J%qD was used with no prototype before its definition",
+    warning (OPT_Wmissing_prototypes,
+            "%J%qD was used with no prototype before its definition",
             decl1, decl1);
   /* Optionally warn of any global def with no previous declaration.  */
   else if (warn_missing_declarations
           && TREE_PUBLIC (decl1)
           && old_decl == 0
           && !MAIN_NAME_P (DECL_NAME (decl1)))
-    warning (0, "%Jno previous declaration for %qD", decl1, decl1);
+    warning (OPT_Wmissing_declarations, "%Jno previous declaration for %qD",
+            decl1, decl1);
   /* Optionally warn of any def with no previous declaration
      if the function has already been used.  */
   else if (warn_missing_declarations
@@ -5761,7 +5927,8 @@ start_function (struct c_declspecs *declspecs, struct c_declarator *declarator,
           && old_decl != error_mark_node
           && TREE_USED (old_decl)
           && C_DECL_IMPLICIT (old_decl))
-    warning (0, "%J%qD was used with no declaration before its definition",
+    warning (OPT_Wmissing_declarations,
+            "%J%qD was used with no declaration before its definition",
             decl1, decl1);
 
   /* This is a definition, not a reference.
@@ -5897,9 +6064,10 @@ store_parm_decls_newstyle (tree fndecl, const struct c_arg_info *arg_info)
      warning if we got here because ARG_INFO_TYPES was error_mark_node
      (this happens when a function definition has just an ellipsis in
      its parameter list).  */
-  else if (warn_traditional && !in_system_header && !current_function_scope
+  else if (!in_system_header && !current_function_scope
           && arg_info->types != error_mark_node)
-    warning (0, "%Jtraditional C rejects ISO C style function definitions",
+    warning (OPT_Wtraditional,
+            "%Jtraditional C rejects ISO C style function definitions",
             fndecl);
 
   /* Now make all the parameter declarations visible in the function body.
@@ -5950,8 +6118,9 @@ store_parm_decls_oldstyle (tree fndecl, const struct c_arg_info *arg_info)
     gcc_assert (TREE_CODE (b->decl) != PARM_DECL || !DECL_WEAK (b->decl));
 #endif
 
-  if (warn_old_style_definition && !in_system_header)
-    warning (0, "%Jold-style function definition", fndecl);
+  if (!in_system_header)
+    warning (OPT_Wold_style_definition, "%Jold-style function definition",
+            fndecl);
 
   /* Match each formal parameter name with its declaration.  Save each
      decl in the appropriate TREE_PURPOSE slot of the parmids chain.  */
@@ -6000,7 +6169,8 @@ store_parm_decls_oldstyle (tree fndecl, const struct c_arg_info *arg_info)
          if (flag_isoc99)
            pedwarn ("%Jtype of %qD defaults to %<int%>", decl, decl);
          else if (extra_warnings)
-           warning (0, "%Jtype of %qD defaults to %<int%>", decl, decl);
+           warning (OPT_Wextra, "%Jtype of %qD defaults to %<int%>",
+                    decl, decl);
        }
 
       TREE_PURPOSE (parm) = decl;
@@ -6063,11 +6233,11 @@ store_parm_decls_oldstyle (tree fndecl, const struct c_arg_info *arg_info)
      set the DECL_ARG_TYPE of each argument according to
      the type previously specified, and report any mismatches.  */
 
-  if (TYPE_ARG_TYPES (TREE_TYPE (fndecl)))
+  if (current_function_prototype_arg_types)
     {
       tree type;
       for (parm = DECL_ARGUMENTS (fndecl),
-            type = TYPE_ARG_TYPES (TREE_TYPE (fndecl));
+            type = current_function_prototype_arg_types;
           parm || (type && (TYPE_MAIN_VARIANT (TREE_VALUE (type))
                             != void_type_node));
           parm = TREE_CHAIN (parm), type = TREE_CHAIN (type))
@@ -6075,9 +6245,15 @@ store_parm_decls_oldstyle (tree fndecl, const struct c_arg_info *arg_info)
          if (parm == 0 || type == 0
              || TYPE_MAIN_VARIANT (TREE_VALUE (type)) == void_type_node)
            {
-             error ("number of arguments doesn%'t match prototype");
-             error ("%Hprototype declaration",
-                    &current_function_prototype_locus);
+             if (current_function_prototype_built_in)
+               warning (0, "number of arguments doesn%'t match "
+                        "built-in prototype");
+             else
+               {
+                 error ("number of arguments doesn%'t match prototype");
+                 error ("%Hprototype declaration",
+                        &current_function_prototype_locus);
+               }
              break;
            }
          /* Type for passing arg must be consistent with that
@@ -6104,17 +6280,33 @@ store_parm_decls_oldstyle (tree fndecl, const struct c_arg_info *arg_info)
 
                  if (pedantic)
                    {
-                     pedwarn ("promoted argument %qD "
-                              "doesn%'t match prototype", parm);
-                     pedwarn ("%Hprototype declaration",
-                              &current_function_prototype_locus);
+                     /* ??? Is it possible to get here with a
+                        built-in prototype or will it always have
+                        been diagnosed as conflicting with an
+                        old-style definition and discarded?  */
+                     if (current_function_prototype_built_in)
+                       warning (0, "promoted argument %qD "
+                                "doesn%'t match built-in prototype", parm);
+                     else
+                       {
+                         pedwarn ("promoted argument %qD "
+                                  "doesn%'t match prototype", parm);
+                         pedwarn ("%Hprototype declaration",
+                                  &current_function_prototype_locus);
+                       }
                    }
                }
              else
                {
-                 error ("argument %qD doesn%'t match prototype", parm);
-                 error ("%Hprototype declaration",
-                        &current_function_prototype_locus);
+                 if (current_function_prototype_built_in)
+                   warning (0, "argument %qD doesn%'t match "
+                            "built-in prototype", parm);
+                 else
+                   {
+                     error ("argument %qD doesn%'t match prototype", parm);
+                     error ("%Hprototype declaration",
+                            &current_function_prototype_locus);
+                   }
                }
            }
        }
@@ -6332,14 +6524,18 @@ finish_function (void)
       /* Normally, with -Wreturn-type, flow will complain.  Unless we're an
         inline function, as we might never be compiled separately.  */
       && DECL_INLINE (fndecl))
-    warning (0, "no return statement in function returning non-void");
+    {
+      warning (OPT_Wreturn_type,
+              "no return statement in function returning non-void");
+      TREE_NO_WARNING (fndecl) = 1;
+    }
 
   /* With just -Wextra, complain only if function returns both with
      and without a value.  */
   if (extra_warnings
       && current_function_returns_value
       && current_function_returns_null)
-    warning (0, "this function may return with or without a value");
+    warning (OPT_Wextra, "this function may return with or without a value");
 
   /* Store the end of the function, so that we get good line number
      info for the epilogue.  */
@@ -6560,16 +6756,6 @@ c_dup_lang_specific_decl (tree decl)
    functions are not called from anywhere in the C front end, but as
    these changes continue, that will change.  */
 
-/* Returns nonzero if the current statement is a full expression,
-   i.e. temporaries created during that statement should be destroyed
-   at the end of the statement.  */
-
-int
-stmts_are_full_exprs_p (void)
-{
-  return 0;
-}
-
 /* Returns the stmt_tree (if any) to which statements are currently
    being added.  If there is no active statement-tree, NULL is
    returned.  */
@@ -7087,7 +7273,7 @@ declspecs_add_scspec (struct c_declspecs *specs, tree scspec)
              && C_IS_RESERVED_WORD (scspec));
   i = C_RID_CODE (scspec);
   if (extra_warnings && specs->non_sc_seen_p)
-    warning (0, "%qE is not at beginning of declaration", scspec);
+    warning (OPT_Wextra, "%qE is not at beginning of declaration", scspec);
   switch (i)
     {
     case RID_INLINE: