c-decl.c (duplicate_decls): Break apart into...
authorZack Weinberg <zack@codesourcery.com>
Sun, 11 Jan 2004 01:18:58 +0000 (01:18 +0000)
committerZack Weinberg <zack@gcc.gnu.org>
Sun, 11 Jan 2004 01:18:58 +0000 (01:18 +0000)
* c-decl.c (duplicate_decls): Break apart into...
(diagnose_arglist_conflict, validate_proto_after_old_defn)
(locate_old_defn, diagnose_mismatched_decls, merge_decls):
... these new functions.  Restructure for comprehensibility.
Remove various archaic special cases.  Always report the
location of the previous declaration when a diagnostic is issued.
(redeclaration_error_message): Fold into diagnose_mismatched_decls.
(match_builtin_function_types): Delete unnecessary forward declaration.
testsuite:
* gcc.dg/Wshadow-1.c, gcc.dg/attr-noinline.c, gcc.dg/decl3.c
* gcc.dg/redecl-1.c, gcc.dg/visibility-7.c, gcc.dg/wtr-static-1.c
* gcc.dg/noncompile/20020220-1.c, objc.dg/method-1.m:
Update dg-error regexps.

From-SVN: r75667

12 files changed:
gcc/ChangeLog
gcc/c-decl.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/Wshadow-1.c
gcc/testsuite/gcc.dg/attr-noinline.c
gcc/testsuite/gcc.dg/decl-3.c
gcc/testsuite/gcc.dg/noncompile/20020213-1.c
gcc/testsuite/gcc.dg/noncompile/20020220-1.c
gcc/testsuite/gcc.dg/redecl-1.c
gcc/testsuite/gcc.dg/visibility-7.c
gcc/testsuite/gcc.dg/wtr-static-1.c
gcc/testsuite/objc.dg/method-1.m

index 2ac7526..4c0fa09 100644 (file)
@@ -1,5 +1,16 @@
 2004-01-10  Zack Weinberg  <zack@codesourcery.com>
 
+       * c-decl.c (duplicate_decls): Break apart into...
+       (diagnose_arglist_conflict, validate_proto_after_old_defn)
+       (locate_old_defn, diagnose_mismatched_decls, merge_decls):
+       ... these new functions.  Restructure for comprehensibility.
+       Remove various archaic special cases.  Always report the
+       location of the previous declaration when a diagnostic is issued.
+       (redeclaration_error_message): Fold into diagnose_mismatched_decls.
+       (match_builtin_function_types): Delete unnecessary forward declaration.
+
+2004-01-10  Zack Weinberg  <zack@codesourcery.com>
+
        * genautomata.c (make_automaton, NDFA_to_DFA):
        Print progress bars with '.' characters instead of '*'.
        (build_automaton): Change notes to match.
index b41ed86..639ad22 100644 (file)
@@ -306,9 +306,6 @@ tree static_ctors, static_dtors;
 
 static struct c_scope *make_scope (void);
 static void pop_scope (void);
-static tree match_builtin_function_types (tree, tree);
-static int duplicate_decls (tree, tree, int, int);
-static int redeclaration_error_message (tree, tree);
 static tree make_label (tree, location_t);
 static void bind_label (tree, tree, struct c_scope *);
 static void implicit_decl_warning (tree);
@@ -755,12 +752,12 @@ pushtag (tree name, tree type)
   TYPE_CONTEXT (type) = DECL_CONTEXT (TYPE_STUB_DECL (type));
 }
 \f
-/* Subroutine of duplicate_decls.  Allow harmless mismatches in return
+/* Subroutine of compare_decls.  Allow harmless mismatches in return
    and argument types provided that the type modes match.  This function
    return a unified type given a suitable match, and 0 otherwise.  */
 
 static tree
-match_builtin_function_types (tree oldtype, tree newtype)
+match_builtin_function_types (tree newtype, tree oldtype)
 {
   tree newrettype, oldrettype;
   tree newargs, oldargs;
@@ -795,121 +792,227 @@ match_builtin_function_types (tree oldtype, tree newtype)
   return build_type_attribute_variant (trytype, TYPE_ATTRIBUTES (oldtype));
 }
 
