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]

RFHelp: c-decl.c rewrite 2/3


So here's the present state of the second stage of my c-decl.c
rewrite.  This is roughly Per's "never modify olddecl in
duplicate_decls" concept from last month, only it uses a different
mechanism to identify the canonical decl (to avoid conflict with
DECL_ABSTRACT_ORIGIN) and it copies over more information.

It is unfortunately necessary to have merge_weak behave differently
when called from the C front end than when called from the C++ front
end.

I get a small handful of C testsuite failures on i686-linux, which I
am not having any luck resolving:

FAIL: gcc.c-torture/compile/20011119-2.c, -O1 (test for excess errors)

  Abort in make_decl_rtl because expand_expr was passed a RESULT_DECL
  whose DECL_RTL was not set by assign_parms - I cannot figure out why
  this is happening.

FAIL: gcc.c-torture/compile/20031113-1.c, -O2
FAIL: gcc.c-torture/compile/900313-1.c, -O2
FAIL: gcc.c-torture/compile/950618-1.c, -O2

  Abort in dwarf2out.c:gen_subprogram_die upon being handed a function
  definition a second time.  The problem construct is

     foo() { baz(); } /* implicit declaration of baz */
     bar() { baz(); } /* this line might not be necessary */
     baz() { }

  This is some kind of funky interaction with cgraph and, again, I
  can't figure out what's going on.

I'd appreciate any help resolving these bugs.  I would also appreciate
testing on non-i686-linux platforms, especially those that use
different object or debug formats.

The varray.[ch] changes are just extra checking, I will split them out
and send them separately.  The testsuite change is a case of 'why
weren't we issuing this warning in the first place?'

zw

        * tree.h (DECL_HAS_DUPLICATE, DECL_CANONICAL): New macros.
        (decl_get_canonical, decl_set_canonical): New prototypes.
        (struct tree_decl): Add has_duplicate bit.
        * tree.c: Include varray.h.
        (copy_node): Does not create duplicated decls.
        (canonical_decls, decl_get_canonical, decl_set_canonical): New.
        (get_callee_fndecl): Use the canonical decl.
        * print-tree.c (print_node): Print has_duplicate flag.
        * Makefile.in (tree.o): Depend on varray.h.
        * output.h: Update prototypes.

        * c-decl.c (merge_decls): Remove different_tu argument.  Never
        modify olddecl.  Copy all necessary information from olddecl
        to newdecl.  Call common_type for builtins too.  Move
        PARM_DECL special case to duplicate_decls.  Mark newdecl and
        olddecl as duplicates of each other.
        (duplicate_decls): Update to match.
        (pushdecl): Update calls to duplicate_decls.  Do not call
        copy_node.  Do not call duplicate_decls with newdecl and
        olddecl equal.
        (any_external_decl, lookup_name, lookup_name_current_level):
        Return DECL_CANONICAL of the decl found.
        (merge_translation_unit_decls): Update call to duplicate_decls.
        (c_write_global_declarations): Only put canonical decls in the
        vector.

        * expr.c (expand_expr_real <VAR_DECL, FUNCTION_DECL, RESULT_DECL>):
        Use the canonical decl.
        * tree-inline.c (expand_call_inline): Likewise.
        * varasm.c (assemble_variable, weak_finish): Likewise.
        (merge_weak): Do not modify olddecl or remove it from the
        lists if modify_olddecl is false.

        * varray.h: When ENABLE_CHECKING, do bounds checking in
        VARRAY_TOP and VARRAY_POP also.
        * varray.c: Don't prototype error.
        (varray_check_failed): Split long string.
        (varray_underflow): New function.

cp:
        * decl.c (duplicate_decls): Update call to merge_weak.
testsuite:
        * gcc.dg/noncompile/20020213-1.c: Update error regexps.

===================================================================
Index: Makefile.in
--- Makefile.in	11 Jan 2004 15:56:25 -0000	1.1218
+++ Makefile.in	12 Jan 2004 18:15:31 -0000
@@ -1494,7 +1494,7 @@ langhooks.o : langhooks.c $(CONFIG_H) $(
    $(LANGHOOKS_DEF_H) flags.h $(GGC_H) gt-langhooks.h diagnostic.h
 tree.o : tree.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) flags.h function.h \
    toplev.h $(GGC_H) $(HASHTAB_H) $(TARGET_H) output.h $(TM_P_H) langhooks.h \
-   real.h gt-tree.h
+   real.h gt-tree.h varray.h
 tree-dump.o: tree-dump.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \
    $(C_TREE_H) flags.h langhooks.h toplev.h output.h c-pragma.h $(RTL_H) $(GGC_H) \
    $(EXPR_H) $(SPLAY_TREE_H) tree-dump.h
===================================================================
Index: c-decl.c
--- c-decl.c	11 Jan 2004 22:40:47 -0000	1.468
+++ c-decl.c	12 Jan 2004 18:15:32 -0000
@@ -1234,56 +1234,35 @@ diagnose_mismatched_decls (tree newdecl,
 }
 
 /* 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.  */
