]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
re PR c++/3187 (gcc lays down two copies of constructors)
authorJakub Jelinek <jakub@redhat.com>
Wed, 18 Nov 2009 09:53:52 +0000 (10:53 +0100)
committerJakub Jelinek <jakub@gcc.gnu.org>
Wed, 18 Nov 2009 09:53:52 +0000 (10:53 +0100)
PR c++/3187
* cgraph.h (struct cgraph_node): Add same_body and same_body_alias
fields.
(cgraph_same_body_alias, cgraph_remove_same_body_alias): New
prototypes.
* cgraphunit.c (cgraph_expand_function, cgraph_emit_thunks,
cgraph_materialize_all_clones): Handle same_body aliases.
* cgraph.c (cgraph_allocate_node): New function.
(cgraph_create_node): Use it.
(cgraph_node_for_decl, cgraph_node, cgraph_get_node,
cgraph_node_for_asm, cgraph_remove_node): Handle same_body aliases.
(cgraph_same_body_alias, cgraph_remove_same_body_alias): New
functions.
* lto-cgraph.c (lto_output_node): Stream out same_body aliases.
(input_node): Stream in same_body aliases.
* lto-symtab.c (lto_cgraph_replace_node): Clear node pointers
for same_body aliases.
(lto_symtab_merge_cgraph_nodes_1): Handle same_body aliases.

* cp-tree.h (expand_or_defer_fn_1): New prototype.
* decl2.c (cp_write_global_declarations): Mark as !DECL_EXTERNAL
also all same_body aliases.
* semantics.c (expand_or_defer_fn): Move most of the function
except registering with cgraph to ...
(expand_or_defer_fn_1): ... here.  New function.
* optimize.c: Include cgraph.h.
(maybe_clone_body): If in charge parm is not used and both base
and complete clones are created and are not comdat, tell cgraph
they have the same body.
* Make-lang.in (cp/optimize.o): Depend on $(CGRAPH_H).

* g++.dg/abi/mangle26.C: Also match *C2* definition.
* g++.dg/abi/mangle27.C: Likewise.
* g++.dg/abi/mangle28.C: Likewise.
* g++.dg/abi/mangle29.C: Likewise.

From-SVN: r154284

17 files changed:
gcc/ChangeLog
gcc/cgraph.c
gcc/cgraph.h
gcc/cgraphunit.c
gcc/cp/ChangeLog
gcc/cp/Make-lang.in
gcc/cp/cp-tree.h
gcc/cp/decl2.c
gcc/cp/optimize.c
gcc/cp/semantics.c
gcc/lto-cgraph.c
gcc/lto-symtab.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/abi/mangle26.C
gcc/testsuite/g++.dg/abi/mangle27.C
gcc/testsuite/g++.dg/abi/mangle28.C
gcc/testsuite/g++.dg/abi/mangle29.C

index 2d615af844ac58a30f53b9b6d85c7d6bc12a6ece..3ec03fc5b700ae855a4b33d90f4608c6ec00ae57 100644 (file)
@@ -1,3 +1,24 @@
+2009-11-18  Jakub Jelinek  <jakub@redhat.com>
+
+       PR c++/3187
+       * cgraph.h (struct cgraph_node): Add same_body and same_body_alias
+       fields.
+       (cgraph_same_body_alias, cgraph_remove_same_body_alias): New
+       prototypes.
+       * cgraphunit.c (cgraph_expand_function, cgraph_emit_thunks,
+       cgraph_materialize_all_clones): Handle same_body aliases.
+       * cgraph.c (cgraph_allocate_node): New function.
+       (cgraph_create_node): Use it.
+       (cgraph_node_for_decl, cgraph_node, cgraph_get_node,
+       cgraph_node_for_asm, cgraph_remove_node): Handle same_body aliases.
+       (cgraph_same_body_alias, cgraph_remove_same_body_alias): New
+       functions.
+       * lto-cgraph.c (lto_output_node): Stream out same_body aliases.
+       (input_node): Stream in same_body aliases.
+       * lto-symtab.c (lto_cgraph_replace_node): Clear node pointers
+       for same_body aliases.
+       (lto_symtab_merge_cgraph_nodes_1): Handle same_body aliases.
+
 2009-11-18  Iain Sandoe <iain.sandoe@sandoe-acoustics.co.uk>
 
        PR other/39888