-/* Handle when a new declaration NEWDECL
-   has the same name as an old one OLDDECL
-   in the same binding contour.
-   Prints an error message if appropriate.
+/* Subroutine of diagnose_mismathed_decls.  Check for function type
+   mismatch involving an empty arglist vs a nonempty one and give clearer
+   diagnostics. */
+static void
+diagnose_arglist_conflict (tree newdecl, tree olddecl,
+                          tree newtype, tree oldtype)
+{
+  tree t;
 
-   If safely possible, alter OLDDECL to look like NEWDECL, and return 1.
-   Otherwise, return 0.
+  if (TREE_CODE (olddecl) != FUNCTION_DECL
+      || !comptypes (TREE_TYPE (oldtype), TREE_TYPE (newtype), COMPARE_STRICT)
+      || !((TYPE_ARG_TYPES (oldtype) == 0 && DECL_INITIAL (olddecl) == 0)
+          ||
+          (TYPE_ARG_TYPES (newtype) == 0 && DECL_INITIAL (newdecl) == 0)))
+    return;
 
-   When DIFFERENT_BINDING_LEVEL is true, NEWDECL is an external declaration,
-   and OLDDECL is in an outer scope and should thus not be changed.  */
+  t = TYPE_ARG_TYPES (oldtype);
+  if (t == 0)
+    t = TYPE_ARG_TYPES (newtype);
+  for (; t; t = TREE_CHAIN (t))
+    {
+      tree type = TREE_VALUE (t);
 
-static int
-duplicate_decls (tree newdecl, tree olddecl, int different_binding_level,
-                int different_tu)
-{
-  int types_match = comptypes (TREE_TYPE (newdecl), TREE_TYPE (olddecl),
-                              COMPARE_STRICT);
-  int new_is_definition = (TREE_CODE (newdecl) == FUNCTION_DECL
-                          && DECL_INITIAL (newdecl) != 0);
-  tree oldtype = TREE_TYPE (olddecl);
-  tree newtype = TREE_TYPE (newdecl);
-  int errmsg = 0;
+      if (TREE_CHAIN (t) == 0
+         && TYPE_MAIN_VARIANT (type) != void_type_node)
+       {
+         inform ("a parameter list with an ellipsis can't match"
+                 "an empty parameter name list declaration");
+         break;
+       }
 
-  if (DECL_P (olddecl))
-    {
-      if (TREE_CODE (newdecl) == FUNCTION_DECL
-         && TREE_CODE (olddecl) == FUNCTION_DECL
-         && (DECL_UNINLINABLE (newdecl) || DECL_UNINLINABLE (olddecl)))
+      if (c_type_promotes_to (type) != type)
        {
-         if (DECL_DECLARED_INLINE_P (newdecl)
-             && DECL_UNINLINABLE (newdecl)
-             && lookup_attribute ("noinline", DECL_ATTRIBUTES (newdecl)))
-           /* Already warned elsewhere.  */;
-         else if (DECL_DECLARED_INLINE_P (olddecl)
-                  && DECL_UNINLINABLE (olddecl)
-                  && lookup_attribute ("noinline", DECL_ATTRIBUTES (olddecl)))
-           /* Already warned.  */;
-         else if (DECL_DECLARED_INLINE_P (newdecl)
-                  && ! DECL_DECLARED_INLINE_P (olddecl)
-                  && DECL_UNINLINABLE (olddecl)
-                  && lookup_attribute ("noinline", DECL_ATTRIBUTES (olddecl)))
-           {
-             warning ("%Jfunction '%D' redeclared as inline",
-                      newdecl, newdecl);
-             warning ("%Jprevious declaration of function '%D' "
-                       "with attribute noinline", olddecl, olddecl);
-           }
-         else if (DECL_DECLARED_INLINE_P (olddecl)
-                  && DECL_UNINLINABLE (newdecl)
-                  && lookup_attribute ("noinline", DECL_ATTRIBUTES (newdecl)))
-           {
-             warning ("%Jfunction '%D' redeclared with attribute noinline",
-                       newdecl, newdecl);
-             warning ("%Jprevious declaration of function '%D' was inline",
-                       olddecl, olddecl);
-           }
+         inform ("an argument type that has a default promotion can't match"
+                 "an empty parameter name list declaration");
+         break;
        }
+    }
+}
 
-      DECL_ATTRIBUTES (newdecl)
-       = (*targetm.merge_decl_attributes) (olddecl, newdecl);
+/* Another subroutine of diagnose_mismatched_decls.  OLDDECL is an
+   old-style function definition, NEWDECL is a prototype declaration.
+   Diagnose inconsistencies in the argument list.  Returns TRUE if
+   the prototype is compatible, FALSE if not.  */
+static bool
+validate_proto_after_old_defn (tree newdecl, tree newtype, tree oldtype)
+{
+  tree type, parm;
+  int nargs;
+  /* Prototype decl follows defn w/o prototype.  */
+
+  for (parm = TYPE_ACTUAL_ARG_TYPES (oldtype),
+        type = TYPE_ARG_TYPES (newtype),
+        nargs = 1;
+       ;
+       parm = TREE_CHAIN (parm), type = TREE_CHAIN (type), nargs++)
+    {
+      if (TYPE_MAIN_VARIANT (TREE_VALUE (parm)) == void_type_node
+         && TYPE_MAIN_VARIANT (TREE_VALUE (type)) == void_type_node)
+       {
+         /* End of list.  */
+         warning ("%Jprototype for '%D' follows non-prototype definition",
+                  newdecl, newdecl);
+         return true;
+       }
+
+      if (TYPE_MAIN_VARIANT (TREE_VALUE (parm)) == void_type_node
+         || TYPE_MAIN_VARIANT (TREE_VALUE (type)) == void_type_node)
+       {
+         error ("%Jprototype for '%D' with different number of arguments "
+                "follows non-prototype definition", newdecl, newdecl);
+         return false;
+       }
+      /* Type for passing arg must be consistent
+        with that declared for the arg.  */
+      if (! comptypes (TREE_VALUE (parm), TREE_VALUE (type),
+                      COMPARE_STRICT))
+       {
+         error ("%Jprototype for '%D' with incompatible argument %d "
+                "follows non-prototype definition", newdecl, newdecl, nargs);
+         return false;
+       }
     }
+}
+
+/* Subroutine of diagnose_mismatched_decls.  Report the location of DECL,
+   first in a pair of mismatched declarations, using the diagnostic
+   function DIAG.  */
+static void
+locate_old_decl (tree decl, void (*diag)(const char *, ...))
+{
+  if (TREE_CODE (decl) == FUNCTION_DECL && DECL_BUILT_IN (decl))
+    ;
+  else if (DECL_INITIAL (decl))
+    diag (N_("%Jprevious definition of '%D' was here"), decl, decl);
+  else if (C_DECL_IMPLICIT (decl))
+    diag (N_("%Jprevious implicit declaration of '%D' was here"), decl, decl);
+  else
+    diag (N_("%Jprevious declaration of '%D' was here"), decl, decl);
+}
 
-  if (TREE_CODE (newtype) == ERROR_MARK
-      || TREE_CODE (oldtype) == ERROR_MARK)
-    types_match = 0;
+/* Subroutine of duplicate_decls.  Compare NEWDECL to OLDDECL.
+   Returns true if the caller should proceed to merge the two, false
+   if OLDDECL should simply be discarded.  As a side effect, issues
+   all necessary diagnostics for invalid or poor-style combinations.
+   If it returns true, writes the types of NEWDECL and OLDDECL to
+   *NEWTYPEP and *OLDTYPEP - these may have been adjusted from
+   TREE_TYPE (NEWDECL, OLDDECL) respectively.  */
 
-  /* New decl is completely inconsistent with the old one =>
-     tell caller to replace the old one.
-     This is always an error except in the case of shadowing a builtin.  */
+static bool
+diagnose_mismatched_decls (tree newdecl, tree olddecl,
+                          tree *newtypep, tree *oldtypep)
+{
+  tree newtype, oldtype;
+  bool pedwarned = false;
+  bool warned = false;
+
+  /* If we have error_mark_node for either decl or type, just discard
+     the previous decl - we're in an error cascade already.  */
+  if (olddecl == error_mark_node || newdecl == error_mark_node)
+    return false;
+  oldtype = TREE_TYPE (olddecl);
+  newtype = TREE_TYPE (newdecl);
+  if (oldtype == error_mark_node || newtype == error_mark_node)
+    return false;
+
+  /* Two different categories of symbol altogether.  This is an error
+     unless OLDDECL is a builtin.  OLDDECL will be discarded in any case.  */
   if (TREE_CODE (olddecl) != TREE_CODE (newdecl))
     {
-      if (TREE_CODE (olddecl) == FUNCTION_DECL
-         && DECL_BUILT_IN (olddecl))
+      if (TREE_CODE (olddecl) != FUNCTION_DECL || !DECL_BUILT_IN (olddecl))
        {
-         /* If you declare a built-in or predefined function name as static,
-            the old definition is overridden,
-            but optionally warn this was a bad choice of name.  */
-         if (!TREE_PUBLIC (newdecl))
+         error ("%J'%D' redeclared as different kind of symbol",
+                newdecl, newdecl);
+         locate_old_decl (olddecl, error);
+       }
+      else if (TREE_PUBLIC (newdecl))
+       warning ("%Jbuilt-in function '%D' declared as non-function",
+                newdecl, newdecl);
+      else if (warn_shadow)
+       warning ("%Jshadowing built-in function '%D'",
+                newdecl, newdecl);
+      return false;
+    }
+
+  if (!comptypes (oldtype, newtype, COMPARE_STRICT))
+    {
+      if (TREE_CODE (olddecl) == FUNCTION_DECL && DECL_BUILT_IN (olddecl))
+       {
+         /* Accept harmless mismatch in function types.
+            This is for the ffs and fprintf builtins.  */
+         tree trytype = match_builtin_function_types (newtype, oldtype);
+
+         if (trytype && comptypes (newtype, trytype, COMPARE_STRICT))
+           oldtype = trytype;
+         else
            {
-             if (warn_shadow)
-               warning ("%Jshadowing built-in function '%D'",
-                        newdecl, newdecl);
+             /* If types don't match for a built-in, throw away the
+                built-in.  No point in calling locate_old_decl here, it
+                won't print anything. */
+             warning ("%Jconflicting types for built-in function '%D'",
+                      newdecl, newdecl);
+             return false;
            }
-         else
-           warning ("%Jbuilt-in function '%D' declared as non-function",
-                     newdecl, newdecl);
+       }
+      else if (TREE_CODE (olddecl) == FUNCTION_DECL
+              && DECL_SOURCE_LINE (olddecl) == 0)
+       {
+         /* A conflicting function declaration for a predeclared
+            function that isn't actually built in.  Objective C uses
+            these.  The new declaration silently overrides everything
+            but the volatility (i.e. noreturn) indication.  See also
+            below.  FIXME: Make Objective C use normal builtins.  */
+         TREE_THIS_VOLATILE (newdecl) |= TREE_THIS_VOLATILE (olddecl);
+         return false;
+       }
+      /* Permit void foo (...) to match int foo (...) if the latter is
+        the definition and implicit int was used.  See
+        c-torture/compile/920625-2.c.  */
+      else if (TREE_CODE (newdecl) == FUNCTION_DECL && DECL_INITIAL (newdecl)
+              && TYPE_MAIN_VARIANT (TREE_TYPE (oldtype)) == void_type_node
+              && TYPE_MAIN_VARIANT (TREE_TYPE (newtype)) == integer_type_node
+              && C_FUNCTION_IMPLICIT_INT (newdecl))
+       {
+         pedwarn ("%Jconflicting types for '%D'", newdecl, newdecl);
+         /* Make sure we keep void as the return type.  */
+         TREE_TYPE (newdecl) = newtype = oldtype;
+         C_FUNCTION_IMPLICIT_INT (newdecl) = 0;
+         pedwarned = true;
        }
       else
        {
-         error ("%J'%D' redeclared as different kind of symbol",
-                newdecl, newdecl);
-         error ("%Jprevious declaration of '%D'", olddecl, olddecl);
+         error ("%Jconflicting types for '%D'", newdecl, newdecl);
+         diagnose_arglist_conflict (newdecl, olddecl, newtype, oldtype);
+         locate_old_decl (olddecl, error);
+         return false;
        }
-
-      return 0;
     }
 
-  /* For real parm decl following a forward decl, return 1 so old decl
-     will be reused.  Only allow this to happen once.  */
-  if (types_match && TREE_CODE (newdecl) == PARM_DECL
-      && TREE_ASM_WRITTEN (olddecl) && ! TREE_ASM_WRITTEN (newdecl))
+  /* Redeclaration of a type is a constraint violation (6.7.2.3p1),
+     but silently ignore the redeclaration if either is in a system
+     header.  (Conflicting redeclarations were handled above.)  */
+  if (TREE_CODE (newdecl) == TYPE_DECL)
     {
-      TREE_ASM_WRITTEN (olddecl) = 0;
-      return 1;
+      if (DECL_IN_SYSTEM_HEADER (newdecl) || DECL_IN_SYSTEM_HEADER (olddecl))
+       return true;  /* allow OLDDECL to continue in use */
+      
+      error ("%Jredefinition of typedef '%D'", newdecl, newdecl);
+      locate_old_decl (olddecl, error);
+      return false;
     }
 
-  /* The new declaration is the same kind of object as the old one.
-     The declarations may partially match.  Print warnings if they don't
-     match enough.  Ultimately, copy most of the information from the new
-     decl to the old one, and keep using the old one.  */
-
-  if (TREE_CODE (olddecl) == FUNCTION_DECL && DECL_BUILT_IN (olddecl))
+  /* Function declarations can either be 'static' or 'extern' (no
+     qualifier is equivalent to 'extern' - C99 6.2.2p5) and therefore
+     can never conflict with each other on account of linkage (6.2.2p4).
+     Multiple definitions are not allowed (6.9p3,5) but GCC permits
+     two definitions if one is 'extern inline' and one is not.  The non-
+     extern-inline definition supersedes the extern-inline definition.  */
+  else if (TREE_CODE (newdecl) == FUNCTION_DECL)
     {
-      /* A function declaration for a built-in function.  */
-      if (!TREE_PUBLIC (newdecl))
+      if (DECL_BUILT_IN (olddecl) && !TREE_PUBLIC (newdecl))
        {
          /* If you declare a built-in function name as static, the
             built-in definition is overridden,
@@ -917,458 +1020,355 @@ duplicate_decls (tree newdecl, tree olddecl, int different_binding_level,
          if (warn_shadow)
            warning ("%Jshadowing built-in function '%D'", newdecl, newdecl);
          /* Discard the old built-in function.  */
-         return 0;
+         return false;
        }
-      if (!types_match)
+      
+      if (DECL_INITIAL (newdecl))
        {
-         /* Accept harmless mismatch in function types.
-            This is for the ffs and fprintf builtins.  */
-         tree trytype = match_builtin_function_types (oldtype, newtype);
-
-         if (trytype)
+         if (DECL_INITIAL (olddecl)
+             && !(DECL_DECLARED_INLINE_P (olddecl)
+                  && DECL_EXTERNAL (olddecl)
+                  && !(DECL_DECLARED_INLINE_P (newdecl)
+                       && DECL_EXTERNAL (newdecl))))
            {
-             types_match = comptypes (newtype, trytype, COMPARE_STRICT);
-             if (types_match)
-               oldtype = trytype;
-             if (! different_binding_level)
-               TREE_TYPE (olddecl) = oldtype;
+             error ("%Jredefinition of '%D'", newdecl, newdecl);
+             locate_old_decl (olddecl, error);
+             return false;
            }
        }
-      if (!types_match)
+      /* If we have a prototype after an old-style function definition,
+        the argument types must be checked specially.  */
+      else if (DECL_INITIAL (olddecl)
+              && !TYPE_ARG_TYPES (oldtype) && TYPE_ARG_TYPES (newtype)
+              && TYPE_ACTUAL_ARG_TYPES (oldtype)
+              && !validate_proto_after_old_defn (newdecl, newtype, oldtype))
        {
-         /* If types don't match for a built-in, throw away the built-in.  */
-         warning ("%Jconflicting types for built-in function '%D'",
-                  newdecl, newdecl);
-         return 0;
+         locate_old_decl (olddecl, error);
+         return false;
+       }
+      /* Mismatched non-static and static is considered poor style.
+         We only diagnose static then non-static if -Wtraditional,
+        because it is the most convenient way to get some effects
+        (see e.g.  what unwind-dw2-fde-glibc.c does to the definition
+        of _Unwind_Find_FDE in unwind-dw2-fde.c).  Revisit?  */
+      if (TREE_PUBLIC (olddecl) && !TREE_PUBLIC (newdecl))
+       {
+         /* A static function declaration for a predeclared function
+            that isn't actually built in, silently overrides the
+            default.  Objective C uses these.  See also above.
+            FIXME: Make Objective C use normal builtins.  */
+         if (TREE_CODE (olddecl) == FUNCTION_DECL
+             && DECL_SOURCE_LINE (olddecl) == 0)
+           return false;
+         else
+           {
+             warning ("%Jstatic declaration of '%D' follows "
+                      "non-static declaration", newdecl, newdecl);
+             warned = true;
+           }
+       }
+      else if (TREE_PUBLIC (newdecl) && !TREE_PUBLIC (olddecl)
+              && warn_traditional)
+       {
+         warning ("%Jnon-static declaration of '%D' follows "
+                  "static declaration", newdecl, newdecl);
+         warned = true;
        }
     }
-  else if (TREE_CODE (olddecl) == FUNCTION_DECL
-          && DECL_SOURCE_LINE (olddecl) == 0)
+  else if (TREE_CODE (newdecl) == VAR_DECL)
     {
-      /* A function declaration for a predeclared function
-        that isn't actually built in.  */
-      if (!TREE_PUBLIC (newdecl))
+      /* Only variables can be thread-local, and all declarations must
+        agree on this property.  */
+      if (DECL_THREAD_LOCAL (newdecl) != DECL_THREAD_LOCAL (olddecl))
        {
-         /* If you declare it as static, the
-            default definition is overridden.  */
-         return 0;
+         if (DECL_THREAD_LOCAL (newdecl))
+           error ("%Jthread-local declaration of '%D' follows "
+                  "non-thread-local declaration", newdecl, newdecl);
+         else
+           error ("%Jnon-thread-local declaration of '%D' follows "
+                  "thread-local declaration", newdecl, newdecl);
+
+         locate_old_decl (olddecl, error);
+         return false;
        }
-      else if (!types_match)
+
+      /* Multiple initialized definitions are not allowed (6.9p3,5).  */
+      if (DECL_INITIAL (newdecl) && DECL_INITIAL (olddecl))
        {
-         /* If the types don't match, preserve volatility indication.
-            Later on, we will discard everything else about the
-            default declaration.  */
-         TREE_THIS_VOLATILE (newdecl) |= TREE_THIS_VOLATILE (olddecl);
+         error ("%Jredefinition of '%D'", newdecl, newdecl);
+         locate_old_decl (olddecl, error);
+         return false;
        }
-    }
-  /* Permit char *foo () to match void *foo (...) if not pedantic,
-     if one of them came from a system header file.  */
-  else if (!types_match
-          && TREE_CODE (olddecl) == FUNCTION_DECL
-          && TREE_CODE (newdecl) == FUNCTION_DECL
-          && TREE_CODE (TREE_TYPE (oldtype)) == POINTER_TYPE
-          && TREE_CODE (TREE_TYPE (newtype)) == POINTER_TYPE
-          && (DECL_IN_SYSTEM_HEADER (olddecl)
-              || DECL_IN_SYSTEM_HEADER (newdecl))
-          && ((TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (newtype))) == void_type_node
-               && TYPE_ARG_TYPES (oldtype) == 0
-               && self_promoting_args_p (TYPE_ARG_TYPES (newtype))
-               && TREE_TYPE (TREE_TYPE (oldtype)) == char_type_node)
-              ||
-              (TREE_TYPE (TREE_TYPE (newtype)) == char_type_node
-               && TYPE_ARG_TYPES (newtype) == 0
-               && self_promoting_args_p (TYPE_ARG_TYPES (oldtype))
-               && TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (oldtype))) == void_type_node)))
-    {
-      if (pedantic)
-       pedwarn ("%Jconflicting types for '%D'", newdecl, newdecl);
-      /* Make sure we keep void * as ret type, not char *.  */
-      if (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (oldtype))) == void_type_node)
-       TREE_TYPE (newdecl) = newtype = oldtype;
-
-      /* Set DECL_IN_SYSTEM_HEADER, so that if we see another declaration
-        we will come back here again.  */
-      DECL_IN_SYSTEM_HEADER (newdecl) = 1;
-    }
-  /* Permit void foo (...) to match int foo (...) if the latter is the
-     definition and implicit int was used.  See c-torture/compile/920625-2.c.  */
-  else if (!types_match        && new_is_definition
-          && TREE_CODE (olddecl) == FUNCTION_DECL
-          && TREE_CODE (newdecl) == FUNCTION_DECL
-          && TYPE_MAIN_VARIANT (TREE_TYPE (oldtype)) == void_type_node
-          && TYPE_MAIN_VARIANT (TREE_TYPE (newtype)) == integer_type_node
-          && C_FUNCTION_IMPLICIT_INT (newdecl))
-    {
-      pedwarn ("%Jconflicting types for '%D'", newdecl, newdecl);
-      /* Make sure we keep void as the return type.  */
-      TREE_TYPE (newdecl) = newtype = oldtype;
-      C_FUNCTION_IMPLICIT_INT (newdecl) = 0;
-    }
-  else if (!types_match
-          /* Permit char *foo (int, ...); followed by char *foo ();
-             if not pedantic.  */
-          && ! (TREE_CODE (olddecl) == FUNCTION_DECL
-                && ! pedantic
-                /* Return types must still match.  */
-                && comptypes (TREE_TYPE (oldtype),
-                              TREE_TYPE (newtype), COMPARE_STRICT)
-                && TYPE_ARG_TYPES (newtype) == 0))
-    {
-      error ("%Jconflicting types for '%D'", newdecl, newdecl);
-      /* Check for function type mismatch
-        involving an empty arglist vs a nonempty one.  */
-      if (TREE_CODE (olddecl) == FUNCTION_DECL
-         && comptypes (TREE_TYPE (oldtype),
-                       TREE_TYPE (newtype), COMPARE_STRICT)
-         && ((TYPE_ARG_TYPES (oldtype) == 0
-              && DECL_INITIAL (olddecl) == 0)
-             ||
-             (TYPE_ARG_TYPES (newtype) == 0
-              && DECL_INITIAL (newdecl) == 0)))
+
+      /* Objects declared at file scope: if at least one is 'extern',
+        it's fine (6.2.2p4); otherwise the linkage must agree (6.2.2p7).  */
+      if (DECL_FILE_SCOPE_P (newdecl))
        {
-         /* Classify the problem further.  */
-         tree t = TYPE_ARG_TYPES (oldtype);
-         if (t == 0)
-           t = TYPE_ARG_TYPES (newtype);
-         for (; t; t = TREE_CHAIN (t))
+         if (!DECL_EXTERNAL (newdecl)
+             && !DECL_EXTERNAL (olddecl)
+             && TREE_PUBLIC (newdecl) != TREE_PUBLIC (olddecl))
            {
-             tree type = TREE_VALUE (t);
-
-             if (TREE_CHAIN (t) == 0
-                 && TYPE_MAIN_VARIANT (type) != void_type_node)
-               {
-                 error ("a parameter list with an ellipsis can't match an empty parameter name list declaration");
-                 break;
-               }
+             if (TREE_PUBLIC (newdecl))
+               error ("%Jnon-static declaration of '%D' follows "
+                      "static declaration", newdecl, newdecl);
+             else
+               error ("%Jstatic declaration of '%D' follows "
+                      "non-static declaration", newdecl, newdecl);
 
-             if (c_type_promotes_to (type) != type)
-               {
-                 error ("an argument type that has a default promotion can't match an empty parameter name list declaration");
-                 break;
-               }
+             locate_old_decl (olddecl, error);
+             return false;
            }
        }
-      if (C_DECL_IMPLICIT (olddecl))
-       error ("%Jprevious implicit declaration of '%D'", olddecl, olddecl);
-      else
-       error ("%Jprevious declaration of '%D'", olddecl, olddecl);
+      /* Two objects with the same name declared at the same block
+        scope must both be external references (6.7p3).  */
+      else if (DECL_CONTEXT (newdecl) == DECL_CONTEXT (olddecl)
+              && (!DECL_EXTERNAL (newdecl) || !DECL_EXTERNAL (olddecl)))
+       {
+         if (DECL_EXTERNAL (newdecl))
+           error ("%Jextern declaration of '%D' follows "
+                  "declaration with no linkage", newdecl, newdecl);
+         else if (DECL_EXTERNAL (olddecl))
+           error ("%Jdeclaration of '%D' with no linkage follows "
+                  "extern declaration", newdecl, newdecl);
+         else
+           error ("%Jredeclaration of '%D' with no linkage",
+                  newdecl, newdecl);
 
-      /* This is safer because the initializer might contain references
-        to variables that were declared between olddecl and newdecl. This
-        will make the initializer invalid for olddecl in case it gets
-        assigned to olddecl below.  */
-      if (TREE_CODE (newdecl) == VAR_DECL)
-       DECL_INITIAL (newdecl) = 0;
-    }
-  /* TLS cannot follow non-TLS declaration.  */
-  else if (TREE_CODE (olddecl) == VAR_DECL && TREE_CODE (newdecl) == VAR_DECL
-          && !DECL_THREAD_LOCAL (olddecl) && DECL_THREAD_LOCAL (newdecl))
-    {
-      error ("%Jthread-local declaration of '%D' follows non thread-local "
-             "declaration", newdecl, newdecl);
-      error ("%Jprevious declaration of '%D'", olddecl, olddecl);
+         locate_old_decl (olddecl, error);
+         return false;
+       }
     }