+   consistent with OLDDECL, but carries new information.  Merge
+   all information that OLDDECL has and NEWDECL does not, into
+   NEWDECL.  This function issues no diagnostics.
+
+   new information into OLDDECL.  If DIFFERENT_BINDING_LEVEL 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)
+	     bool different_binding_level)
 {
   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);
 
   /* Merge the data types specified in the two decls.  */
-  if (TREE_CODE (newdecl) != FUNCTION_DECL || !DECL_BUILT_IN (olddecl))
-    {
-      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)));
-	}
-      else
-	TREE_TYPE (newdecl)
-	  = TREE_TYPE (olddecl)
-	  = common_type (newtype, oldtype);
-    }
+  if (different_binding_level
+      && (TYPE_ARG_TYPES (oldtype) == 0
+	  || TYPE_ARG_TYPES (newtype) != 0))
+    TREE_TYPE (newdecl)
+      = build_type_attribute_variant
+      (newtype,
+       merge_attributes (TYPE_ATTRIBUTES (newtype),
+			 TYPE_ATTRIBUTES (oldtype)));
+  else
+    TREE_TYPE (newdecl) = common_type (newtype, oldtype);
 
   /* Lay the type out, unless already done.  */
   if (oldtype != TREE_TYPE (newdecl))
@@ -1301,27 +1280,20 @@ merge_decls (tree newdecl, tree olddecl,
       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);
