Submitted By:            Bruce Dubbs <bdubbs at linuxfromscratch dot org>
Date:                    2014-09-07
Initial Package Version: 4.9.1
Upstream Status:         Applied
Origin:                  Upstream
Description:             This patch fixes an undefined symbol error because
                         of internal devirtualization.

diff -Naur a/gcc/cp/decl2.c b/gcc/cp/decl2.c
--- a/gcc/cp/decl2.c	2014-04-01 19:49:38.000000000 +0200
+++ b/gcc/cp/decl2.c	2014-09-07 14:01:14.504752625 +0200
@@ -1896,6 +1896,12 @@
 	 definition.  */
       struct cgraph_node *node = cgraph_get_create_node (decl);
       node->forced_by_abi = true;
+
+      /* #pragma interface and -frepo code can call mark_needed for
+          maybe-in-charge 'tors; mark the clones as well.  */
+      tree clone;
+      FOR_EACH_CLONE (clone, decl)
+	mark_needed (clone);
     }
   else if (TREE_CODE (decl) == VAR_DECL)
     {
@@ -2678,17 +2684,7 @@
     {
       /* The repository indicates that this entity should be defined
 	 here.  Make sure the back end honors that request.  */
-      if (VAR_P (decl))
-	mark_needed (decl);
-      else if (DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P (decl)
-	       || DECL_MAYBE_IN_CHARGE_DESTRUCTOR_P (decl))
-	{
-	  tree clone;
-	  FOR_EACH_CLONE (clone, decl)
-	    mark_needed (clone);
-	}
-      else
-	mark_needed (decl);
+      mark_needed (decl);
       /* Output the definition as an ordinary strong definition.  */
       DECL_EXTERNAL (decl) = 0;
       DECL_INTERFACE_KNOWN (decl) = 1;
diff -Naur a/gcc/cp/decl.c b/gcc/cp/decl.c
--- a/gcc/cp/decl.c	2014-06-09 21:29:17.000000000 +0200
+++ b/gcc/cp/decl.c	2014-09-07 14:03:27.252996512 +0200
@@ -2185,6 +2185,7 @@
 		      olddecl);
 
 	  SET_DECL_TEMPLATE_SPECIALIZATION (olddecl);
+	  DECL_COMDAT (newdecl) = DECL_DECLARED_INLINE_P (newdecl);
 
 	  /* Don't propagate visibility from the template to the
 	     specialization here.  We'll do that in determine_visibility if
@@ -4638,6 +4639,8 @@
       if (DECL_LANG_SPECIFIC (decl) && DECL_USE_TEMPLATE (decl))
 	{
 	  SET_DECL_TEMPLATE_SPECIALIZATION (decl);
+	  if (TREE_CODE (decl) == FUNCTION_DECL)
+	    DECL_COMDAT (decl) = DECL_DECLARED_INLINE_P (decl);
 
 	  /* [temp.expl.spec] An explicit specialization of a static data
 	     member of a template is a definition if the declaration
@@ -7602,7 +7605,10 @@
 
   /* If the declaration was declared inline, mark it as such.  */
   if (inlinep)
-    DECL_DECLARED_INLINE_P (decl) = 1;
+    {
+      DECL_DECLARED_INLINE_P (decl) = 1;
+      DECL_COMDAT (decl) = 1;
+    }
   if (inlinep & 2)
     DECL_DECLARED_CONSTEXPR_P (decl) = true;
 
@@ -14147,6 +14153,7 @@
 
   check_template_shadow (fndecl);
 
+  DECL_COMDAT (fndecl) = 1;
   DECL_DECLARED_INLINE_P (fndecl) = 1;
   DECL_NO_INLINE_WARNING_P (fndecl) = 1;
 
diff -Naur a/gcc/cp/method.c b/gcc/cp/method.c
--- a/gcc/cp/method.c	2014-03-26 22:33:28.000000000 +0100
+++ b/gcc/cp/method.c	2014-09-07 14:01:14.508085994 +0200
@@ -1760,8 +1760,6 @@
   DECL_ARGUMENTS (fn) = this_parm;
 
   grokclassfn (type, fn, kind == sfk_destructor ? DTOR_FLAG : NO_SPECIAL);
-  set_linkage_according_to_type (type, fn);
-  rest_of_decl_compilation (fn, toplevel_bindings_p (), at_eof);
   DECL_IN_AGGR_P (fn) = 1;
   DECL_ARTIFICIAL (fn) = 1;
   DECL_DEFAULTED_FN (fn) = 1;
@@ -1773,6 +1771,9 @@
   DECL_EXTERNAL (fn) = true;
   DECL_NOT_REALLY_EXTERN (fn) = 1;
   DECL_DECLARED_INLINE_P (fn) = 1;
+  DECL_COMDAT (fn) = 1;
+  set_linkage_according_to_type (type, fn);
+  rest_of_decl_compilation (fn, toplevel_bindings_p (), at_eof);
   gcc_assert (!TREE_USED (fn));
 
   /* Restore PROCESSING_TEMPLATE_DECL.  */
diff -Naur a/gcc/cp/pt.c b/gcc/cp/pt.c
--- a/gcc/cp/pt.c	2014-06-30 20:52:45.000000000 +0200
+++ b/gcc/cp/pt.c	2014-09-07 14:01:14.514752733 +0200
@@ -2783,6 +2783,9 @@
 	       It's just the name of an instantiation.  But, it's not
 	       a request for an instantiation, either.  */
 	    SET_DECL_IMPLICIT_INSTANTIATION (decl);
+	  else
+	    /* A specialization is not necessarily COMDAT.  */
+	    DECL_COMDAT (decl) = DECL_DECLARED_INLINE_P (decl);
 
 	  /* Register this specialization so that we can find it
 	     again.  */
@@ -5022,6 +5025,14 @@
 	DECL_TEMPLATE_INFO (decl) = info;
     }
 
