commit 062e714358ad384f1a69051f3b7f3902b9714904
Author: Jason Merrill <jason@redhat.com>
Date:   Mon May 19 15:41:24 2014 -0400

    	PR c++/47202
    gcc/cp/
    	* decl.c (cxx_comdat_group): Return a decl.
    	* optimize.c (cdtor_comdat_group): Get its DECL_ASSEMBLER_NAME.
    gcc/
    	* cgraph.h (symtab_node::get_comdat_group_id): New.
    	* cgraphunit.c (analyze_functions): Call it.
    	* symtab.c (dump_symtab_node): Likewise.
    	* tree.c (decl_comdat_group_id): New.
    	* tree.h: Declare it.
    	* lto-streamer-out.c (write_symbol): Use it.
    	* trans-mem.c (ipa_tm_create_version_alias): Likewise.

diff --git a/gcc/cgraph.h b/gcc/cgraph.h
index 8556e2d..44c8211 100644
--- a/gcc/cgraph.h
+++ b/gcc/cgraph.h
@@ -147,6 +147,13 @@ public:
       return comdat_group_;
     }
 
+  tree get_comdat_group_id ()
+    {
+      if (comdat_group_ && TREE_CODE (comdat_group_) != IDENTIFIER_NODE)
+	comdat_group_ = DECL_ASSEMBLER_NAME (comdat_group_);
+      return comdat_group_;
+    }
+
   /* Set comdat group.  */
   void set_comdat_group (tree group)
     {
diff --git a/gcc/cgraphunit.c b/gcc/cgraphunit.c
index 3bd364b..e19b0a2 100644
--- a/gcc/cgraphunit.c
+++ b/gcc/cgraphunit.c
@@ -974,6 +974,8 @@ analyze_functions (void)
 	   node != first_analyzed
 	   && node != first_analyzed_var; node = node->next)
 	{
+	  /* Convert COMDAT group designators to IDENTIFIER_NODEs.  */
+	  node->get_comdat_group_id ();
 	  if (decide_is_symbol_needed (node))
 	    {
 	      enqueue_node (node);
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 9e97ff8..3502447 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -14484,18 +14484,17 @@ cp_missing_noreturn_ok_p (tree decl)
   return DECL_MAIN_P (decl);
 }
 
-/* Return the COMDAT group into which DECL should be placed.  */
+/* Return the decl used to identify the COMDAT group into which DECL should
+   be placed.  */
 
 tree
 cxx_comdat_group (tree decl)
 {
-  tree name;
-
   /* Virtual tables, construction virtual tables, and virtual table
      tables all go in a single COMDAT group, named after the primary
      virtual table.  */
   if (VAR_P (decl) && DECL_VTABLE_OR_VTT_P (decl))
-    name = DECL_ASSEMBLER_NAME (CLASSTYPE_VTABLES (DECL_CONTEXT (decl)));
+    decl = CLASSTYPE_VTABLES (DECL_CONTEXT (decl));
   /* For all other DECLs, the COMDAT group is the mangled name of the
      declaration itself.  */
   else
@@ -14513,10 +14512,9 @@ cxx_comdat_group (tree decl)
 	  else
 	    break;
 	}
-      name = DECL_ASSEMBLER_NAME (decl);
     }
 
-  return name;
+  return decl;
 }
 
 /* Returns the return type for FN as written by the user, which may include
diff --git a/gcc/cp/mangle.c b/gcc/cp/mangle.c
index 4205fec..6b0c555 100644
--- a/gcc/cp/mangle.c
+++ b/gcc/cp/mangle.c
@@ -3517,10 +3517,15 @@ mangle_decl (const tree decl)
       DECL_IGNORED_P (alias) = 1;
       TREE_PUBLIC (alias) = TREE_PUBLIC (decl);
       DECL_VISIBILITY (alias) = DECL_VISIBILITY (decl);
+      DECL_EXTERNAL (alias) = DECL_EXTERNAL (decl);
       if (vague_linkage_p (decl))
 	DECL_WEAK (alias) = 1;
       if (TREE_CODE (decl) == FUNCTION_DECL)
-	cgraph_same_body_alias (cgraph_get_create_node (decl), alias, decl);
+	{
+	  /* Don't create an alias to an unreferenced function.  */
+	  if (struct cgraph_node *n = cgraph_get_node (decl))
+	    cgraph_same_body_alias (n, alias, decl);
+	}
       else
 	varpool_extra_name_alias (alias, decl);
 #endif
diff --git a/gcc/cp/optimize.c b/gcc/cp/optimize.c
index a58565c..3f89b81 100644
--- a/gcc/cp/optimize.c
+++ b/gcc/cp/optimize.c
@@ -170,6 +170,8 @@ cdtor_comdat_group (tree complete, tree base)
     complete_name = cxx_comdat_group (complete);
   if (base_name == NULL)
     base_name = cxx_comdat_group (base);