-	  }
+      if (TREE_CODE (olddecl) != FUNCTION_DECL
+	  && 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;
+  TREE_READONLY (newdecl) |= TREE_READONLY (olddecl);
+  TREE_THIS_VOLATILE (newdecl) |= TREE_THIS_VOLATILE (olddecl);
 
-  if (TREE_THIS_VOLATILE (newdecl))
-    {
-      TREE_THIS_VOLATILE (write_olddecl) = 1;
-      if (TREE_CODE (newdecl) == VAR_DECL)
-	make_var_volatile (newdecl);
-    }
+  if (TREE_THIS_VOLATILE (newdecl) && 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
@@ -1331,24 +1303,33 @@ merge_decls (tree newdecl, tree olddecl,
     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;
+  DECL_IN_SYSTEM_HEADER (newdecl) |= DECL_IN_SYSTEM_HEADER (olddecl);
 
   /* 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)
+  if (!different_binding_level && DECL_INITIAL (newdecl) == 0)    
     DECL_INITIAL (newdecl) = DECL_INITIAL (olddecl);
 
+  if (!different_binding_level
+      && DECL_INITIAL (newdecl) == error_mark_node
+      && DECL_INITIAL (olddecl)
+      && TREE_CODE (DECL_INITIAL (olddecl)) == BLOCK)
+    {
+      /* This happens when olddecl is an extern-inline definition and
+	 newdecl is a weak alias.  See c-torture/compile/20011119-2.c.
+	 new_is_definition is incorrectly set in this case.  */
+      DECL_INITIAL (newdecl) = DECL_INITIAL (olddecl);
+      new_is_definition = false;
+    }
+
   /* 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);
+  if (!DECL_SECTION_NAME (newdecl))
+    DECL_SECTION_NAME (newdecl) = DECL_SECTION_NAME (olddecl);	
 
   /* Copy the assembler name.
      Currently, it can only be defined in the prototype.  */
@@ -1365,31 +1346,30 @@ merge_decls (tree newdecl, tree 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_CODE (newdecl) == VAR_DECL)
+    {
+      DECL_IN_TEXT_SECTION (newdecl) |= DECL_IN_TEXT_SECTION (olddecl);
+    }
+
   /* Merge the storage class information.  */
-  merge_weak (newdecl, olddecl);
+  merge_weak (newdecl, olddecl, /*modify_olddecl=*/false);
 
   /* For functions, static overrides non-static.  */
   if (TREE_CODE (newdecl) == FUNCTION_DECL)
     {
       TREE_PUBLIC (newdecl) &= TREE_PUBLIC (olddecl);
-      /* This is since we don't automatically
-	 copy the attributes of NEWDECL into OLDDECL.  */
-      /* No need to worry about different_binding_level here because
-	 then TREE_PUBLIC (newdecl) was true.  */
-      TREE_PUBLIC (olddecl) = TREE_PUBLIC (newdecl);
       /* If this clears `static', clear it in the identifier too.  */
       if (! TREE_PUBLIC (olddecl))
 	TREE_PUBLIC (DECL_NAME (olddecl)) = 0;
     }
+
   if (DECL_EXTERNAL (newdecl))
     {
-      if (! different_binding_level || different_tu)
+      if (! different_binding_level)
 	{
 	  /* Don't mess with these flags on local externs; they remain
 	     external even if there's a declaration at file scope which
@@ -1397,23 +1377,15 @@ merge_decls (tree newdecl, tree olddecl,
 	  TREE_STATIC (newdecl) = TREE_STATIC (olddecl);
 	  DECL_EXTERNAL (newdecl) = DECL_EXTERNAL (olddecl);
 	}
+
       /* An extern decl does not override previous storage class.  */
       TREE_PUBLIC (newdecl) = TREE_PUBLIC (olddecl);
       if (! DECL_EXTERNAL (newdecl))
 	{
 	  DECL_CONTEXT (newdecl) = DECL_CONTEXT (olddecl);
 	  DECL_COMMON (newdecl) = DECL_COMMON (olddecl);
-	  /* If we have two non-EXTERNAL file-scope decls that are
-	     the same, only one of them should be written out.  */
-	  if (different_tu)
-	    TREE_ASM_WRITTEN (newdecl) = 1;
 	}
     }
-  else
-    {
-      TREE_STATIC (olddecl) = TREE_STATIC (newdecl);
-      TREE_PUBLIC (olddecl) = TREE_PUBLIC (newdecl);
-    }
 
   if (TREE_CODE (newdecl) == FUNCTION_DECL)
     {
@@ -1438,116 +1410,101 @@ merge_decls (tree newdecl, tree olddecl,
 	{
 	  /* If either decl says `inline', this fn is inline,
 	     unless its definition was passed already.  */
-	  if (DECL_DECLARED_INLINE_P (newdecl)
-	      || DECL_DECLARED_INLINE_P (olddecl))
-	    DECL_DECLARED_INLINE_P (newdecl) = 1;
-
-	  DECL_UNINLINABLE (newdecl) = DECL_UNINLINABLE (olddecl)
-	    = (DECL_UNINLINABLE (newdecl) || DECL_UNINLINABLE (olddecl));
-	}
-
-      if (DECL_BUILT_IN (olddecl))
-	{
-	  /* Get rid of any built-in function if we have a function
-	     definition.  */
-	  if (new_is_definition)
-	    {
-	      if (! different_binding_level)
-		{
-		  TREE_TYPE (olddecl) = TREE_TYPE (newdecl);
-		  DECL_BUILT_IN_CLASS (olddecl) = NOT_BUILT_IN;
-		}
-	    }
-	  else
-	    {
-	      /* If redeclaring a builtin function, and not a definition,
-		 it stays built in.  */
-	      DECL_BUILT_IN_CLASS (newdecl) = DECL_BUILT_IN_CLASS (olddecl);
-	      DECL_FUNCTION_CODE (newdecl) = DECL_FUNCTION_CODE (olddecl);
-	    }
-	}
+	  DECL_DECLARED_INLINE_P (newdecl) |= DECL_DECLARED_INLINE_P (olddecl);
+	  DECL_UNINLINABLE (newdecl) |= DECL_UNINLINABLE (olddecl);
 
-      /* Also preserve various other info from the definition.  */
-      if (! new_is_definition)
-	{
-	  DECL_RESULT (newdecl) = DECL_RESULT (olddecl);
-	  /* 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 (! different_binding_level)
-	    DECL_INITIAL (newdecl) = DECL_INITIAL (olddecl);
-	  DECL_SAVED_INSNS (newdecl) = DECL_SAVED_INSNS (olddecl);
-	  DECL_SAVED_TREE (newdecl) = DECL_SAVED_TREE (olddecl);
-	  DECL_ESTIMATED_INSNS (newdecl) = DECL_ESTIMATED_INSNS (olddecl);
-	  DECL_ARGUMENTS (newdecl) = DECL_ARGUMENTS (olddecl);
-
-	  /* Set DECL_INLINE on the declaration if we've got a body
-	     from which to instantiate.  */
-	  if (DECL_INLINE (olddecl) && ! DECL_UNINLINABLE (newdecl))
-	    {
-	      DECL_INLINE (newdecl) = 1;
-	      DECL_ABSTRACT_ORIGIN (newdecl)
-		= (different_binding_level
-		   ? DECL_ORIGIN (olddecl)
-		   : DECL_ABSTRACT_ORIGIN (olddecl));
-	    }
-	}
-      else
-	{
-	  /* If a previous declaration said inline, mark the
-	     definition as inlinable.  */
 	  if (DECL_DECLARED_INLINE_P (newdecl)
-	      && ! DECL_UNINLINABLE (newdecl))
+	      && !DECL_UNINLINABLE (newdecl))
 	    DECL_INLINE (newdecl) = 1;
-	}
-    }
+
+	  if (DECL_INLINE (newdecl))
+	    DECL_ABSTRACT_ORIGIN (newdecl)
+	      = (different_binding_level
+		 ? DECL_ORIGIN (olddecl)
+		 : DECL_ABSTRACT_ORIGIN (olddecl));
+	}
+
+      if (!new_is_definition && DECL_BUILT_IN (olddecl))
+	{
+	  /* If redeclaring a builtin function, and not a definition,
+	     it stays built in.  */
+	  DECL_BUILT_IN_CLASS (newdecl) = DECL_BUILT_IN_CLASS (olddecl);
+	  DECL_FUNCTION_CODE (newdecl) = DECL_FUNCTION_CODE (olddecl);
+	}
+
+      /* Preserve various other information.  */
+      DECL_RESULT (newdecl) = DECL_RESULT (olddecl);
+      DECL_SAVED_INSNS (newdecl) = DECL_SAVED_INSNS (olddecl);
+      DECL_SAVED_TREE (newdecl) = DECL_SAVED_TREE (olddecl);
+      DECL_ESTIMATED_INSNS (newdecl) = DECL_ESTIMATED_INSNS (olddecl);
+      DECL_ARGUMENTS (newdecl) = DECL_ARGUMENTS (olddecl);
+      DECL_NO_STATIC_CHAIN (newdecl) |= DECL_NO_STATIC_CHAIN (olddecl);
+      DECL_INLINED_FNS (newdecl) = DECL_INLINED_FNS (olddecl);
+    }
+
+  /* Other common information to be copied over.  */
+  TREE_ADDRESSABLE (newdecl) |= TREE_ADDRESSABLE (olddecl);
+  TREE_ASM_WRITTEN (newdecl) |= TREE_ASM_WRITTEN (olddecl);
+  TREE_USED (newdecl) |= TREE_USED (olddecl);
+  TREE_DEPRECATED (newdecl) |= TREE_DEPRECATED (olddecl);
+
+  DECL_IGNORED_P (newdecl) |= DECL_IGNORED_P (olddecl);
+  DECL_ABSTRACT (newdecl) |= DECL_ABSTRACT (olddecl);
+  DECL_COMMON (newdecl) |= DECL_COMMON (olddecl);
+  DECL_REGISTER (newdecl) |= DECL_REGISTER (olddecl);
+  DECL_NONLOCAL (newdecl) |= DECL_NONLOCAL (olddecl);
+  DECL_DEFER_OUTPUT (newdecl) |= DECL_DEFER_OUTPUT (olddecl);
+  DECL_ARTIFICIAL (newdecl) |= DECL_ARTIFICIAL (olddecl);
+  
   if (different_binding_level)
     return;
 
-  /* Copy most of the decl-specific fields of NEWDECL into OLDDECL.
-     But preserve OLDDECL's DECL_UID.  */
-  {
-    unsigned olddecl_uid = DECL_UID (olddecl);
-
-    memcpy ((char *) olddecl + sizeof (struct tree_common),
-	    (char *) newdecl + sizeof (struct tree_common),
-	    sizeof (struct tree_decl) - sizeof (struct tree_common));
-    DECL_UID (olddecl) = olddecl_uid;
-  }
-
-  /* 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.  */
-  if (DECL_RTL_SET_P (olddecl)
-      && (TREE_CODE (olddecl) == FUNCTION_DECL
-	  || (TREE_CODE (olddecl) == VAR_DECL
-	      && TREE_STATIC (olddecl))))
-    make_decl_rtl (olddecl, NULL);
+  /* Make NEWDECL a duplicate of OLDDECL.  */
+  DECL_HAS_DUPLICATE (newdecl) = 1;
+  DECL_HAS_DUPLICATE (olddecl) = 1;
+  DECL_UID (newdecl) = DECL_UID (olddecl);
+  decl_set_canonical (newdecl);
+
+  /* Update cgraph if appropriate.  It indexes by DECL_ASSEMBLER_NAME,
+     so will find the appropriate node from NEWDECL.  */
+  if (DECL_INITIAL (newdecl) && TREE_CODE (newdecl) == FUNCTION_DECL)
+    cgraph_node (newdecl)->decl = newdecl;
 }
 
 /* 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 appropriate.  Combines information from OLDDECL and NEWDECL.
 
-   If safely possible, alter OLDDECL to look like NEWDECL, and return
-   true.  Otherwise, return false.
+   The return value is true if OLDDECL is the decl to continue using
+   (this is rare, but could be made more common); false if NEWDECL
+   should be used instead.
 
    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)
+duplicate_decls (tree newdecl, tree olddecl, bool different_binding_level)
 {
   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;
+  /* For real parm decl following a forward decl, old decl should
+     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 true;
+    }
+  else
+    {
+      merge_decls (newdecl, olddecl, newtype, oldtype,
+		   different_binding_level);
+      return false;
+    }
 }
   
 
@@ -1563,11 +1520,11 @@ any_external_decl (tree id)
   if (decl == 0 || TREE_CODE (decl) == ERROR_MARK)
     return 0;
   else if (TREE_CODE (decl) != TYPE_DECL && DECL_EXTERNAL (decl))
-    return decl;
+    return DECL_CANONICAL (decl);
 
   t = purpose_member (id, truly_local_externals);
   if (t)
-    return TREE_VALUE (t);
+    return DECL_CANONICAL (TREE_VALUE (t));
 
   return 0;
 }
@@ -1728,7 +1685,7 @@ pushdecl (tree x)
 		 IDENTIFIER_POINTER (name));
 
       old = lookup_name_current_level (name);
-      if (old && duplicate_decls (x, old, 0, false))
+      if (old && duplicate_decls (x, old, false))
 	{
 	  /* For PARM_DECLs, old may be a forward declaration.
 	     If so, we want to remove it from its old location
@@ -1747,18 +1704,18 @@ pushdecl (tree x)
 	    }
 	  return old;
 	}
-      if (DECL_EXTERNAL (x) || scope == global_scope)
+      else if (DECL_EXTERNAL (x) || scope == global_scope)
 	{
 	  /* Find and check against a previous, not-in-scope, external
 	     decl for this identifier.  (C99 6.2.7p2: All declarations
 	     that refer to the same object or function shall have
 	     compatible type; otherwise, the behavior is undefined.)  */
  	  tree ext = any_external_decl (name);
