Submitted By: Bruce Dubbs 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 struct A { static int i; }; +template<> int A::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 struct parser : public generic_parser_base { + virtual void getOption() {} +}; +struct PassNameParser : public parser { + 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 struct A +{ + friend void f(); +}; + +A 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 inline void f (T *); +template <> void f (int *) { }