+  complete_name = DECL_ASSEMBLER_NAME (complete_name);
+  base_name = DECL_ASSEMBLER_NAME (base_name);
   gcc_assert (IDENTIFIER_LENGTH (complete_name)
 	      == IDENTIFIER_LENGTH (base_name));
   grp_name = XALLOCAVEC (char, IDENTIFIER_LENGTH (complete_name) + 1);
diff --git a/gcc/lto-streamer-out.c b/gcc/lto-streamer-out.c
index d1c8d9f..034d9d9 100644
--- a/gcc/lto-streamer-out.c
+++ b/gcc/lto-streamer-out.c
@@ -2329,7 +2329,7 @@ write_symbol (struct streamer_tree_cache_d *cache,
     size = 0;
 
   if (DECL_ONE_ONLY (t))
-    comdat = IDENTIFIER_POINTER (DECL_COMDAT_GROUP (t));
+    comdat = IDENTIFIER_POINTER (decl_comdat_group_id (t));
   else
     comdat = "";
 
diff --git a/gcc/symtab.c b/gcc/symtab.c
index 8abb7a1..79fdbc2 100644
--- a/gcc/symtab.c
+++ b/gcc/symtab.c
@@ -560,7 +560,7 @@ dump_symtab_base (FILE *f, symtab_node *node)
     fprintf (f, " comdat");
   if (node->get_comdat_group ())
     fprintf (f, " comdat_group:%s",
-	     IDENTIFIER_POINTER (node->get_comdat_group ()));
+	     IDENTIFIER_POINTER (node->get_comdat_group_id ()));
   if (DECL_ONE_ONLY (node->decl))
     fprintf (f, " one_only");
   if (DECL_SECTION_NAME (node->decl))
@@ -1062,7 +1062,7 @@ symtab_resolve_alias (symtab_node *node, symtab_node *target)
   node->analyzed = true;
   ipa_record_reference (node, target, IPA_REF_ALIAS, NULL);
 
-  /* Alias targets become reudndant after alias is resolved into an reference.
+  /* Alias targets become redundant after alias is resolved into an reference.
      We do not want to keep it around or we would have to mind updating them
      when renaming symbols.  */
   node->alias_target = NULL;
diff --git a/gcc/trans-mem.c b/gcc/trans-mem.c
index a0903e4..7c9f163 100644
--- a/gcc/trans-mem.c
+++ b/gcc/trans-mem.c
@@ -4852,7 +4852,7 @@ ipa_tm_create_version_alias (struct cgraph_node *node, void *data)
 
   /* Perform the same remapping to the comdat group.  */
   if (DECL_ONE_ONLY (new_decl))
-    varpool_get_node (new_decl)->set_comdat_group (tm_mangle (DECL_COMDAT_GROUP (old_decl)));
+    varpool_get_node (new_decl)->set_comdat_group (tm_mangle (decl_comdat_group_id (old_decl)));
 
   new_node = cgraph_same_body_alias (NULL, new_decl, info->new_decl);
   new_node->tm_clone = true;
diff --git a/gcc/tree.c b/gcc/tree.c
index 394a821..cf7e362 100644
--- a/gcc/tree.c
+++ b/gcc/tree.c
@@ -603,7 +603,9 @@ decl_assembler_name (tree decl)
   return DECL_WITH_VIS_CHECK (decl)->decl_with_vis.assembler_name;
 }
 
-/* Return comdat group of DECL.  */
+/* When the target supports COMDAT groups, this indicates which group the
+   DECL is associated with.  This can be either an IDENTIFIER_NODE or a
+   decl, in which case its DECL_ASSEMBLER_NAME identifies the group.  */
 tree
 decl_comdat_group (tree node)
 {
@@ -613,6 +615,16 @@ decl_comdat_group (tree node)
   return snode->get_comdat_group ();
 }
 
+/* Likewise, but make sure it's been reduced to an IDENTIFIER_NODE.  */
+tree
+decl_comdat_group_id (tree node)
+{
+  struct symtab_node *snode = symtab_get_node (node);
+  if (!snode)
+    return NULL;
+  return snode->get_comdat_group_id ();
+}
+
 /* Compute the number of bytes occupied by a tree with code CODE.
    This function cannot be used for nodes that have variable sizes,
    including TREE_VEC, INTEGER_CST, STRING_CST, and CALL_EXPR.  */
diff --git a/gcc/tree.h b/gcc/tree.h
index de2b5c8..9fe7360 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -3432,6 +3432,7 @@ tree_operand_check_code (const_tree __t, enum tree_code __code, int __i,
 
 extern tree decl_assembler_name (tree);
 extern tree decl_comdat_group (tree);
+extern tree decl_comdat_group_id (tree);
 
 /* Compute the number of bytes occupied by 'node'.  This routine only
    looks at TREE_CODE and, if the code is TREE_VEC, TREE_VEC_LENGTH.  */