+  if (flag_implicit_templates
+      && !is_friend
+      && TREE_CODE (decl) == FUNCTION_DECL)
+    /* Set DECL_COMDAT on template instantiations; if we force
+       them to be emitted by explicit instantiation or -frepo,
+       mark_needed will tell cgraph to do the right thing.  */
+    DECL_COMDAT (decl) = true;
+
   return DECL_TEMPLATE_RESULT (tmpl);
 }
 
diff -Naur a/gcc/cp/tree.c b/gcc/cp/tree.c
--- a/gcc/cp/tree.c	2014-06-30 16:25:21.000000000 +0200
+++ b/gcc/cp/tree.c	2014-09-07 14:01:14.518086103 +0200
@@ -3716,23 +3716,15 @@
   if (TREE_CODE (decl) == CONST_DECL)
     return decl_linkage (TYPE_NAME (DECL_CONTEXT (decl)));
 
-  /* Some things that are not TREE_PUBLIC have external linkage, too.
-     For example, on targets that don't have weak symbols, we make all
-     template instantiations have internal linkage (in the object
-     file), but the symbols should still be treated as having external
-     linkage from the point of view of the language.  */
-  if (VAR_OR_FUNCTION_DECL_P (decl)
-      && DECL_COMDAT (decl))
-    return lk_external;
-
   /* Things in local scope do not have linkage, if they don't have
      TREE_PUBLIC set.  */
   if (decl_function_context (decl))
     return lk_none;
 
   /* Members of the anonymous namespace also have TREE_PUBLIC unset, but
-     are considered to have external linkage for language purposes.  DECLs
-     really meant to have internal linkage have DECL_THIS_STATIC set.  */
+     are considered to have external linkage for language purposes, as do
+     template instantiations on targets without weak symbols.  DECLs really
+     meant to have internal linkage have DECL_THIS_STATIC set.  */
   if (TREE_CODE (decl) == TYPE_DECL)
     return lk_external;
   if (VAR_OR_FUNCTION_DECL_P (decl))
