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


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

c-decl.c overhaul (1/3) Refactor duplicate_decls


This is patch 1 of 3 in a series which eventually will result in
fixing all the bugs related to bad scoping of identifier bindings in
the C front end (at least 12267, 12336, 12373, 12391, 12560, 12934,
13129).  This one is just laying groundwork: I have restructured
duplicate_decls so that it is comprehensible and modifiable.  It
should be noted that I made it somewhat pickier in the process: I
removed two special cases where the type compatibility rules were
relaxed for the sake of K+R code, and I made certain warnings
unconditional where formerly they appeared only with -pedantic.  Apart
from the above special cases, I do not believe that any more code is
outright rejected.  I also arranged always to indicate the location of
the previous decl, which fixes some long-standing expected failures in
the test suite.

Some weird special cases remain - one for a pseudo-K+R construct that
I expect is still fairly common, one for Objective C's not-really-
builtin builtins, and a few more.

Part of the point of this patch is that I need to make changes of
behavior to duplicate_decls, so I'm getting the changes of form out of
the way now; part of the point is to get all the testsuite tweaks out
of the way in advance.

Bootstrapped i686-linux.  Patches 2 and 3 in this series will need
more extensive testing; in particular, I am looking for help testing
on powerpc-darwin.

zw

        * 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.

===================================================================
Index: c-decl.c
--- c-decl.c	7 Jan 2004 19:39:58 -0000	1.466
+++ c-decl.c	11 Jan 2004 01:08:44 -0000
@@ -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));
 }
 
-/* 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 oldty
   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.
-
-   If safely possible, alter OLDDECL to look like NEWDECL, and return 1.
-   Otherwise, return 0.
-
-   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 int
-duplicate_decls (tree newdecl, tree olddecl, int different_binding_level,
-		 int different_tu)
+/* 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)
 {
-  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 (DECL_P (olddecl))
-    {
-      if (TREE_CODE (newdecl) == FUNCTION_DECL
-	  && TREE_CODE (olddecl) == FUNCTION_DECL
-	  && (DECL_UNINLINABLE (newdecl) || DECL_UNINLINABLE (olddecl)))
+  tree t;
+
+  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;
+
+  t = TYPE_ARG_TYPES (oldtype);
+  if (t == 0)
+    t = TYPE_ARG_TYPES (newtype);
+  for (; t; t = TREE_CHAIN (t))
+    {
+      tree type = TREE_VALUE (t);
+
+      if (TREE_CHAIN (t) == 0
+	  && TYPE_MAIN_VARIANT (type) != void_type_node)
 	{
-	  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 ("a parameter list with an ellipsis can't match"
+		  "an empty parameter name list declaration");
+	  break;
 	}
 
-      DECL_ATTRIBUTES (newdecl)
-	= (*targetm.merge_decl_attributes) (olddecl, newdecl);
+      if (c_type_promotes_to (type) != type)
+	{
+	  inform ("an argument type that has a default promotion can't match"
+		  "an empty parameter name list declaration");
+	  break;
+	}
     }
+}
 
-  if (TREE_CODE (newtype) == ERROR_MARK
-      || TREE_CODE (oldtype) == ERROR_MARK)
-    types_match = 0;
+/* 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;
+	}
 
-  /* 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.  */
+      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);
+}
+
+/* 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.  */
+
+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 oldd
 	  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 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))
+	{
+	  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;
 	    }
 	}