index 391882ed2c805c1f1b2bd9e5980fb7437519e25d..02beae92469b8f1a25167e64a147a29e456ff532 100644 (file)
@@ -425,7 +425,11 @@ cgraph_node_for_decl (tree decl)
       key.decl = decl;
       slot = htab_find_slot (cgraph_hash, &key, NO_INSERT);
       if (slot && *slot)
-       node = (struct cgraph_node *) *slot;
+       {
+         node = (struct cgraph_node *) *slot;
+         if (node->same_body_alias)
+           node = node->same_body;
+       }
     }
 
   return node;
@@ -442,10 +446,10 @@ eq_node (const void *p1, const void *p2)
   return DECL_UID (n1->decl) == DECL_UID (n2->decl);
 }
 
-/* Allocate new callgraph node and insert it into basic data structures.  */
+/* Allocate new callgraph node.  */
 
-static struct cgraph_node *
-cgraph_create_node (void)
+static inline struct cgraph_node *
+cgraph_allocate_node (void)
 {
   struct cgraph_node *node;
 
@@ -460,6 +464,16 @@ cgraph_create_node (void)
       node->uid = cgraph_max_uid++;
     }
 
+  return node;
+}
+
+/* Allocate new callgraph node and insert it into basic data structures.  */
+
+static struct cgraph_node *
+cgraph_create_node (void)
+{
+  struct cgraph_node *node = cgraph_allocate_node ();
+
   node->next = cgraph_nodes;
   node->pid = -1;
   node->order = cgraph_order++;
@@ -491,6 +505,8 @@ cgraph_node (tree decl)
   if (*slot)
     {
       node = *slot;
+      if (node->same_body_alias)
+       node = node->same_body;
       return node;
     }
 
@@ -521,6 +537,52 @@ cgraph_node (tree decl)
   return node;
 }
 
+/* Attempt to mark ALIAS as an alias to DECL.  Return TRUE if successful.
+   Same body aliases are output whenever the body of DECL is output,
+   and cgraph_node (ALIAS) transparently returns cgraph_node (DECL).  */
+
+bool
+cgraph_same_body_alias (tree alias, tree decl)
+{
+  struct cgraph_node key, *alias_node, *decl_node, **slot;
+
+  gcc_assert (TREE_CODE (decl) == FUNCTION_DECL);
+  gcc_assert (TREE_CODE (alias) == FUNCTION_DECL);
+  gcc_assert (!assembler_name_hash);
+
+#ifndef ASM_OUTPUT_DEF
+  /* If aliases aren't supported by the assembler, fail.  */
+  return false;
+#endif
+
+  /* Comdat same body aliases are only supported when comdat groups
+     are supported and the symbols are weak.  */
+  if (DECL_ONE_ONLY (decl) && (!HAVE_COMDAT_GROUP || !DECL_WEAK (decl)))
+    return false;
+
+  decl_node = cgraph_node (decl);
+
+  key.decl = alias;
+
+  slot = (struct cgraph_node **) htab_find_slot (cgraph_hash, &key, INSERT);
+
+  /* If the cgraph_node has been already created, fail.  */
+  if (*slot)
+    return false;
+
+  alias_node = cgraph_allocate_node ();
+  alias_node->decl = alias;
+  alias_node->same_body_alias = 1;
+  alias_node->same_body = decl_node;
+  alias_node->previous = NULL;
+  if (decl_node->same_body)
+    decl_node->same_body->previous = alias_node;
+  alias_node->next = decl_node->same_body;
+  decl_node->same_body = alias_node;
+  *slot = alias_node;
+  return true;
+}
+
 /* Returns the cgraph node assigned to DECL or NULL if no cgraph node
    is assigned.  */
 
@@ -540,7 +602,11 @@ cgraph_get_node (tree decl)
                                                 NO_INSERT);
 
   if (slot && *slot)