-	  if (ext)
+	  if (ext && ext != x)
 	    {
-	      if (duplicate_decls (x, ext, scope != global_scope,
-				   false))
-		x = copy_node (ext);
+	      if (duplicate_decls (x, ext, scope != global_scope))
+		/* Cannot have a PARM_DECL here.  */
+		return ext;
 	    }
 	  else
 	    record_external_decl (x);
@@ -2186,7 +2143,7 @@ lookup_name (tree name)
     return decl;
   if (C_DECL_INVISIBLE (decl))
     return 0;
-  return decl;
+  return DECL_CANONICAL (decl);
 }
 
 /* Similar to `lookup_name' but look only at the current scope.  */
@@ -2200,16 +2157,16 @@ lookup_name_current_level (tree name)
     return 0;
 
   if (current_scope == global_scope)
-    return decl;
+    return DECL_CANONICAL (decl);
 
   /* Scan the current scope for a decl with name NAME.
      For PARM_DECLs, we have to look at both ->parms and ->names, since
      forward parameter declarations wind up on the ->names list.  */
   if (TREE_CODE (decl) == PARM_DECL
       && chain_member (decl, current_scope->parms))
-    return decl;
+    return DECL_CANONICAL (decl);
   if (chain_member (decl, current_scope->names))
-    return decl;
+    return DECL_CANONICAL (decl);
 
   return 0;
 }