-      if (!types_match)
+      else if (TREE_PUBLIC (newdecl) && !TREE_PUBLIC (olddecl)
+	       && warn_traditional)
 	{
-	  /* 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;
+	  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)))
-	{
-	  /* Classify the problem further.  */
-	  tree t = TYPE_ARG_TYPES (oldtype);
-	  if (t == 0)
-	    t = TYPE_ARG_TYPES (newtype);
-	  for (; t; t = TREE_CHAIN (t))
-	    {
-	      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;
-		}
+      /* 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))
+	{
+	  if (!DECL_EXTERNAL (newdecl)
+	      && !DECL_EXTERNAL (olddecl)
+	      && TREE_PUBLIC (newdecl) != TREE_PUBLIC (olddecl))
+	    {
+	      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;
+	  locate_old_decl (olddecl, error);
+	  return false;
+	}
     }
-  /* 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);
-    }
-  /* 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))
-    {
-      error ("%Jnon thread-local declaration of '%D' follows "
-             "thread-local declaration", newdecl, newdecl);
-      error ("%Jprevious declaration of '%D'", olddecl, olddecl);
+
+  /* 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))
+    {
+      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;
-	}
-      else if (TREE_CODE (newdecl) == TYPE_DECL
-               && (DECL_IN_SYSTEM_HEADER (olddecl)
-                   || DECL_IN_SYSTEM_HEADER (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 ("%Jinline declaration of '%D' follows "
+		   "declaration with attribute noinline", 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)
-	{
-	  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)
-		{
-		  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;
-		}
-	    }
-	}
-      /* Warn about mismatches in various flags.  */
-      else
+      else if (DECL_DECLARED_INLINE_P (olddecl)
+	       && lookup_attribute ("noinline", DECL_ATTRIBUTES (newdecl)))
 	{
-	  /* 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);
-	}
-    }
-
-  /* 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)))
-    {
-      warning ("%Jredundant redeclaration of '%D' in same scope",
-	       newdecl, newdecl);
-      warning ("%Jprevious declaration of '%D'", olddecl, olddecl);
-    }
-
-  /* Copy all the DECL_... slots specified in the new decl
-     except for any that we copy here from the old type.
-
-     Past this point, we don't change OLDTYPE and NEWTYPE
-     even if we change the types of NEWDECL and OLDDECL.  */
-
-  if (types_match)
-    {
-      /* 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;
+	  warning ("%Jdeclaration of '%D' with attribute noinline follows "
+		   "inline declaration ", newdecl, newdecl);
+	  warned = true;
+	}
 
-      /* Merge the data types specified in the two decls.  */
-      if (TREE_CODE (newdecl) != FUNCTION_DECL || !DECL_BUILT_IN (olddecl))
+      /* 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))
 	{
-	  if (different_binding_level)
+	  if (TREE_USED (olddecl))
 	    {
-	      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)));
+	      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;
 	    }
+	}
+    }
+  else /* VAR_DECL */
+    {
+      /* These bits are only type qualifiers when applied to objects.  */
+      if (TREE_THIS_VOLATILE (newdecl) != TREE_THIS_VOLATILE (olddecl))
+	{
+	  if (TREE_THIS_VOLATILE (newdecl))
+	    pedwarn ("%Jvolatile declaration of '%D' follows "
+		     "non-volatile declaration", newdecl, newdecl);
 	  else
-	    TREE_TYPE (newdecl)
-	      = TREE_TYPE (olddecl)
-		= common_type (newtype, oldtype);
+	    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;
 	}
+    }
+
+  /* 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'", newdecl, newdecl);
+      warned = true;
+    }
+
+  /* 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;
+}
+
+/* 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.  */
+
+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))
+    {
+      TREE_ASM_WRITTEN (olddecl) = 0;
+      return;
+    }
+
+  DECL_ATTRIBUTES (newdecl)
+    = (*targetm.merge_decl_attributes) (olddecl, newdecl);
 
-      /* Lay the type out, unless already done.  */
-      if (oldtype != TREE_TYPE (newdecl))
+  /* Merge the data types specified in the two decls.  */
+  if (TREE_CODE (newdecl) != FUNCTION_DECL || !DECL_BUILT_IN (olddecl))
+    {
+      if (different_binding_level)
 	{
-	  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);
+	  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)));
 	}
       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);
-	      }
-	}
-
-      /* Keep the old rtl since we can safely use it.  */
-      COPY_DECL_RTL (olddecl, newdecl);
-
-      /* Merge the type qualifiers.  */
-      if (TREE_READONLY (newdecl))
-	TREE_READONLY (write_olddecl) = 1;
-
-      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);
-	}
-
-      /* 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);
+	TREE_TYPE (newdecl)
+	  = TREE_TYPE (olddecl)
+	  = common_type (newtype, oldtype);
+    }
 
-      /* 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);
-	}
+  /* 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);
+	  }
+    }
+
+  /* Keep the old rtl since we can safely use it.  */
+  COPY_DECL_RTL (olddecl, newdecl);
+
+  /* Merge the type qualifiers.  */
+  if (TREE_READONLY (newdecl))
+    TREE_READONLY (write_olddecl) = 1;
 