-  /* non-TLS declaration cannot follow TLS declaration.  */
-  else if (TREE_CODE (olddecl) == VAR_DECL && TREE_CODE (newdecl) == VAR_DECL
-          && DECL_THREAD_LOCAL (olddecl) && !DECL_THREAD_LOCAL (newdecl))
+
+  /* warnings */
+  /* All decls must agree on a non-default visibility.  */
+  if (DECL_VISIBILITY (newdecl) != VISIBILITY_DEFAULT
+      && DECL_VISIBILITY (olddecl) != VISIBILITY_DEFAULT
+      && DECL_VISIBILITY (newdecl) != DECL_VISIBILITY (olddecl))
     {
-      error ("%Jnon thread-local declaration of '%D' follows "
-             "thread-local declaration", newdecl, newdecl);
-      error ("%Jprevious declaration of '%D'", olddecl, olddecl);
+      warning ("%Jredeclaration of '%D' with different visibility "
+              "(old visibility preserved)", newdecl, newdecl);
+      warned = true;
     }
-  else
+
+  if (TREE_CODE (newdecl) == FUNCTION_DECL)
     {
-      errmsg = redeclaration_error_message (newdecl, olddecl);
-      if (errmsg)
+      /* Diagnose inline __attribute__ ((noinline)) which is silly.  */
+      if (DECL_DECLARED_INLINE_P (newdecl)
+         && lookup_attribute ("noinline", DECL_ATTRIBUTES (olddecl)))
        {
-         switch (errmsg)
-           {
-           case 1:
-             error ("%Jredefinition of '%D'", newdecl, newdecl);
-             break;
-           case 2:
-             error ("%Jredeclaration of '%D'", newdecl, newdecl);
-             break;
-           case 3:
-             error ("%Jconflicting declarations of '%D'", newdecl, newdecl);
-             break;
-           default:
-             abort ();
-           }
-
-          if (DECL_INITIAL (olddecl)
-              && current_scope == global_scope)
-            error ("%J'%D' previously defined here", olddecl, olddecl);
-          else
-            error ("%J'%D' previously declared here", olddecl, olddecl);
-         return 0;
+         warning ("%Jinline declaration of '%D' follows "
+                  "declaration with attribute noinline", newdecl, newdecl);
+         warned = true;
        }
-      else if (TREE_CODE (newdecl) == TYPE_DECL
-               && (DECL_IN_SYSTEM_HEADER (olddecl)
-                   || DECL_IN_SYSTEM_HEADER (newdecl)))
+      else if (DECL_DECLARED_INLINE_P (olddecl)
+              && lookup_attribute ("noinline", DECL_ATTRIBUTES (newdecl)))
        {
-         warning ("%Jredefinition of '%D'", newdecl, newdecl);
-          if (DECL_INITIAL (olddecl) && current_scope == global_scope)
-            warning ("%J'%D' previously defined here", olddecl, olddecl);
-          else
-            warning ("%J'%D' previously declared here", olddecl, olddecl);
+         warning ("%Jdeclaration of '%D' with attribute noinline follows "
+                  "inline declaration ", newdecl, newdecl);
+         warned = true;
        }
-      else if (TREE_CODE (olddecl) == FUNCTION_DECL
-              && DECL_INITIAL (olddecl) != 0
-              && TYPE_ARG_TYPES (oldtype) == 0
-              && TYPE_ARG_TYPES (newtype) != 0
-              && TYPE_ACTUAL_ARG_TYPES (oldtype) != 0)
+
+      /* Inline declaration after use or definition.
+        ??? Should we still warn about this now we have unit-at-a-time
+        mode and can get it right?  */
+      if (DECL_DECLARED_INLINE_P (newdecl) && !DECL_DECLARED_INLINE_P (olddecl))
        {
-         tree type, parm;
-         int nargs;
-         /* Prototype decl follows defn w/o prototype.  */
-
-         for (parm = TYPE_ACTUAL_ARG_TYPES (oldtype),
-              type = TYPE_ARG_TYPES (newtype),
-              nargs = 1;
-              ;
-              parm = TREE_CHAIN (parm), type = TREE_CHAIN (type), nargs++)
+         if (TREE_USED (olddecl))
            {
-             if (TYPE_MAIN_VARIANT (TREE_VALUE (parm)) == void_type_node
-                 && TYPE_MAIN_VARIANT (TREE_VALUE (type)) == void_type_node)
-               {
-                 warning ("%Jprototype for '%D' follows", newdecl, newdecl);
-                 warning ("%Jnon-prototype definition here", olddecl);
-                 break;
-               }
-             if (TYPE_MAIN_VARIANT (TREE_VALUE (parm)) == void_type_node
-                 || TYPE_MAIN_VARIANT (TREE_VALUE (type)) == void_type_node)
-               {
-                 error ("%Jprototype for '%D' follows and number of "
-                         "arguments doesn't match", newdecl, newdecl);
-                 error ("%Jnon-prototype definition here", olddecl);
-                 errmsg = 1;
-                 break;
-               }
-             /* Type for passing arg must be consistent
-                with that declared for the arg.  */
-             if (! comptypes (TREE_VALUE (parm), TREE_VALUE (type),
-                              COMPARE_STRICT))
-               {
-                 error ("%Jprototype for '%D' follows and argument %d "
-                         "doesn't match", newdecl, newdecl, nargs);
-                 error ("%Jnon-prototype definition here", olddecl);
-                 errmsg = 1;
-                 break;
-               }
+             warning ("%J'%D' declared inline after being called");
+             warned = true;
+           }
+         else if (DECL_INITIAL (olddecl))
+           {
+             warning ("%J'%D' declared inline after its definition");
+             warned = true;
            }
        }
-      /* Warn about mismatches in various flags.  */
-      else
+    }
+  else /* VAR_DECL */
+    {
+      /* These bits are only type qualifiers when applied to objects.  */
+      if (TREE_THIS_VOLATILE (newdecl) != TREE_THIS_VOLATILE (olddecl))
        {
-         /* Warn if function is now inline
-            but was previously declared not inline and has been called.  */
-         if (TREE_CODE (olddecl) == FUNCTION_DECL
-             && ! DECL_DECLARED_INLINE_P (olddecl)
-             && DECL_DECLARED_INLINE_P (newdecl)
-             && TREE_USED (olddecl))
-           warning ("%J'%D' declared inline after being called",
-                    newdecl, newdecl);
-         if (TREE_CODE (olddecl) == FUNCTION_DECL
-             && ! DECL_DECLARED_INLINE_P (olddecl)
-             && DECL_DECLARED_INLINE_P (newdecl)
-             && DECL_INITIAL (olddecl) != 0)
-           warning ("%J'%D' declared inline after its definition",
-                    newdecl, newdecl);
-
-         /* If pedantic, warn when static declaration follows a non-static
-            declaration.  Otherwise, do so only for functions.  */
-         if ((pedantic || TREE_CODE (olddecl) == FUNCTION_DECL)
-             && TREE_PUBLIC (olddecl)
-             && !TREE_PUBLIC (newdecl))
-           warning ("%Jstatic declaration for '%D' follows non-static",
-                    newdecl, newdecl);
-
-         /* If warn_traditional, warn when a non-static function
-            declaration follows a static one.  */
-         if (warn_traditional && !in_system_header
-             && TREE_CODE (olddecl) == FUNCTION_DECL
-             && !TREE_PUBLIC (olddecl)
-             && TREE_PUBLIC (newdecl))
-           warning ("%Jnon-static declaration for '%D' follows static",
-                    newdecl, newdecl);
-
-         /* Warn when const declaration follows a non-const
-            declaration, but not for functions.  */
-         if (TREE_CODE (olddecl) != FUNCTION_DECL
-             && !TREE_READONLY (olddecl)
-             && TREE_READONLY (newdecl))
-           warning ("%Jconst declaration for '%D' follows non-const",
-                    newdecl, newdecl);
-         /* These bits are logically part of the type, for variables.
-            But not for functions
-            (where qualifiers are not valid ANSI anyway).  */
-         else if (pedantic && TREE_CODE (olddecl) != FUNCTION_DECL
-             && (TREE_READONLY (newdecl) != TREE_READONLY (olddecl)
-                 || TREE_THIS_VOLATILE (newdecl) != TREE_THIS_VOLATILE (olddecl)))
-           pedwarn ("%Jtype qualifiers for '%D' conflict with previous "
-                    "declaration", newdecl, newdecl);
+         if (TREE_THIS_VOLATILE (newdecl))
+           pedwarn ("%Jvolatile declaration of '%D' follows "
+                    "non-volatile declaration", newdecl, newdecl);
+         else
+           pedwarn ("%Jnon-volatile declaration of '%D' follows "
+                    "volatile declaration", newdecl, newdecl);
+         pedwarned = true;
+       }
+      if (TREE_READONLY (newdecl) != TREE_READONLY (olddecl))
+       {
+         if (TREE_READONLY (newdecl))
+           pedwarn ("%Jconst declaration of '%D' follows "
+                    "non-const declaration", newdecl, newdecl);
+         else
+           pedwarn ("%Jnon-const declaration of '%D' follows "
+                    "const declaration", newdecl, newdecl);
+         pedwarned = true;
        }
     }
 