diff -Naur a/gcc/testsuite/g++.dg/abi/spec1.C b/gcc/testsuite/g++.dg/abi/spec1.C
--- a/gcc/testsuite/g++.dg/abi/spec1.C	1970-01-01 01:00:00.000000000 +0100
+++ b/gcc/testsuite/g++.dg/abi/spec1.C	2014-09-07 14:01:14.518086103 +0200
@@ -0,0 +1,4 @@
+// { dg-final { scan-assembler-not "weak" } }
+
+template <class T> struct A { static int i; };
+template<> int A<int>::i = 42;
diff -Naur a/gcc/testsuite/g++.dg/opt/devirt4.C b/gcc/testsuite/g++.dg/opt/devirt4.C
--- a/gcc/testsuite/g++.dg/opt/devirt4.C	2014-02-25 19:54:48.000000000 +0100
+++ b/gcc/testsuite/g++.dg/opt/devirt4.C	2014-09-07 14:01:14.518086103 +0200
@@ -1,8 +1,7 @@
 // PR lto/53808
-// Devirtualization + inlining should produce a non-virtual
-// call to ~foo.
-// { dg-options "-O -fdevirtualize" }
-// { dg-final { scan-assembler "_ZN3fooD2Ev" } }
+// Devirtualization should not produce an external ref to ~bar.
+// { dg-options "-O2" }
+// { dg-final { scan-assembler-not "_ZN3barD0Ev" } }
 
 struct foo {
  virtual ~foo();
diff -Naur a/gcc/testsuite/g++.dg/opt/devirt5.C b/gcc/testsuite/g++.dg/opt/devirt5.C
--- a/gcc/testsuite/g++.dg/opt/devirt5.C	1970-01-01 01:00:00.000000000 +0100
+++ b/gcc/testsuite/g++.dg/opt/devirt5.C	2014-09-07 14:01:14.518086103 +0200
@@ -0,0 +1,19 @@
+// PR c++/61659
+// { dg-options "-O3" }
+// { dg-final { scan-assembler-not "_ZN6parserIiE9getOptionEv" } }
+
+struct generic_parser_base {
+  virtual void getOption();
+  void getExtraOptionNames() { getOption(); }
+};
+template <class DataType> struct parser : public generic_parser_base {
+  virtual void getOption() {}
+};
+struct PassNameParser : public parser<int> {
+  PassNameParser();
+};
+struct list {
+  PassNameParser Parser;
+  virtual void getExtraOptionNames() { return Parser.getExtraOptionNames(); }
+};
+list PassList;
diff -Naur a/gcc/testsuite/g++.dg/template/friend56.C b/gcc/testsuite/g++.dg/template/friend56.C
--- a/gcc/testsuite/g++.dg/template/friend56.C	1970-01-01 01:00:00.000000000 +0100
+++ b/gcc/testsuite/g++.dg/template/friend56.C	2014-09-07 14:01:14.518086103 +0200
@@ -0,0 +1,13 @@
+// Make sure we don't mistakenly mark f as DECL_COMDAT.
+// { dg-final { scan-assembler "_Z1fv" } }
+
+void f();
+
+template <class T> struct A
+{
+  friend void f();
+};
+
+A<int> a;
+
+void f() { }
diff -Naur a/gcc/testsuite/g++.dg/template/spec38.C b/gcc/testsuite/g++.dg/template/spec38.C
--- a/gcc/testsuite/g++.dg/template/spec38.C	1970-01-01 01:00:00.000000000 +0100
+++ b/gcc/testsuite/g++.dg/template/spec38.C	2014-09-07 14:03:27.256329888 +0200
@@ -0,0 +1,6 @@
+// PR ipa/61659
+
+// { dg-final { scan-assembler "_Z1fIiEvPT_" } }
+
+template <typename T> inline void f (T *);
+template <> void f (int *) { }