-    node = *slot;
+    {
+      node = *slot;
+      if (node->same_body_alias)
+       node = node->same_body;
+    }
   return node;
 }
 
@@ -601,9 +667,23 @@ cgraph_node_for_asm (tree asmname)
               it is __builtin_strlen and strlen, for instance.  Do we need to
               record them all?  Original implementation marked just first one
               so lets hope for the best.  */
-           if (*slot)
-             continue;
-           *slot = node;
+           if (!*slot)
+             *slot = node;
+           if (node->same_body)
+             {
+               struct cgraph_node *alias;
+
+               for (alias = node->same_body; alias; alias = alias->next)
+                 {
+                   hashval_t hash;
+                   name = DECL_ASSEMBLER_NAME (alias->decl);
+                   hash = decl_assembler_name_hash (name);
+                   slot = htab_find_slot_with_hash (assembler_name_hash, name,
+                                                    hash,  INSERT);
+                   if (!*slot)
+                     *slot = alias;
+                 }
+             }
          }
     }
 
@@ -612,7 +692,12 @@ cgraph_node_for_asm (tree asmname)
                                   NO_INSERT);
 
   if (slot)
-    return (struct cgraph_node *) *slot;
+    {
+      node = (struct cgraph_node *) *slot;
+      if (node->same_body_alias)
+       node = node->same_body;
+      return node;
+    }
   return NULL;
 }
 
@@ -1146,6 +1231,44 @@ cgraph_release_function_body (struct cgraph_node *node)
     DECL_INITIAL (node->decl) = error_mark_node;
 }
 
+/* Remove same body alias node.  */
+
+void
+cgraph_remove_same_body_alias (struct cgraph_node *node)
+{
+  void **slot;
+  int uid = node->uid;
+
+  gcc_assert (node->same_body_alias);
+  if (node->previous)
+    node->previous->next = node->next;
+  else
+    node->same_body->same_body = node->next;
+  if (node->next)
+    node->next->previous = node->previous;
+  node->next = NULL;
+  node->previous = NULL;
+  slot = htab_find_slot (cgraph_hash, node, NO_INSERT);
+  if (*slot == node)
+    htab_clear_slot (cgraph_hash, slot);
+  if (assembler_name_hash)
+    {
+      tree name = DECL_ASSEMBLER_NAME (node->decl);
+      slot = htab_find_slot_with_hash (assembler_name_hash, name,
+                                      decl_assembler_name_hash (name),
+                                      NO_INSERT);
+      if (slot && *slot == node)
+       htab_clear_slot (assembler_name_hash, slot);
+    }
+
+  /* Clear out the node to NULL all pointers and add the node to the free
+     list.  */
+  memset (node, 0, sizeof(*node));
+  node->uid = uid;
+  NEXT_FREE_NODE (node) = free_nodes;
+  free_nodes = node;
+}
+
 /* Remove the node from cgraph.  */
 
 void
@@ -1283,6 +1406,9 @@ cgraph_remove_node (struct cgraph_node *node)
       node->clone_of->clones = node->clones;
     }
 
+  while (node->same_body)
+    cgraph_remove_same_body_alias (node->same_body);
+
   /* While all the clones are removed after being proceeded, the function
      itself is kept in the cgraph even after it is compiled.  Check whether
      we are done with this body and reclaim it proactively if this is the case.
index 33eb821dd5d49693852a5eb14cf1ebb9f549e225..02c087d772e616150eecf5a25e90f5d079bc5c33 100644 (file)
@@ -184,6 +184,9 @@ struct GTY((chain_next ("%h.next"), chain_prev ("%h.previous"))) cgraph_node {
   struct cgraph_node *prev_sibling_clone;
   struct cgraph_node *clones;
   struct cgraph_node *clone_of;
+  /* For normal nodes pointer to the list of alias nodes, in alias
+     nodes pointer to the normal node.  */
+  struct cgraph_node *same_body;
   /* For functions with many calls sites it holds map from call expression
      to the edge to speed up cgraph_edge function.  */
   htab_t GTY((param_is (struct cgraph_edge))) call_site_hash;
