From d5d0ed2d89a56273efe30331c3e94651134615e7 Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Wed, 30 Jul 2014 13:27:14 -0400 Subject: [PATCH] re PR lto/53808 (Undefined symbol when building a library with lto) 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 | 14 ++++++++++++++ gcc/cp/decl.c | 11 ++++++++++- gcc/cp/decl2.c | 18 +++++++----------- gcc/cp/method.c | 5 +++-- gcc/cp/pt.c | 10 ++++++++++ gcc/cp/tree.c | 14 +++----------- gcc/testsuite/g++.dg/opt/devirt4.C | 7 +++---- 7 files changed, 50 insertions(+), 29 deletions(-) diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index cfe0a48..3d8bf6d 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,17 @@ +2014-07-30 Jason Merrill + + 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 diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index aafb917..fd5e2e5 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -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; diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c index 8fa3145..884be0a 100644 --- a/gcc/cp/decl2.c +++ b/gcc/cp/decl2.c @@ -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; diff --git a/gcc/cp/method.c b/gcc/cp/method.c index e5fa0c1..f86a214 100644 --- a/gcc/cp/method.c +++ b/gcc/cp/method.c @@ -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. */ diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index b32cf6c..0eac771 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -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); } diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c index f6c5693..1bfffb8 100644 --- a/gcc/cp/tree.c +++ b/gcc/cp/tree.c @@ -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)) diff --git a/gcc/testsuite/g++.dg/opt/devirt4.C b/gcc/testsuite/g++.dg/opt/devirt4.C index 5a24eec..72f56af 100644 --- a/gcc/testsuite/g++.dg/opt/devirt4.C +++ b/gcc/testsuite/g++.dg/opt/devirt4.C @@ -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(); -- 2.7.4