@@ -6589,7 +6546,7 @@ merge_translation_unit_decls (void)
 
 	  /* Print any appropriate error messages, and partially merge
 	     the decls.  */
-	  (void) duplicate_decls (decl, global_decl, true, true);
+	  (void) duplicate_decls (decl, global_decl, true);
 	}
 
   htab_delete (link_hash_table);
@@ -6598,7 +6555,7 @@ merge_translation_unit_decls (void)
 /* Perform final processing on file-scope data.  */
 
 void
-c_write_global_declarations(void)
+c_write_global_declarations (void)
 {
   tree link;
 
@@ -6612,14 +6569,13 @@ c_write_global_declarations(void)
 
       /* Process the decls in the order they were written.  */
 
-      for (i = 0, decl = globals; i < len; i++, decl = TREE_CHAIN (decl))
-	vec[i] = decl;
-
-      wrapup_global_declarations (vec, len);
+      for (i = 0, decl = globals; decl; decl = TREE_CHAIN (decl))
+	if (decl == DECL_CANONICAL (decl))
+	  vec[i++] = decl;
 
-      check_global_declarations (vec, len);
+      wrapup_global_declarations (vec, i);
+      check_global_declarations (vec, i);
 
-      /* Clean up.  */
       free (vec);
     }
 }