@@ -241,6 +244,9 @@ struct GTY((chain_next ("%h.next"), chain_prev ("%h.previous"))) cgraph_node {
   unsigned alias : 1;
   /* Set for nodes that was constructed and finalized by frontend.  */
   unsigned finalized_by_frontend : 1;
+  /* Set for alias nodes, same_body points to the node they are alias of
+     and they are linked through the next/previous pointers.  */
+  unsigned same_body_alias : 1;
 };
 
 typedef struct cgraph_node *cgraph_node_ptr;
@@ -416,6 +422,8 @@ struct cgraph_edge *cgraph_create_edge (struct cgraph_node *,
 
 struct cgraph_node * cgraph_get_node (tree);
 struct cgraph_node *cgraph_node (tree);
+bool cgraph_same_body_alias (tree, tree);
+void cgraph_remove_same_body_alias (struct cgraph_node *);
 struct cgraph_node *cgraph_node_for_asm (tree);
 struct cgraph_node *cgraph_node_for_decl (tree);
 struct cgraph_edge *cgraph_edge (struct cgraph_node *, gimple);
index 2c232a53ad25e6e3ee1501a53be67b6ac53ce532..e934b3d8abc7ff73a51c15e52ce26d5bb7bd3012 100644 (file)
@@ -1040,7 +1040,7 @@ cgraph_analyze_functions (void)
 static void
 cgraph_emit_thunks (void)
 {
-  struct cgraph_node *n;
+  struct cgraph_node *n, *alias;
 
   for (n = cgraph_nodes; n; n = n->next)
     {
@@ -1053,7 +1053,12 @@ cgraph_emit_thunks (void)
         cgraph_mark_functions_to_output in cgraph_optimize).  */
       if (n->reachable
          && !DECL_EXTERNAL (n->decl))
-       lang_hooks.callgraph.emit_associated_thunks (n->decl);
+       {
+         lang_hooks.callgraph.emit_associated_thunks (n->decl);
+         for (alias = n->same_body; alias; alias = alias->next)
+           if (!DECL_EXTERNAL (alias->decl))
+             lang_hooks.callgraph.emit_associated_thunks (alias->decl);
+       }
     }
 }
 
@@ -1175,6 +1180,14 @@ cgraph_expand_function (struct cgraph_node *node)
   /* Make sure that BE didn't give up on compiling.  */
   gcc_assert (TREE_ASM_WRITTEN (decl));
   current_function_decl = NULL;
