re PR lto/53808 (Undefined symbol when building a library with lto)
authorJason Merrill <jason@redhat.com>
Wed, 30 Jul 2014 17:27:14 +0000 (13:27 -0400)
committerJason Merrill <jason@gcc.gnu.org>
Wed, 30 Jul 2014 17:27:14 +0000 (13:27 -0400)
PR lto/53808
PR c++/61659
* pt.c (push_template_decl_real): Set DECL_COMDAT on templates.
(check_explicit_specialization): Clear it on specializations.
* decl.c (duplicate_decls, start_decl): Likewise.
(grokmethod, grokfndecl): Set DECL_COMDAT on inlines.
* method.c (implicitly_declare_fn): Set DECL_COMDAT.  Determine
linkage after setting the appropriate flags.
* tree.c (decl_linkage): Don't check DECL_COMDAT.
* decl2.c (mark_needed): Mark clones.
(import_export_decl): Not here.

From-SVN: r213307

gcc/cp/ChangeLog
gcc/cp/decl.c
gcc/cp/decl2.c
gcc/cp/method.c
gcc/cp/pt.c
gcc/cp/tree.c
gcc/testsuite/g++.dg/opt/devirt4.C

index cfe0a48..3d8bf6d 100644 (file)
@@ -1,3 +1,17 @@
+2014-07-30  Jason Merrill  <jason@redhat.com>
+
+       PR lto/53808
+       PR c++/61659
+       * pt.c (push_template_decl_real): Set DECL_COMDAT on templates.
+       (check_explicit_specialization): Clear it on specializations.
+       * decl.c (duplicate_decls, start_decl): Likewise.
+       (grokmethod, grokfndecl): Set DECL_COMDAT on inlines.
+       * method.c (implicitly_declare_fn): Set DECL_COMDAT.  Determine
+       linkage after setting the appropriate flags.
+       * tree.c (decl_linkage): Don't check DECL_COMDAT.
+       * decl2.c (mark_needed): Mark clones.
+       (import_export_decl): Not here.
+
 2014-07-25  Edward Smith-Rowland  <3dw4rd@verizon.net>
 
        Implement N4051 - Allow typename in a template template parameter
index aafb917..fd5e2e5 100644 (file)
@@ -2197,6 +2197,7 @@ duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend)
                      olddecl);
 
          SET_DECL_TEMPLATE_SPECIALIZATION (olddecl);
+         DECL_COMDAT (newdecl) = DECL_DECLARED_INLINE_P (olddecl);
 
          /* Don't propagate visibility from the template to the
             specialization here.  We'll do that in determine_visibility if
@@ -4683,6 +4684,10 @@ start_decl (const cp_declarator *declarator,
       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);
+         else
+           DECL_COMDAT (decl) = false;
 
          /* [temp.expl.spec] An explicit specialization of a static data
             member of a template is a definition if the declaration
@@ -7663,7 +7668,10 @@ grokfndecl (tree ctype,
 
   /* 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;
 
@@ -14223,6 +14231,7 @@ grokmethod (cp_decl_specifier_seq *declspecs,
 
   check_template_shadow (fndecl);
 
+  DECL_COMDAT (fndecl) = 1;
   DECL_DECLARED_INLINE_P (fndecl) = 1;
   DECL_NO_INLINE_WARNING_P (fndecl) = 1;
 
index 8fa3145..884be0a 100644 (file)
@@ -1930,6 +1930,12 @@ mark_needed (tree decl)
         definition.  */
       struct cgraph_node *node = cgraph_node::get_create (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)
     {
@@ -2728,17 +2734,7 @@ import_export_decl (tree decl)
     {
       /* 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;
index e5fa0c1..f86a214 100644 (file)
@@ -1798,8 +1798,6 @@ implicitly_declare_fn (special_function_kind kind, tree type,
   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;
@@ -1811,6 +1809,9 @@ implicitly_declare_fn (special_function_kind kind, tree type,
   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.  */
index b32cf6c..0eac771 100644 (file)
@@ -2787,6 +2787,9 @@ check_explicit_specialization (tree declarator,
               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.  */
@@ -5017,6 +5020,13 @@ template arguments to %qD do not match original template %qD",
        DECL_TEMPLATE_INFO (decl) = info;
     }
 
+  if (flag_implicit_templates
+      && VAR_OR_FUNCTION_DECL_P (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);
 }
 
index f6c5693..1bfffb8 100644 (file)
@@ -3722,23 +3722,15 @@ decl_linkage (tree decl)
   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))
index 5a24eec..72f56af 100644 (file)
@@ -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();