===================================================================
Index: expr.c
--- expr.c	10 Jan 2004 20:50:53 -0000	1.614
+++ expr.c	12 Jan 2004 18:15:33 -0000
@@ -6350,6 +6350,7 @@ expand_expr_real (tree exp, rtx target, 
 
     case FUNCTION_DECL:
     case RESULT_DECL:
+      exp = DECL_CANONICAL (exp);
       if (DECL_RTL (exp) == 0)
 	abort ();
 
===================================================================
Index: output.h
--- output.h	1 Oct 2003 22:57:57 -0000	1.133
+++ output.h	12 Jan 2004 18:15:33 -0000
@@ -224,7 +224,7 @@ extern void mergeable_constant_section (
 /* Declare DECL to be a weak symbol.  */
 extern void declare_weak (tree);
 /* Merge weak status.  */
-extern void merge_weak (tree, tree);
+extern void merge_weak (tree, tree, bool);
 
 /* Emit any pending weak declarations.  */
 extern void weak_finish (void);
===================================================================
Index: print-tree.c
--- print-tree.c	5 Jan 2004 15:16:35 -0000	1.80
+++ print-tree.c	12 Jan 2004 18:15:33 -0000
@@ -307,6 +307,8 @@ print_node (FILE *file, const char *pref
 	fputs (" external", file);
       if (DECL_WEAK (node))
 	fputs (" weak", file);
+      if (DECL_HAS_DUPLICATE (node))
+	fputs (" has_duplicate", file);
       if (DECL_REGISTER (node) && TREE_CODE (node) != FIELD_DECL
 	  && TREE_CODE (node) != FUNCTION_DECL
 	  && TREE_CODE (node) != LABEL_DECL)
===================================================================
Index: tree-inline.c
--- tree-inline.c	4 Jan 2004 14:39:12 -0000	1.89
+++ tree-inline.c	12 Jan 2004 18:15:33 -0000
@@ -1312,7 +1312,7 @@ expand_call_inline (tree *tp, int *walk_
     return NULL_TREE;
 
   /* Turn forward declarations into real ones.  */
-  fn = cgraph_node (fn)->decl;
+  fn = DECL_CANONICAL (cgraph_node (fn)->decl);
 
   /* If fn is a declaration of a function in a nested scope that was
      globally declared inline, we don't set its DECL_INITIAL.
===================================================================
Index: tree.c
--- tree.c	10 Jan 2004 12:02:34 -0000	1.341
+++ tree.c	12 Jan 2004 18:15:33 -0000
@@ -45,6 +45,7 @@ Software Foundation, 59 Temple Place - S
 #include "output.h"
 #include "target.h"
 #include "langhooks.h"
+#include "varray.h"
 
 /* obstack.[ch] explicitly declined to prototype this.  */
 extern int _obstack_allocated_p (struct obstack *h, void *obj);
@@ -355,7 +356,13 @@ copy_node (tree node)
   TREE_ASM_WRITTEN (t) = 0;
 
   if (TREE_CODE_CLASS (code) == 'd')
-    DECL_UID (t) = next_decl_uid++;
+    {
+      /* This process creates a new decl which is distinct from the
+	 old one.  If caller meant to create a duplicate, caller can
+	 undo this.  */
+      DECL_UID (t) = next_decl_uid++;
+      DECL_HAS_DUPLICATE (t) = 0;
+    }
   else if (TREE_CODE_CLASS (code) == 't')
     {
       TYPE_UID (t) = next_type_uid++;
@@ -4450,7 +4457,88 @@ decl_type_context (tree decl)
 
   return NULL_TREE;
 }
+
+/* There may be more than one decl for the same object.  If so, this
+   data structure holds the canonical decl for that object (the one
+   with the most information).  See merge_decls, etc. in c-decl.c.
+
+   Use of this data structure should be rare, and we know that
+   DECL_UIDs are assigned in strictly ascending order.  Thus,
+   we use a sorted varray and binary search: O(log n) all
+   operations.  */
+static GTY(()) varray_type canonical_decls;
+
+tree
+decl_get_canonical (tree decl)
+{
+  unsigned int uid = DECL_UID (decl);
+  int high, low, probe;
+
+  if (!canonical_decls)
+    abort ();
+  if (VARRAY_ACTIVE_SIZE (canonical_decls) > INT_MAX)
+    abort ();
+
+  /* Binary search on DECL_UID */
+  low = -1;
+  high = VARRAY_ACTIVE_SIZE (canonical_decls);
+  while (high - low > 1)
+    {
+      probe = (high + low) / 2;
+      if (DECL_UID (VARRAY_TREE (canonical_decls, probe)) > uid)
+	high = probe;
+      else
+	low = probe;
+    }
+
+  if (low == -1 || DECL_UID (VARRAY_TREE (canonical_decls, low)) != uid)
+    abort ();
+
+  return VARRAY_TREE (canonical_decls, low);
+}
+
+void
+decl_set_canonical (tree decl)
+{
+  unsigned int uid = DECL_UID (decl);
+  int high, low, probe;
+
+  if (!canonical_decls)
+    VARRAY_TREE_INIT (canonical_decls, 16, "canonical_decls");
+  if (VARRAY_ACTIVE_SIZE (canonical_decls) > INT_MAX)
+    abort ();
+
+  /* Binary search on DECL_UID */
+  low = -1;
+  high = VARRAY_ACTIVE_SIZE (canonical_decls);
+  while (high - low > 1)
+    {
+      probe = (high + low) / 2;
+      if (DECL_UID (VARRAY_TREE (canonical_decls, probe)) > uid)
+	high = probe;
+      else
+	low = probe;
+    }
+
+  if (low != -1 && DECL_UID (VARRAY_TREE (canonical_decls, low)) == uid)
+    VARRAY_TREE (canonical_decls, low) = decl;
+  else if (low == (int)VARRAY_ACTIVE_SIZE (canonical_decls) - 1)
+    VARRAY_PUSH_TREE (canonical_decls, decl);
+  else
+    {
+      /* Need to insert in the middle of the array.  low points
+	 one before the target address.  */
+      VARRAY_PUSH_TREE (canonical_decls, 0); /* make room */
+      memmove (&VARRAY_TREE (canonical_decls, low + 2),
+	       &VARRAY_TREE (canonical_decls, low + 1),
+	       /* do _not_ include the new slot we just allocated
+		  in the move */
+	       (VARRAY_ACTIVE_SIZE (canonical_decls)-low-2) * sizeof (tree));
 
+      VARRAY_TREE (canonical_decls, low + 1) = decl;
+    }
+}
+
 /* CALL is a CALL_EXPR.  Return the declaration for the function
    called, or NULL_TREE if the called function cannot be
    determined.  */
@@ -4481,7 +4569,8 @@ get_callee_fndecl (tree call)
      that `f' is being called.  */
   if (TREE_CODE (addr) == ADDR_EXPR
       && TREE_CODE (TREE_OPERAND (addr, 0)) == FUNCTION_DECL)
-    return TREE_OPERAND (addr, 0);
+    /* There might be more than one decl for this function.  */
+    return DECL_CANONICAL (TREE_OPERAND (addr, 0));
   
   /* We couldn't figure out what was being called.  Maybe the front
      end has some idea.  */
===================================================================
Index: tree.h
--- tree.h	9 Jan 2004 19:55:01 -0000	1.456
+++ tree.h	12 Jan 2004 18:15:34 -0000
@@ -1497,6 +1497,14 @@ struct tree_type GTY(())
 /* Value of the decls's visibility attribute */
 #define DECL_VISIBILITY(NODE) (DECL_CHECK (NODE)->decl.visibility)
 
+/* Nonzero for a decl which has at least one duplicate.  */
+#define DECL_HAS_DUPLICATE(DECL) (DECL_CHECK (DECL)->decl.has_duplicate)
+
+/* Find the version of this DECL which carries the most information.
+   Note evaluates DECL twice.  */
+#define DECL_CANONICAL(DECL) \
+  (DECL_HAS_DUPLICATE (DECL) ? decl_get_canonical (DECL) : (DECL))
+
 /* In a FUNCTION_DECL, nonzero if the function cannot be inlined.  */
 #define DECL_UNINLINABLE(NODE) (FUNCTION_DECL_CHECK (NODE)->decl.uninlinable)
 
@@ -1689,8 +1697,7 @@ struct tree_decl GTY(())
   unsigned thread_local_flag : 1;
   unsigned declared_inline_flag : 1;
   ENUM_BITFIELD(symbol_visibility) visibility : 2;
-  unsigned unused : 1;
-  /* one unused bit.  */
+  unsigned has_duplicate : 1;
 
   unsigned lang_flag_0 : 1;
   unsigned lang_flag_1 : 1;
@@ -2665,6 +2672,13 @@ extern tree decl_function_context (tree)
 /* Return the RECORD_TYPE, UNION_TYPE, or QUAL_UNION_TYPE which provides
    this _DECL with its context, or zero if none.  */
 extern tree decl_type_context (tree);
+
+/* Return the version of this decl which carries the most information.  */
+extern tree decl_get_canonical (tree);
+
+/* Assert that DECL is the version of all decls of the same object
+   which carries the most information.  */
+extern void decl_set_canonical (tree);
 
 /* Given the FUNCTION_DECL for the current function,
    return zero if it is ok for this function to be inline.
===================================================================
Index: varasm.c
--- varasm.c	6 Jan 2004 16:51:21 -0000	1.402
+++ varasm.c	12 Jan 2004 18:15:34 -0000
@@ -1351,6 +1351,8 @@ assemble_variable (tree decl, int top_le
   int reloc = 0;
   rtx decl_rtl;
 
+  decl = DECL_CANONICAL (decl);
+
   if (lang_hooks.decls.prepare_assemble_variable)
     (*lang_hooks.decls.prepare_assemble_variable) (decl);
 
@@ -4240,10 +4242,12 @@ mark_weak (tree decl)
     SYMBOL_REF_WEAK (XEXP (DECL_RTL (decl), 0)) = 1;
 }
 
-/* Merge weak status between NEWDECL and OLDDECL.  */
+/* Merge weak status between NEWDECL and OLDDECL.
+   MODIFY_OLDDECL is false if we are not to modify OLDDECL
+   (the C and C++ front ends' expectations are different).  */
 
 void
-merge_weak (tree newdecl, tree olddecl)
+merge_weak (tree newdecl, tree olddecl, bool modify_olddecl)
 {
   if (DECL_WEAK (newdecl) == DECL_WEAK (olddecl))
     return;
@@ -4255,9 +4259,9 @@ merge_weak (tree newdecl, tree olddecl)
       /* NEWDECL is weak, but OLDDECL is not.  */
 
       /* If we already output the OLDDECL, we're in trouble; we can't
-	 go back and make it weak.  This error cannot caught in
-	 declare_weak because the NEWDECL and OLDDECL was not yet
-	 been merged; therefore, TREE_ASM_WRITTEN was not set.  */
+	 go back and make it weak.  This error cannot be caught in
+	 declare_weak because NEWDECL and OLDDECL had not yet been
+	 merged; therefore, TREE_ASM_WRITTEN was not set.  */
       if (TREE_ASM_WRITTEN (olddecl))
 	error ("%Jweak declaration of '%D' must precede definition",
 	       newdecl, newdecl);
@@ -4270,7 +4274,7 @@ merge_weak (tree newdecl, tree olddecl)
 	warning ("%Jweak declaration of '%D' after first use results "
                  "in unspecified behavior", newdecl, newdecl);
 
-      if (SUPPORTS_WEAK)
+      if (SUPPORTS_WEAK && modify_olddecl)
 	{
 	  /* We put the NEWDECL on the weak_decls list at some point.
 	     Replace it with the OLDDECL.  */
@@ -4286,8 +4290,9 @@ merge_weak (tree newdecl, tree olddecl)
 	     not need to do anything.  */
 	}
 
-      /* Make the OLDDECL weak; it's OLDDECL that we'll be keeping.  */
-      mark_weak (olddecl);
+      if (modify_olddecl)
+	/* Make the OLDDECL weak; it's OLDDECL that we'll be keeping.  */
+	mark_weak (olddecl);
     }
   else
     /* OLDDECL was weak, but NEWDECL was not explicitly marked as
@@ -4324,7 +4329,7 @@ weak_finish (void)
 
   for (t = weak_decls; t; t = TREE_CHAIN (t))
     {
-      tree decl = TREE_VALUE (t);
+      tree decl = DECL_CANONICAL (TREE_VALUE (t));
 #if defined (ASM_WEAKEN_DECL) || defined (ASM_WEAKEN_LABEL)
       const char *const name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
 #endif
===================================================================
Index: varray.c
--- varray.c	19 Jul 2003 14:47:14 -0000	1.21
+++ varray.c	12 Jan 2004 18:15:34 -0000
@@ -118,15 +118,22 @@ varray_clear (varray_type va)
 
 #if defined ENABLE_CHECKING && (GCC_VERSION >= 2007)
 
-extern void error (const char *, ...)	ATTRIBUTE_PRINTF_1;
-
 void
 varray_check_failed (varray_type va, size_t n, const char *file, int line,
 		     const char *function)
 {
-  internal_error ("virtual array %s[%lu]: element %lu out of bounds in %s, at %s:%d",
+  internal_error ("virtual array %s[%lu]: element %lu out of bounds "
+		  "in %s, at %s:%d",
 		  va->name, (unsigned long) va->num_elements, (unsigned long) n,
 		  function, trim_filename (file), line);
+}
+
+void
+varray_underflow (varray_type va, const char *file, int line,
+		  const char *function)
+{
+  internal_error ("underflowed virtual array %s in %s, at %s:%d",
+		  va->name, function, trim_filename (file), line);
 }
 
 #endif
===================================================================
Index: varray.h
--- varray.h	10 Jul 2003 11:38:18 -0000	1.32
+++ varray.h	12 Jan 2004 18:15:34 -0000
@@ -227,14 +227,27 @@ extern void varray_clear (varray_type);
 #if defined ENABLE_CHECKING && (GCC_VERSION >= 2007)
 extern void varray_check_failed (varray_type, size_t, const char *, int,
 				 const char *) ATTRIBUTE_NORETURN;
+extern void varray_underflow (varray_type, const char *, int, const char *)
+     ATTRIBUTE_NORETURN;
 #define VARRAY_CHECK(VA, N, T) __extension__			\
 (*({ varray_type const _va = (VA);				\
      const size_t _n = (N);					\
      if (_n >= _va->num_elements)				\
        varray_check_failed (_va, _n, __FILE__, __LINE__, __FUNCTION__);	\
      &_va->data.T[_n]; }))
+
+#define VARRAY_POP(VA) do {					\
+  varray_type const _va = (VA);					\
+  if (_va->elements_used == 0)					\
+    varray_underflow (_va, __FILE__, __LINE__, __FUNCTION__);	\
+  else								\
+    _va->elements_used--;					\
+} while (0)
+
 #else
 #define VARRAY_CHECK(VA, N, T) ((VA)->data.T[N])
+/* Pop the top element of VA.  */
+#define VARRAY_POP(VA) do { ((VA)->elements_used--); } while (0)
 #endif
 
 /* Push X onto VA.  T is the name of the field in varray_data
@@ -248,14 +261,6 @@ extern void varray_check_failed (varray_
     }							\
   while (0)
 
-/* Pop the top element of VA.  */
-#define VARRAY_POP(VA) \
-  ((VA)->elements_used--)
-
-/* Return the top element of VA.  */
-#define VARRAY_TOP(VA, T) \
-  ((VA)->data.T[(VA)->elements_used - 1])
-
 #define VARRAY_CHAR(VA, N)		VARRAY_CHECK (VA, N, c)
 #define VARRAY_UCHAR(VA, N)		VARRAY_CHECK (VA, N, uc)
 #define VARRAY_SHORT(VA, N)		VARRAY_CHECK (VA, N, s)
@@ -299,6 +304,8 @@ extern void varray_check_failed (varray_
 #define VARRAY_PUSH_BB(VA, X)		VARRAY_PUSH (VA, bb, X)
 
 /* Return the last element of VA.  */
+#define VARRAY_TOP(VA, T) VARRAY_CHECK(VA, (VA)->elements_used - 1, T)
+
 #define VARRAY_TOP_CHAR(VA)		VARRAY_TOP (VA, c)
 #define VARRAY_TOP_UCHAR(VA)	        VARRAY_TOP (VA, uc)
 #define VARRAY_TOP_SHORT(VA)	        VARRAY_TOP (VA, s)
===================================================================
Index: cp/decl.c
--- cp/decl.c	10 Jan 2004 01:18:08 -0000	1.1171
+++ cp/decl.c	12 Jan 2004 18:15:39 -0000
@@ -1734,7 +1734,7 @@ duplicate_decls (tree newdecl, tree oldd
     }
 
   /* Merge the storage class information.  */
-  merge_weak (newdecl, olddecl);
+  merge_weak (newdecl, olddecl, /*modify_olddecl=*/true);
 
   DECL_ONE_ONLY (newdecl) |= DECL_ONE_ONLY (olddecl);
   DECL_DEFER_OUTPUT (newdecl) |= DECL_DEFER_OUTPUT (olddecl);
===================================================================
Index: testsuite/gcc.dg/noncompile/20020213-1.c
--- testsuite/gcc.dg/noncompile/20020213-1.c	11 Jan 2004 01:18:58 -0000	1.2
+++ testsuite/gcc.dg/noncompile/20020213-1.c	12 Jan 2004 18:15:44 -0000
@@ -24,6 +24,7 @@ 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 Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]