+  if (node->same_body)
+    {
+      struct cgraph_node *alias;
+      bool saved_alias = node->alias;
+      for (alias = node->same_body; alias; alias = alias->next)
+       assemble_alias (alias->decl, DECL_ASSEMBLER_NAME (decl));
+      node->alias = saved_alias;
+    }
   gcc_assert (!cgraph_preserve_function_body_p (decl));
   cgraph_release_function_body (node);
   /* Eliminate all call edges.  This is important so the GIMPLE_CALL no longer
@@ -1924,7 +1937,22 @@ cgraph_materialize_all_clones (void)
              {
                gimple new_stmt;
                gimple_stmt_iterator gsi;
-               
+
+               if (e->callee->same_body)
+                 {
+                   struct cgraph_node *alias;
+
+                   for (alias = e->callee->same_body;
+                        alias;
+                        alias = alias->next)
+                     if (decl == alias->decl)
+                       break;
+                   /* Don't update call from same body alias to the real
+                      function.  */
+                   if (alias)
+                     continue;
+                 }
+
                if (cgraph_dump_file)
                  {
                    fprintf (cgraph_dump_file, "updating call of %s in %s:",
index 17968f50860988e50e80d868cd621468212db989..b3acf8e15f1687be657f09d9251653a6d1fa07bc 100644 (file)
@@ -1,3 +1,18 @@
+2009-11-18  Jakub Jelinek  <jakub@redhat.com>
+
+       PR c++/3187
+       * cp-tree.h (expand_or_defer_fn_1): New prototype.
+       * decl2.c (cp_write_global_declarations): Mark as !DECL_EXTERNAL
+       also all same_body aliases.
+       * semantics.c (expand_or_defer_fn): Move most of the function
+       except registering with cgraph to ...
+       (expand_or_defer_fn_1): ... here.  New function.
+       * optimize.c: Include cgraph.h.
+       (maybe_clone_body): If in charge parm is not used and both base
+       and complete clones are created and are not comdat, tell cgraph
+       they have the same body.
+       * Make-lang.in (cp/optimize.o): Depend on $(CGRAPH_H).
+
 2009-11-17  Paolo Carlini  <paolo.carlini@oracle.com>
 
        PR c++/42058
index 861c93df066bb53e83dd5d7b2df1dadb3353acc1..f5c652ec552fdc9634ef0e0cb154e3fd7f69fe5d 100644 (file)
@@ -303,7 +303,7 @@ cp/semantics.o: cp/semantics.c $(CXX_TREE_H) $(TM_H) except.h toplev.h \
 cp/dump.o: cp/dump.c $(CXX_TREE_H) $(TM_H) $(TREE_DUMP_H)
 cp/optimize.o: cp/optimize.c $(CXX_TREE_H) $(TM_H) rtl.h $(INTEGRATE_H) \
   insn-config.h input.h $(PARAMS_H) debug.h $(TREE_INLINE_H) $(GIMPLE_H) \
-  $(TARGET_H) tree-iterator.h
+  $(TARGET_H) tree-iterator.h $(CGRAPH_H)
 cp/mangle.o: cp/mangle.c $(CXX_TREE_H) $(TM_H) toplev.h $(REAL_H) \
   gt-cp-mangle.h $(TARGET_H) $(TM_P_H)
 cp/parser.o: cp/parser.c $(CXX_TREE_H) $(TM_H) $(DIAGNOSTIC_H) gt-cp-parser.h \
index a71dc739cfa66d2f9c6856a44aaa6cd36b56f28b..3652fe072dffaf53dcc2356f61b45b50c42f3249 100644 (file)
@@ -5037,6 +5037,7 @@ extern void finish_eh_cleanup                     (tree);
 extern void emit_associated_thunks             (tree);
 extern void finish_mem_initializers            (tree);
 extern tree check_template_template_default_arg (tree);
+extern bool expand_or_defer_fn_1               (tree);
 extern void expand_or_defer_fn                 (tree);
 extern void check_accessibility_of_qualified_id (tree, tree, tree);
 extern tree finish_qualified_id_expr           (tree, tree, bool, bool,
index 7c3f7c058d6ad5130957593f9743ae1ef91aabec..c0febad25157eba478060f1226163ffa5936bc9b 100644 (file)
@@ -3658,7 +3658,19 @@ cp_write_global_declarations (void)
          if (DECL_NOT_REALLY_EXTERN (decl)
              && DECL_INITIAL (decl)
              && decl_needed_p (decl))
-           DECL_EXTERNAL (decl) = 0;
+           {
+             struct cgraph_node *node = cgraph_get_node (decl), *alias;
+
+             DECL_EXTERNAL (decl) = 0;
+             /* If we mark !DECL_EXTERNAL one of the same body aliases,
+                we need to mark all of them that way.  */
+             if (node && node->same_body)
+               {
+                 DECL_EXTERNAL (node->decl) = 0;
+                 for (alias = node->same_body; alias; alias = alias->next)
+                   DECL_EXTERNAL (alias->decl) = 0;
+               }
+           }
 
          /* If we're going to need to write this function out, and
             there's already a body for it, create RTL for it now.
index 662bd4a22a38d3644ca5ec33b7f881e9c462e82d..c691f0b6a0bd4e227f6f34902d703f716a290b61 100644 (file)
@@ -42,6 +42,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-dump.h"
 #include "gimple.h"
 #include "tree-iterator.h"
+#include "cgraph.h"
 
 /* Prototypes.  */
 
@@ -149,8 +150,10 @@ bool
 maybe_clone_body (tree fn)
 {
   tree clone;
-  tree complete_dtor = NULL_TREE;
+  tree fns[3];
   bool first = true;
+  bool in_charge_parm_used;
+  int idx;
 
   /* We only clone constructors and destructors.  */
   if (!DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P (fn)
@@ -160,25 +163,40 @@ maybe_clone_body (tree fn)
   /* Emit the DWARF1 abstract instance.  */
   (*debug_hooks->deferred_inline_function) (fn);
 
+  in_charge_parm_used = CLASSTYPE_VBASECLASSES (DECL_CONTEXT (fn)) != NULL;
+  fns[0] = NULL_TREE;
+  fns[1] = NULL_TREE;
+  fns[2] = NULL_TREE;
+
   /* Look for the complete destructor which may be used to build the
      delete destructor.  */
   FOR_EACH_CLONE (clone, fn)
-    if (DECL_NAME (clone) == complete_dtor_identifier)
-      {
-        complete_dtor = clone;
-        break;
-      }
+    if (DECL_NAME (clone) == complete_dtor_identifier
+       || DECL_NAME (clone) == complete_ctor_identifier)
+      fns[1] = clone;
+    else if (DECL_NAME (clone) == base_dtor_identifier
+            || DECL_NAME (clone) == base_ctor_identifier)
+      fns[0] = clone;
+    else if (DECL_NAME (clone) == deleting_dtor_identifier)
+      fns[2] = clone;
+    else
+      gcc_unreachable ();
 
   /* We know that any clones immediately follow FN in the TYPE_METHODS
      list.  */
   push_to_top_level ();
-  FOR_EACH_CLONE (clone, fn)
+  for (idx = 0; idx < 3; idx++)
     {
       tree parm;
       tree clone_parm;
       int parmno;
+      bool alias = false;
       struct pointer_map_t *decl_map;
 
+      clone = fns[idx];
+      if (!clone)
+       continue;      
+
       /* Update CLONE's source position information to match FN's.  */
       DECL_SOURCE_LOCATION (clone) = DECL_SOURCE_LOCATION (fn);
       DECL_DECLARED_INLINE_P (clone) = DECL_DECLARED_INLINE_P (fn);
@@ -223,12 +241,25 @@ maybe_clone_body (tree fn)
       /* Start processing the function.  */
       start_preparsed_function (clone, NULL_TREE, SF_PRE_PARSED);
 
+      /* Tell cgraph if both ctors or both dtors are known to have
+        the same body.  */
+      if (!in_charge_parm_used
+         && fns[0]
+         && idx == 1
+         && !flag_use_repository
+         && DECL_INTERFACE_KNOWN (fns[0])
+         && !DECL_ONE_ONLY (fns[0])
+         && cgraph_same_body_alias (clone, fns[0]))
+       alias = true;
+
       /* Build the delete destructor by calling complete destructor
          and delete function.  */
-      if (DECL_NAME (clone) == deleting_dtor_identifier)
-        build_delete_destructor_body (clone, complete_dtor);
+      if (idx == 2)
+       build_delete_destructor_body (clone, fns[1]);
+      else if (alias)
+       /* No need to populate body.  */ ;
       else
-        {
+       {
           /* Remap the parameters.  */
           decl_map = pointer_map_create ();
           for (parmno = 0,
@@ -291,7 +322,10 @@ maybe_clone_body (tree fn)
       /* Now, expand this function into RTL, if appropriate.  */
       finish_function (0);
       BLOCK_ABSTRACT_ORIGIN (DECL_INITIAL (clone)) = DECL_INITIAL (fn);
-      expand_or_defer_fn (clone);
+      if (alias)
+       expand_or_defer_fn_1 (clone);
+      else
+       expand_or_defer_fn (clone);
       first = false;
     }
   pop_from_top_level ();
index c1df24bfffaaaf10e7d8feafe01b2cdc5f303982..7401593bcc68597face45c166dda6b1bc4addae5 100644 (file)
@@ -3315,8 +3315,8 @@ emit_associated_thunks (tree fn)
 
 /* Generate RTL for FN.  */
 
-void
-expand_or_defer_fn (tree fn)
+bool
+expand_or_defer_fn_1 (tree fn)
 {
   /* When the parser calls us after finishing the body of a template
      function, we don't really want to expand the body.  */
@@ -3330,7 +3330,7 @@ expand_or_defer_fn (tree fn)
         is not a GC root.  */
       if (!function_depth)
        ggc_collect ();
-      return;
+      return false;
     }
 
   gcc_assert (DECL_SAVED_TREE (fn));
@@ -3343,7 +3343,7 @@ expand_or_defer_fn (tree fn)
         it out, even though we haven't.  */
       TREE_ASM_WRITTEN (fn) = 1;
       DECL_SAVED_TREE (fn) = NULL_TREE;
-      return;
+      return false;
     }
 
   /* We make a decision about linkage for these functions at the end
@@ -3390,14 +3390,23 @@ expand_or_defer_fn (tree fn)
   /* There's no reason to do any of the work here if we're only doing
      semantic analysis; this code just generates RTL.  */
   if (flag_syntax_only)
-    return;
+    return false;
 
-  function_depth++;
+  return true;
+}
+
+void
+expand_or_defer_fn (tree fn)
+{
+  if (expand_or_defer_fn_1 (fn))
+    {
+      function_depth++;
 
-  /* Expand or defer, at the whim of the compilation unit manager.  */
-  cgraph_finalize_function (fn, function_depth > 1);
+      /* Expand or defer, at the whim of the compilation unit manager.  */
+      cgraph_finalize_function (fn, function_depth > 1);
 
-  function_depth--;
+      function_depth--;
+    }
 }
 
 struct nrv_data
index 38d02b8317578af642803da422e164bc3a5ba6a7..a3c7719ffbf383c6a91a560ebf9a90dbd1ea2a7a 100644 (file)
@@ -306,6 +306,23 @@ lto_output_node (struct lto_simple_output_block *ob, struct cgraph_node *node,
   lto_output_sleb128_stream (ob->main_stream,
                             node->global.estimated_growth);
   lto_output_uleb128_stream (ob->main_stream, node->global.inlined);
+  if (node->same_body)
+    {
+      struct cgraph_node *alias;
+      unsigned long alias_count = 1;
+      for (alias = node->same_body; alias->next; alias = alias->next)
+       alias_count++;
+      lto_output_uleb128_stream (ob->main_stream, alias_count);
+      do
+       {
+         lto_output_fn_decl_index (ob->decl_state, ob->main_stream,
+                                   alias->decl);
+         alias = alias->previous;
+       }
+      while (alias);
+    }
+  else
+    lto_output_uleb128_stream (ob->main_stream, 0);
 }
 
 /* Stream out profile_summary to OB.  */
@@ -495,6 +512,7 @@ input_node (struct lto_file_decl_data *file_data,
   int self_size = 0;
   int time_inlining_benefit = 0;
   int size_inlining_benefit = 0;
+  unsigned long same_body_count = 0;
   bool inlined = false;
 
   clone_p = (lto_input_uleb128 (ib) != 0);
@@ -528,6 +546,7 @@ input_node (struct lto_file_decl_data *file_data,
   size = lto_input_sleb128 (ib);
   estimated_growth = lto_input_sleb128 (ib);
   inlined = lto_input_uleb128 (ib);
+  same_body_count = lto_input_uleb128 (ib);
 
   /* Make sure that we have not read this node before.  Nodes that
      have already been read will have their tag stored in the 'aux'
@@ -553,6 +572,13 @@ input_node (struct lto_file_decl_data *file_data,
   node->global.estimated_growth = estimated_growth;
   node->global.inlined = inlined;
 
+  while (same_body_count-- > 0)
+    {
+      tree alias_decl;
+      decl_index = lto_input_uleb128 (ib);
+      alias_decl = lto_file_decl_data_get_fn_decl (file_data, decl_index);
+      cgraph_same_body_alias (alias_decl, fn_decl);
+    }
   return node;
 }
 
index 5f98a3515f288f08ba1f1f2440a9160b5a2ec473..3b2823bb12e2298ec0209f4dc7bc74499f74115d 100644 (file)
@@ -221,6 +221,25 @@ lto_cgraph_replace_node (struct cgraph_node *node,
       cgraph_remove_edge (e);
     }
 
+  if (node->same_body)
+    {
+      struct cgraph_node *alias;
+
+      for (alias = node->same_body; alias; alias = alias->next)
+       if (DECL_ASSEMBLER_NAME_SET_P (alias->decl))
+         {
+           lto_symtab_entry_t se
+             = lto_symtab_get (DECL_ASSEMBLER_NAME (alias->decl));
+
+           for (; se; se = se->next)
+             if (se->node == node)
+               {
+                 se->node = NULL;
+                 break;
+               }
+         }
+    }
+
   /* Finally remove the replaced node.  */
   cgraph_remove_node (node);
 }
@@ -634,7 +653,22 @@ lto_symtab_merge_cgraph_nodes_1 (void **slot, void *data ATTRIBUTE_UNUSED)
   for (e = prevailing->next; e; e = e->next)
     {
       if (e->node != NULL)
-       lto_cgraph_replace_node (e->node, prevailing->node);
+       {
+         if (e->node->decl != e->decl && e->node->same_body)
+           {
+             struct cgraph_node *alias;
+
+             for (alias = e->node->same_body; alias; alias = alias->next)
+               if (alias->decl == e->decl)
+                 break;
+             if (alias)
+               {
+                 cgraph_remove_same_body_alias (alias);
+                 continue;
+               }
+           }
+         lto_cgraph_replace_node (e->node, prevailing->node);
+       }
     }
 
   /* Drop all but the prevailing decl from the symtab.  */
index 3ebf59bbc6aa86fb12ca6f3af12bcc29a9997bf9..47687cc3a58b1787dbb73586b8c496ddfe623179 100644 (file)
@@ -1,3 +1,11 @@
+2009-11-18  Jakub Jelinek  <jakub@redhat.com>
+
+       PR c++/3187
+       * g++.dg/abi/mangle26.C: Also match *C2* definition.
+       * g++.dg/abi/mangle27.C: Likewise.
+       * g++.dg/abi/mangle28.C: Likewise.
+       * g++.dg/abi/mangle29.C: Likewise.
+
 2009-11-18  Alexandre Oliva  <aoliva@redhat.com>
 
        PR debug/41926
index cfec4b938724138d41b10dc82168edd7f99f0d66..77b0eabdaa5cb69c12a87793ec15be3233ab8ec0 100644 (file)
@@ -11,4 +11,4 @@ namespace std {
 
 std::A a;
 
-// { dg-final { scan-assembler "\n_?_ZNSt1AC1Ev\[: \t\n\]" } }
+// { dg-final { scan-assembler "\n_?_ZNSt1AC\[12\]Ev\[: \t\n\]" } }
index da4efbae696c80396e3516393842c9c1d3275f83..2d15abbf96124c91699e9cd1c0c513772ca08408 100644 (file)
@@ -11,4 +11,4 @@ namespace std {
 
 std::basic_iostream<char,std::char_traits<char> > s1;
 
-// { dg-final { scan-assembler "\n_?_ZNSdC1Ev\[: \t\n\]" } }
+// { dg-final { scan-assembler "\n_?_ZNSdC\[12\]Ev\[: \t\n\]" } }
index b8c40ca8d856b1e4485d307ea2cbc7e400c773e9..bea8ce01974163ce014b6503767bb05c85031478 100644 (file)
@@ -11,4 +11,4 @@ namespace std {
 
 std::basic_istream<char,std::char_traits<char> > s1;
 
-// { dg-final { scan-assembler "\n_?_ZNSiC1Ev\[: \t\n\]" } }
+// { dg-final { scan-assembler "\n_?_ZNSiC\[12\]Ev\[: \t\n\]" } }
index 4f64efb676a4d8f4da80177ab9ad9fc544b8deb2..aaff2b4eb68be2cce8600e70e53818bc35adec5a 100644 (file)
@@ -11,4 +11,4 @@ namespace std {
 
 std::basic_ostream<char,std::char_traits<char> > s1;
 
-// { dg-final { scan-assembler "\n_?_ZNSoC1Ev\[: \t\n\]" } }
+// { dg-final { scan-assembler "\n_?_ZNSoC\[12\]Ev\[: \t\n\]" } }