-  /* Optionally warn about more than one declaration for the same name.  */
-  if (errmsg == 0 && warn_redundant_decls && DECL_SOURCE_LINE (olddecl) != 0
-      /* Don't warn about a function declaration
-        followed by a definition.  */
-      && !(TREE_CODE (newdecl) == FUNCTION_DECL && DECL_INITIAL (newdecl) != 0
-          && DECL_INITIAL (olddecl) == 0)
-      /* Don't warn about extern decl followed by (tentative) definition.  */
-      && !(DECL_EXTERNAL (olddecl) && ! DECL_EXTERNAL (newdecl)))
+  /* Optional warning for completely redundant decls.  */
+  if (!warned && !pedwarned
+      && warn_redundant_decls
+      /* Don't warn about a function declaration followed by a
+        definition.  */
+    && !(TREE_CODE (newdecl) == FUNCTION_DECL
+        && DECL_INITIAL (newdecl) && !DECL_INITIAL (olddecl))
+    /* Don't warn about an extern followed by a definition.  */
+    && !(DECL_EXTERNAL (olddecl) && !DECL_EXTERNAL (newdecl)))
     {
-      warning ("%Jredundant redeclaration of '%D' in same scope",
-              newdecl, newdecl);
-      warning ("%Jprevious declaration of '%D'", olddecl, olddecl);
+      warning ("%Jredundant redeclaration of '%D'", newdecl, newdecl);
+      warned = true;
     }
 