-      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 (TREE_THIS_VOLATILE (newdecl))
+    {
+      TREE_THIS_VOLATILE (write_olddecl) = 1;
+      if (TREE_CODE (newdecl) == VAR_DECL)
+	make_var_volatile (newdecl);
     }
-  /* If cannot merge, then use the new type and qualifiers,
-     and don't preserve the old rtl.  */
-  else if (! different_binding_level)
-    {
-      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);
+
+  /* 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);
     }
 
   /* Merge the storage class information.  */
@@ -1448,9 +1448,9 @@ duplicate_decls (tree newdecl, tree oldd
 
       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 oldd
 	}
     }
   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 oldd
     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 oldd
 	  || (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;
+}
+  
+
 /* Return any external DECL associated with ID, whether or not it is
    currently in scope.  */
 
@@ -1888,69 +1908,6 @@ implicit_decl_warning (tree id)
     error ("implicit declaration of function `%s'", name);
   else if (mesg_implicit_function_declaration == 1)
     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
===================================================================
Index: testsuite/gcc.dg/Wshadow-1.c
--- testsuite/gcc.dg/Wshadow-1.c	11 Apr 2003 04:26:55 -0000	1.3
+++ testsuite/gcc.dg/Wshadow-1.c	11 Jan 2004 01:08:45 -0000
@@ -10,7 +10,7 @@ void foo (double decl1)		/* { dg-warning
 {				
 }
 
-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: testsuite/gcc.dg/attr-noinline.c
--- testsuite/gcc.dg/attr-noinline.c	6 Feb 2002 20:40:17 -0000	1.2
+++ testsuite/gcc.dg/attr-noinline.c	11 Jan 2004 01:08:45 -0000
@@ -13,33 +13,33 @@ static inline void __attribute__((__noin
 
 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: testsuite/gcc.dg/decl-3.c
--- testsuite/gcc.dg/decl-3.c	12 Mar 2003 09:54:38 -0000	1.1
+++ testsuite/gcc.dg/decl-3.c	11 Jan 2004 01:08:45 -0000
@@ -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: testsuite/gcc.dg/redecl-1.c
--- testsuite/gcc.dg/redecl-1.c	11 Apr 2003 04:26:55 -0000	1.1
+++ testsuite/gcc.dg/redecl-1.c	11 Jan 2004 01:08:45 -0000
@@ -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: testsuite/gcc.dg/visibility-7.c
--- testsuite/gcc.dg/visibility-7.c	10 Dec 2003 06:34:45 -0000	1.1
+++ testsuite/gcc.dg/visibility-7.c	11 Jan 2004 01:08:45 -0000
@@ -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: testsuite/gcc.dg/wtr-static-1.c
--- testsuite/gcc.dg/wtr-static-1.c	3 Jul 2002 02:41:34 -0000	1.3
+++ testsuite/gcc.dg/wtr-static-1.c	11 Jan 2004 01:08:45 -0000
@@ -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: testsuite/gcc.dg/noncompile/20020213-1.c
--- testsuite/gcc.dg/noncompile/20020213-1.c	14 Feb 2002 10:22:53 -0000	1.1
+++ testsuite/gcc.dg/noncompile/20020213-1.c	11 Jan 2004 01:08:45 -0000
@@ -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: testsuite/gcc.dg/noncompile/20020220-1.c
--- testsuite/gcc.dg/noncompile/20020220-1.c	20 Feb 2002 22:59:35 -0000	1.1
+++ testsuite/gcc.dg/noncompile/20020220-1.c	11 Jan 2004 01:08:45 -0000
@@ -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: testsuite/objc.dg/method-1.m
--- testsuite/objc.dg/method-1.m	25 Sep 2003 01:26:01 -0000	1.3
+++ testsuite/objc.dg/method-1.m	11 Jan 2004 01:08:45 -0000
@@ -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


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