-  /* Copy all the DECL_... slots specified in the new decl
-     except for any that we copy here from the old type.
+  /* Report location of previous decl/defn in a consistent manner.  */
+  if (warned || pedwarned)
+    locate_old_decl (olddecl, pedwarned ? pedwarn : warning);
+
+  *newtypep = newtype;
+  *oldtypep = oldtype;
+  return true;
+}
 
-     Past this point, we don't change OLDTYPE and NEWTYPE
-     even if we change the types of NEWDECL and OLDDECL.  */
+/* Subroutine of duplicate_decls.  NEWDECL has been found to be
+   consistent with OLDDECL, but carries new information.  Merge the
+   new information into OLDDECL.  If DIFFERENT_BINDING_LEVEL or
+   DIFFERENT_TU is true, avoid completely merging the decls, as this
+   will break assumptions elsewhere.  This function issues no
+   diagnostics.  */
 
-  if (types_match)
+static void
+merge_decls (tree newdecl, tree olddecl, tree newtype, tree oldtype,
+            bool different_binding_level, bool different_tu)
+{
+  int new_is_definition = (TREE_CODE (newdecl) == FUNCTION_DECL
+                          && DECL_INITIAL (newdecl) != 0);
+
+  /* When copying info to olddecl, we store into write_olddecl
+     instead.  This allows us to avoid modifying olddecl when
+     different_binding_level is true.  */
+  tree write_olddecl = different_binding_level ? newdecl : olddecl;
+
+  /* For real parm decl following a forward decl, return 1 so old decl
+     will be reused.  Only allow this to happen once.  */
+  if (TREE_CODE (newdecl) == PARM_DECL
+      && TREE_ASM_WRITTEN (olddecl) && ! TREE_ASM_WRITTEN (newdecl))
     {
-      /* When copying info to olddecl, we store into write_olddecl
-        instead.  This allows us to avoid modifying olddecl when
-        different_binding_level is true.  */
-      tree write_olddecl = different_binding_level ? newdecl : olddecl;
+      TREE_ASM_WRITTEN (olddecl) = 0;
+      return;
+    }
+
+  DECL_ATTRIBUTES (newdecl)
+    = (*targetm.merge_decl_attributes) (olddecl, newdecl);
 
-      /* Merge the data types specified in the two decls.  */
-      if (TREE_CODE (newdecl) != FUNCTION_DECL || !DECL_BUILT_IN (olddecl))
+  /* Merge the data types specified in the two decls.  */
+  if (TREE_CODE (newdecl) != FUNCTION_DECL || !DECL_BUILT_IN (olddecl))
+    {
+      if (different_binding_level)
        {
-         if (different_binding_level)
-           {
-             if (TYPE_ARG_TYPES (oldtype) != 0
-                 && TYPE_ARG_TYPES (newtype) == 0)
-               TREE_TYPE (newdecl) = common_type (newtype, oldtype);
-             else
-               TREE_TYPE (newdecl)
-                 = build_type_attribute_variant
-                   (newtype,
-                    merge_attributes (TYPE_ATTRIBUTES (newtype),
-                                      TYPE_ATTRIBUTES (oldtype)));
-           }
+         if (TYPE_ARG_TYPES (oldtype) != 0
+             && TYPE_ARG_TYPES (newtype) == 0)
+           TREE_TYPE (newdecl) = common_type (newtype, oldtype);
          else
            TREE_TYPE (newdecl)
-             = TREE_TYPE (olddecl)
-               = common_type (newtype, oldtype);
-       }
-
-      /* Lay the type out, unless already done.  */
-      if (oldtype != TREE_TYPE (newdecl))
-       {
-         if (TREE_TYPE (newdecl) != error_mark_node)
-           layout_type (TREE_TYPE (newdecl));
-         if (TREE_CODE (newdecl) != FUNCTION_DECL
-             && TREE_CODE (newdecl) != TYPE_DECL
-             && TREE_CODE (newdecl) != CONST_DECL)
-           layout_decl (newdecl, 0);
+             = build_type_attribute_variant
+             (newtype,
+              merge_attributes (TYPE_ATTRIBUTES (newtype),
+                                TYPE_ATTRIBUTES (oldtype)));
        }
       else
-       {
-         /* Since the type is OLDDECL's, make OLDDECL's size go with.  */
-         DECL_SIZE (newdecl) = DECL_SIZE (olddecl);
-         DECL_SIZE_UNIT (newdecl) = DECL_SIZE_UNIT (olddecl);
-         DECL_MODE (newdecl) = DECL_MODE (olddecl);
-         if (TREE_CODE (olddecl) != FUNCTION_DECL)
-           if (DECL_ALIGN (olddecl) > DECL_ALIGN (newdecl))
-             {
-               DECL_ALIGN (newdecl) = DECL_ALIGN (olddecl);
-               DECL_USER_ALIGN (newdecl) |= DECL_ALIGN (olddecl);
-             }
-       }
+       TREE_TYPE (newdecl)
+         = TREE_TYPE (olddecl)
+         = common_type (newtype, oldtype);
+    }
 
-      /* Keep the old rtl since we can safely use it.  */
-      COPY_DECL_RTL (olddecl, newdecl);
+  /* Lay the type out, unless already done.  */
+  if (oldtype != TREE_TYPE (newdecl))
+    {
+      if (TREE_TYPE (newdecl) != error_mark_node)
+       layout_type (TREE_TYPE (newdecl));
+      if (TREE_CODE (newdecl) != FUNCTION_DECL
+         && TREE_CODE (newdecl) != TYPE_DECL
+         && TREE_CODE (newdecl) != CONST_DECL)
+       layout_decl (newdecl, 0);
+    }
+  else
+    {
+      /* Since the type is OLDDECL's, make OLDDECL's size go with.  */
+      DECL_SIZE (newdecl) = DECL_SIZE (olddecl);
+      DECL_SIZE_UNIT (newdecl) = DECL_SIZE_UNIT (olddecl);
+      DECL_MODE (newdecl) = DECL_MODE (olddecl);
+      if (TREE_CODE (olddecl) != FUNCTION_DECL)
+       if (DECL_ALIGN (olddecl) > DECL_ALIGN (newdecl))
+         {
+           DECL_ALIGN (newdecl) = DECL_ALIGN (olddecl);
+           DECL_USER_ALIGN (newdecl) |= DECL_ALIGN (olddecl);
+         }
+    }
 
-      /* Merge the type qualifiers.  */
-      if (TREE_READONLY (newdecl))
-       TREE_READONLY (write_olddecl) = 1;
+  /* Keep the old rtl since we can safely use it.  */
+  COPY_DECL_RTL (olddecl, newdecl);
 
-      if (TREE_THIS_VOLATILE (newdecl))
-       {
-         TREE_THIS_VOLATILE (write_olddecl) = 1;
-         if (TREE_CODE (newdecl) == VAR_DECL
-             /* If an automatic variable is re-declared in the same
-                function scope, but the old declaration was not
-                volatile, make_var_volatile() would crash because the
-                variable would have been assigned to a pseudo, not a
-                MEM.  Since this duplicate declaration is invalid
-                anyway, we just skip the call.  */
-             && errmsg == 0)
-           make_var_volatile (newdecl);
-       }
+  /* Merge the type qualifiers.  */
+  if (TREE_READONLY (newdecl))
+    TREE_READONLY (write_olddecl) = 1;
 
-      /* Keep source location of definition rather than declaration.  */
-      /* When called with different_binding_level set, keep the old
-        information so that meaningful diagnostics can be given.  */
-      if (DECL_INITIAL (newdecl) == 0 && DECL_INITIAL (olddecl) != 0
-         && ! different_binding_level)
-       DECL_SOURCE_LOCATION (newdecl) = DECL_SOURCE_LOCATION (olddecl);
-
-      /* Merge the unused-warning information.  */
-      if (DECL_IN_SYSTEM_HEADER (olddecl))
-       DECL_IN_SYSTEM_HEADER (newdecl) = 1;
-      else if (DECL_IN_SYSTEM_HEADER (newdecl))
-       DECL_IN_SYSTEM_HEADER (write_olddecl) = 1;
-
-      /* Merge the initialization information.  */
-      /* When called with different_binding_level set, don't copy over
-        DECL_INITIAL, so that we don't accidentally change function
-        declarations into function definitions.  */
-      if (DECL_INITIAL (newdecl) == 0 && ! different_binding_level)
-       DECL_INITIAL (newdecl) = DECL_INITIAL (olddecl);
-
-      /* Merge the section attribute.
-         We want to issue an error if the sections conflict but that must be
-        done later in decl_attributes since we are called before attributes
-        are assigned.  */
-      if (DECL_SECTION_NAME (newdecl) == NULL_TREE)
-       DECL_SECTION_NAME (newdecl) = DECL_SECTION_NAME (olddecl);
-
-      /* Copy the assembler name.
-        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)
-       {
-         if (DECL_VISIBILITY (newdecl) != VISIBILITY_DEFAULT
-             && DECL_VISIBILITY (newdecl) != DECL_VISIBILITY (olddecl))
-           {
-             warning ("%J'%D': visibility attribute ignored because it",
-                      newdecl, newdecl);
-             warning ("%Jconflicts with previous declaration here", olddecl);
-           }
-         DECL_VISIBILITY (newdecl) = DECL_VISIBILITY (olddecl);
-       }
+  if (TREE_THIS_VOLATILE (newdecl))
+    {
+      TREE_THIS_VOLATILE (write_olddecl) = 1;
+      if (TREE_CODE (newdecl) == VAR_DECL)
+       make_var_volatile (newdecl);
+    }
+
+  /* Keep source location of definition rather than declaration.  */
+  /* When called with different_binding_level set, keep the old
+     information so that meaningful diagnostics can be given.  */
+  if (DECL_INITIAL (newdecl) == 0 && DECL_INITIAL (olddecl) != 0
+      && ! different_binding_level)
+    DECL_SOURCE_LOCATION (newdecl) = DECL_SOURCE_LOCATION (olddecl);
+
+  /* Merge the unused-warning information.  */
+  if (DECL_IN_SYSTEM_HEADER (olddecl))
+    DECL_IN_SYSTEM_HEADER (newdecl) = 1;
+  else if (DECL_IN_SYSTEM_HEADER (newdecl))
+    DECL_IN_SYSTEM_HEADER (write_olddecl) = 1;
+
+  /* Merge the initialization information.  */
+  /* When called with different_binding_level set, don't copy over
+     DECL_INITIAL, so that we don't accidentally change function
+     declarations into function definitions.  */
+  if (DECL_INITIAL (newdecl) == 0 && ! different_binding_level)
+    DECL_INITIAL (newdecl) = DECL_INITIAL (olddecl);
+
+  /* Merge the section attribute.
+     We want to issue an error if the sections conflict but that must be
+     done later in decl_attributes since we are called before attributes
+     are assigned.  */
+  if (DECL_SECTION_NAME (newdecl) == NULL_TREE)
+    DECL_SECTION_NAME (newdecl) = DECL_SECTION_NAME (olddecl);
+
+  /* Copy the assembler name.
+     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);
 
-      if (TREE_CODE (newdecl) == FUNCTION_DECL)
-       {
-         DECL_STATIC_CONSTRUCTOR(newdecl) |= DECL_STATIC_CONSTRUCTOR(olddecl);
-         DECL_STATIC_DESTRUCTOR (newdecl) |= DECL_STATIC_DESTRUCTOR (olddecl);
-         DECL_NO_LIMIT_STACK (newdecl) |= DECL_NO_LIMIT_STACK (olddecl);
-         DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (newdecl)
-           |= DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (olddecl);
-         TREE_THIS_VOLATILE (newdecl) |= TREE_THIS_VOLATILE (olddecl);
-         TREE_READONLY (newdecl) |= TREE_READONLY (olddecl);
-         DECL_IS_MALLOC (newdecl) |= DECL_IS_MALLOC (olddecl);
-         DECL_IS_PURE (newdecl) |= DECL_IS_PURE (olddecl);
-       }
-    }
-  /* If cannot merge, then use the new type and qualifiers,
-     and don't preserve the old rtl.  */
-  else if (! different_binding_level)
+  if (TREE_CODE (newdecl) == FUNCTION_DECL)
     {
-      TREE_TYPE (olddecl) = TREE_TYPE (newdecl);
-      TREE_READONLY (olddecl) = TREE_READONLY (newdecl);
-      TREE_THIS_VOLATILE (olddecl) = TREE_THIS_VOLATILE (newdecl);
-      TREE_SIDE_EFFECTS (olddecl) = TREE_SIDE_EFFECTS (newdecl);
+      DECL_STATIC_CONSTRUCTOR(newdecl) |= DECL_STATIC_CONSTRUCTOR(olddecl);
+      DECL_STATIC_DESTRUCTOR (newdecl) |= DECL_STATIC_DESTRUCTOR (olddecl);
+      DECL_NO_LIMIT_STACK (newdecl) |= DECL_NO_LIMIT_STACK (olddecl);
+      DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (newdecl)
+       |= DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (olddecl);
+      TREE_THIS_VOLATILE (newdecl) |= TREE_THIS_VOLATILE (olddecl);
+      TREE_READONLY (newdecl) |= TREE_READONLY (olddecl);
+      DECL_IS_MALLOC (newdecl) |= DECL_IS_MALLOC (olddecl);
+      DECL_IS_PURE (newdecl) |= DECL_IS_PURE (olddecl);
     }
 
   /* Merge the storage class information.  */
@@ -1448,9 +1448,9 @@ duplicate_decls (tree newdecl, tree olddecl, int different_binding_level,
 
       if (DECL_BUILT_IN (olddecl))
        {
-         /* Get rid of any built-in function if new arg types don't match it
-            or if we have a function definition.  */
-         if (! types_match || new_is_definition)
+         /* Get rid of any built-in function if we have a function
+            definition.  */
+         if (new_is_definition)
            {
              if (! different_binding_level)
                {
@@ -1502,7 +1502,7 @@ duplicate_decls (tree newdecl, tree olddecl, int different_binding_level,
        }
     }
   if (different_binding_level)
-    return 0;
+    return;
 
   /* Copy most of the decl-specific fields of NEWDECL into OLDDECL.
      But preserve OLDDECL's DECL_UID.  */
@@ -1515,10 +1515,6 @@ duplicate_decls (tree newdecl, tree olddecl, int different_binding_level,
     DECL_UID (olddecl) = olddecl_uid;
   }
 
-  /* NEWDECL contains the merged attribute lists.
-     Update OLDDECL to be the same.  */
-  DECL_ATTRIBUTES (olddecl) = DECL_ATTRIBUTES (newdecl);
-
   /* If OLDDECL had its DECL_RTL instantiated, re-invoke make_decl_rtl
      so that encode_section_info has a chance to look at the new decl
      flags and attributes.  */
@@ -1527,10 +1523,34 @@ duplicate_decls (tree newdecl, tree olddecl, int different_binding_level,
          || (TREE_CODE (olddecl) == VAR_DECL
              && TREE_STATIC (olddecl))))
     make_decl_rtl (olddecl, NULL);
-
-  return 1;
 }
 
+/* Handle when a new declaration NEWDECL has the same name as an old
+   one OLDDECL in the same binding contour.  Prints an error message
+   if appropriate.
+
+   If safely possible, alter OLDDECL to look like NEWDECL, and return
+   true.  Otherwise, return false.
+
+   When DIFFERENT_BINDING_LEVEL is true, NEWDECL is an external
+   declaration, and OLDDECL is in an outer scope and should thus not
+   be changed.  */
+
+static bool
+duplicate_decls (tree newdecl, tree olddecl,
+                bool different_binding_level, bool different_tu)
+{
+  tree newtype, oldtype;
+
+  if (!diagnose_mismatched_decls (newdecl, olddecl, &newtype, &oldtype))
+    return false;
+
+  merge_decls (newdecl, olddecl, newtype, oldtype,
+              different_binding_level, different_tu);
+  return !different_binding_level;
+}
+  
+\f
 /* Return any external DECL associated with ID, whether or not it is
    currently in scope.  */
 
@@ -1890,69 +1910,6 @@ implicit_decl_warning (tree id)
     warning ("implicit declaration of function `%s'", name);
 }
 
-/* Return zero if the declaration NEWDECL is valid
-   when the declaration OLDDECL (assumed to be for the same name)
-   has already been seen.
-   Otherwise return 1 if NEWDECL is a redefinition, 2 if it is a redeclaration,
-   and 3 if it is a conflicting declaration.  */
-
-static int
-redeclaration_error_message (tree newdecl, tree olddecl)
-{
-  if (TREE_CODE (newdecl) == TYPE_DECL)
-    {
-      /* Do not complain about type redeclarations where at least one
-        declaration was in a system header.  */
-      if (DECL_IN_SYSTEM_HEADER (olddecl) || DECL_IN_SYSTEM_HEADER (newdecl))
-       return 0;
-      return 1;
-    }
-  else if (TREE_CODE (newdecl) == FUNCTION_DECL)
-    {
-      /* Declarations of functions can insist on internal linkage
-        but they can't be inconsistent with internal linkage,
-        so there can be no error on that account.
-        However defining the same name twice is no good.  */
-      if (DECL_INITIAL (olddecl) != 0 && DECL_INITIAL (newdecl) != 0
-         /* However, defining once as extern inline and a second
-            time in another way is ok.  */
-         && ! (DECL_DECLARED_INLINE_P (olddecl) && DECL_EXTERNAL (olddecl)
-              && ! (DECL_DECLARED_INLINE_P (newdecl)
-                    && DECL_EXTERNAL (newdecl))))
-       return 1;
-      return 0;
-    }
-  else if (DECL_FILE_SCOPE_P (newdecl))
-    {
-      /* Objects declared at file scope:  */
-      /* If at least one is a reference, it's ok.  */
-      if (DECL_EXTERNAL (newdecl) || DECL_EXTERNAL (olddecl))
-       return 0;
-      /* Reject two definitions.  */
-      if (DECL_INITIAL (olddecl) != 0 && DECL_INITIAL (newdecl) != 0)
-       return 1;
-      /* Now we have two tentative defs, or one tentative and one real def.  */
-      /* Insist that the linkage match.  */
-      if (TREE_PUBLIC (olddecl) != TREE_PUBLIC (newdecl))
-       return 3;
-      return 0;
-    }
-  else if (current_scope->parm_flag
-          && TREE_ASM_WRITTEN (olddecl) && !TREE_ASM_WRITTEN (newdecl))
-    return 0;
-  else
-    {
-      /* Newdecl has block scope.  If olddecl has block scope also, then
-        reject two definitions, and reject a definition together with an
-        external reference.  Otherwise, it is OK, because newdecl must
-        be an extern reference to olddecl.  */
-      if (!(DECL_EXTERNAL (newdecl) && DECL_EXTERNAL (olddecl))
-         && DECL_CONTEXT (newdecl) == DECL_CONTEXT (olddecl))
-       return 2;
-      return 0;
-    }
-}
-
 /* Issue an error message for a reference to an undeclared variable
    ID, including a reference to a builtin outside of function-call
    context.  Establish a binding of the identifier to error_mark_node
index ac1ae07..2d7b506 100644 (file)
@@ -1,5 +1,12 @@
 2004-01-10  Zack Weinberg  <zack@codesourcery.com>
 
+       * gcc.dg/Wshadow-1.c, gcc.dg/attr-noinline.c, gcc.dg/decl3.c
+       * gcc.dg/redecl-1.c, gcc.dg/visibility-7.c, gcc.dg/wtr-static-1.c
+       * gcc.dg/noncompile/20020220-1.c, objc.dg/method-1.m:
+       Update dg-error regexps.
+
+2004-01-10  Zack Weinberg  <zack@codesourcery.com>
+
        * gcc.c-torture/compile/20021123-2.c: Delete; dup of 20021120-1.c.
        * gcc.c-torture/compile/20021123-3.c: Delete; dup of 20021120-2.c.
 
index c9c3acb..c4553a4 100644 (file)
@@ -10,7 +10,7 @@ void foo (double decl1)               /* { dg-warning "shadows a global decl" } */
 {                              
 }
 
-void foo1 (int d)              /* { dg-warning "previous declaration" } */
+void foo1 (int d)              /* { dg-warning "previous definition" } */
 {
   double d;     /* { dg-bogus "warning" "warning in place of error" } */
   /* { dg-error "redeclared as different" "" { target *-*-* } 15 } */
index ee48eb9..9124e4f 100644 (file)
@@ -13,33 +13,33 @@ static inline void __attribute__((__noinline__)) function_declaration_both_after
 
 static void function_declaration_both_after(void) {}
 
-static void function_declaration_noinline_before(void) __attribute__((__noinline__)); /* { dg-warning "previous declaration \[^\n\]* with attribute noinline" "" } */
+static void function_declaration_noinline_before(void) __attribute__((__noinline__)); /* { dg-warning "previous declaration" "" } */
 
-static inline void function_declaration_noinline_before(void) {} /* { dg-warning "function \[^\n\]* redeclared as inline" "" } */
+static inline void function_declaration_noinline_before(void) {} /* { dg-warning "follows declaration with attribute noinline" "" } */
 
-static inline void function_declaration_noinline_after(void) {} /* { dg-warning "previous declaration \[^\n\]* was inline" "" } */
+static inline void function_declaration_noinline_after(void) {} /* { dg-warning "previous definition" "" } */
 
-static void function_declaration_noinline_after(void) __attribute__((__noinline__)); /* { dg-warning "function \[^\n\]* redeclared with attribute noinline" "" } */
+static void function_declaration_noinline_after(void) __attribute__((__noinline__)); /* { dg-warning "follows inline declaration" "" } */
 
-static inline void function_declaration_inline_before(void); /* { dg-warning "previous declaration \[^\n\]* was inline" "" } */
+static inline void function_declaration_inline_before(void); /* { dg-warning "previous declaration" "" } */
 
-static void __attribute__((__noinline__)) function_declaration_inline_before(void) {} /* { dg-warning "function \[^\n\]* redeclared with attribute noinline" "" } */
+static void __attribute__((__noinline__)) function_declaration_inline_before(void) {} /* { dg-warning "follows inline declaration" "" } */
 
-static inline void function_declaration_inline_noinline_before(void); /* { dg-warning "previous declaration \[^\n\]* was inline" "" } */
+static inline void function_declaration_inline_noinline_before(void); /* { dg-warning "previous declaration" "" } */
 
-static void function_declaration_inline_noinline_before(void) __attribute__((__noinline__)); /* { dg-warning "function \[^\n\]* redeclared with attribute noinline" "" } */
+static void function_declaration_inline_noinline_before(void) __attribute__((__noinline__)); /* { dg-warning "follows inline declaration" "" } */
 
 static void function_declaration_inline_noinline_before(void) {}
 
 static inline void function_declaration_inline_noinline_after(void);
 
-static void function_declaration_inline_noinline_after(void) {} /* { dg-warning "previous declaration \[^\n\]* was inline" "" } */
+static void function_declaration_inline_noinline_after(void) {} /* { dg-warning "previous definition" "" } */
 
-static void function_declaration_inline_noinline_after(void) __attribute__((__noinline__)); /* { dg-warning "function \[^\n\]* redeclared with attribute noinline" "" } */
+static void function_declaration_inline_noinline_after(void) __attribute__((__noinline__)); /* { dg-warning "follows inline declaration" "" } */
 
-static void function_declaration_noinline_inline_before(void) __attribute__((__noinline__)); /* { dg-warning "previous declaration\[^\n\]* with attribute noinline" "" } */
+static void function_declaration_noinline_inline_before(void) __attribute__((__noinline__)); /* { dg-warning "previous declaration" "" } */
 
-static inline void function_declaration_noinline_inline_before(void); /* { dg-warning "function \[^\n\]* redeclared as inline" "" } */
+static inline void function_declaration_noinline_inline_before(void); /* { dg-warning "follows declaration with attribute noinline" "" } */
 
 static void function_declaration_noinline_inline_before(void) {}
 
index b8d00d0..2bfac89 100644 (file)
@@ -1,5 +1,5 @@
 /* PR c/9928 */
 /* { dg-do compile } */
 
-enum { CODES }; /* { dg-error "previous declaration" } */
+enum { CODES }; /* { dg-error "previous definition" } */
 enum { CODES }; /* { dg-error "conflicting types" } */
index 77798b5..079daf0 100644 (file)
@@ -24,7 +24,6 @@ int main ()
   return 0;
 }
 
-/* { dg-warning "passing arg 2 of" "2nd incompatible" { target *-*-* } 15 } */
 /* { dg-warning "passing arg 1 of" "1st incompatible" { target *-*-* } 16 } */
 /* { dg-warning "passing arg 2 of" "2nd incompatible" { target *-*-* } 16 } */
 /* { dg-warning "passing arg 1 of" "1st incompatible" { target *-*-* } 18 } */
index c455f7e..aa57dc3 100644 (file)
@@ -6,7 +6,7 @@ int foo (const char*, const char*);
 void bar (void)
 {
   const char *s = "bar";
-  int i;                       /* { dg-error "previously declared here" } */
+  int i;                       /* { dg-error "previous declaration" } */
   int size = 2;
   int i = foo (s, s + size);   /* { dg-error "redeclaration of" } */
 }
index d2355ba..09b70d7 100644 (file)
@@ -74,7 +74,7 @@ void test5(void)
 
 /* Extern then static, both at file scope.  */
 
-extern int test6(int);         /* { dg-warning "previous" "" { xfail *-*-* } } */
+extern int test6(int);         /* { dg-warning "previous" "" } */
 static int test6(int x)                        
 { return x; }                  /* { dg-warning "follows non-static" } */
 
@@ -83,7 +83,7 @@ static int test6(int x)
 
 void prime7(void)
 {
-  extern int test7(int);       /* { dg-warning "previous" "" { xfail *-*-* } } */
+  extern int test7(int);       /* { dg-warning "previous" "" } */
 }
 
 static int test7(int x)
@@ -93,7 +93,7 @@ static int test7(int x)
 
 void prime8(void)
 {
-  test8();                     /* { dg-warning "previous" "" { xfail *-*-* } } */
+  test8();                     /* { dg-warning "previous" "" } */
                                 /* { dg-warning "implicit" "" { target *-*-* } 96 } */
 }
 
index e98b432..5bdc2b0 100644 (file)
@@ -5,8 +5,8 @@
 
 extern int 
 __attribute__((visibility ("hidden")))
-xyzzy; /* { dg-warning "previous declaration here" "" } */
+xyzzy; /* { dg-warning "previous declaration" "" } */
 
 int 
 __attribute__((visibility ("protected")))
-xyzzy = 5; /* { dg-warning "visibility attribute ignored" "" } */
+xyzzy = 5; /* { dg-warning "different visibility" "" } */
index 310c1ea..42760e8 100644 (file)
@@ -4,7 +4,7 @@
 /* { dg-do compile } */
 /* { dg-options "-Wtraditional" } */
 
-static void testfunc1(void);
+static void testfunc1(void); /* { dg-warning "previous declaration" } */
 void testfunc1() {} /* { dg-warning "non-static.*follows static" "non-static follows static" } */
 
 # 11 "sys-header.h" 3
index 391ee62..a73a0f4 100644 (file)
@@ -16,9 +16,8 @@
 @end
 
 @implementation class3
-- (int) meth1 { return 0; }
+- (int) meth1 { return 0; } /* { dg-error "previous definition" } */
 - (int) meth1 { return 0; } /* { dg-error "redefinition of" } */
-/* { dg-error "previously defined here" "" { target *-*-* } 19 } */
 @end
 
 @interface class4
@@ -26,7 +25,6 @@
 @end
 
 @implementation class4
-+ (void) meth1 {}
++ (void) meth1 {} /* { dg-error "previous definition" } */
 + (void) meth1 {} /* { dg-error "redefinition of" } */
-/* { dg-error "previously defined here" "" { target *-*-* } 29 } */
 @end