From: Jason Merrill Date: Tue, 7 Jun 2022 01:49:06 +0000 (-0400) Subject: c++: redeclared hidden friend take 2 [PR105852] X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=e057d454db4dcf48c22f75e57599f797d8e55baf;p=test_jj.git c++: redeclared hidden friend take 2 [PR105852] My previous patch for 105761 avoided copying DECL_TEMPLATE_INFO from a friend to a later definition, but in this testcase we have first a non-friend declaration and then a definition, and we need to avoid copying in that case as well. But we do still want to set new_template_info to avoid GC trouble. With this change, the modules dump correctly identifies ::foo as a non-template function in tpl-friend-2_a.C. Along the way I noticed that the duplicate_decls handling of DECL_UNIQUE_FRIEND_P was backwards for templates, where we don't clobber DECL_LANG_SPECIFIC (olddecl) with DECL_LANG_SPECIFIC (newdecl) like we do for non-templates. PR c++/105852 PR c++/105761 gcc/cp/ChangeLog: * decl.cc (duplicate_decls): Avoid copying template info from non-templated friend even if newdecl isn't a definition. Correct handling of DECL_UNIQUE_FRIEND_P on templates. * pt.cc (non_templated_friend_p): New. * cp-tree.h (non_templated_friend_p): Declare it. gcc/testsuite/ChangeLog: * g++.dg/modules/tpl-friend-2_a.C: Adjust expected dump. * g++.dg/template/friend74.C: New test. --- diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index b540c23..97610e3 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -7414,6 +7414,7 @@ extern bool push_tinst_level_loc (tree, location_t); extern bool push_tinst_level_loc (tree, tree, location_t); extern void pop_tinst_level (void); extern struct tinst_level *outermost_tinst_level(void); +extern bool non_templated_friend_p (tree); extern void init_template_processing (void); extern void print_template_statistics (void); bool template_template_parameter_p (const_tree); diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc index f53136c..66d62af 100644 --- a/gcc/cp/decl.cc +++ b/gcc/cp/decl.cc @@ -2295,8 +2295,8 @@ duplicate_decls (tree newdecl, tree olddecl, bool hiding, bool was_hidden) merge_default_template_args (new_parms, old_parms, /*class_p=*/false); } - if (!DECL_UNIQUE_FRIEND_P (old_result)) - DECL_UNIQUE_FRIEND_P (new_result) = false; + if (!DECL_UNIQUE_FRIEND_P (new_result)) + DECL_UNIQUE_FRIEND_P (old_result) = false; check_default_args (newdecl); @@ -2655,13 +2655,7 @@ duplicate_decls (tree newdecl, tree olddecl, bool hiding, bool was_hidden) if (LANG_DECL_HAS_MIN (newdecl)) { DECL_ACCESS (newdecl) = DECL_ACCESS (olddecl); - if (new_defines_function - && DECL_TEMPLATE_INFO (olddecl) - && DECL_UNIQUE_FRIEND_P (DECL_TEMPLATE_RESULT - (DECL_TI_TEMPLATE (olddecl)))) - /* Don't copy template info from a non-template friend declaration - in a class template (PR105761). */; - else if (DECL_TEMPLATE_INFO (newdecl)) + if (DECL_TEMPLATE_INFO (newdecl)) { new_template_info = DECL_TEMPLATE_INFO (newdecl); if (DECL_TEMPLATE_INSTANTIATION (olddecl) @@ -2669,8 +2663,10 @@ duplicate_decls (tree newdecl, tree olddecl, bool hiding, bool was_hidden) /* Remember the presence of explicit specialization args. */ TINFO_USED_TEMPLATE_ID (DECL_TEMPLATE_INFO (olddecl)) = TINFO_USED_TEMPLATE_ID (new_template_info); - DECL_TEMPLATE_INFO (newdecl) = DECL_TEMPLATE_INFO (olddecl); } + + if (non_templated_friend_p (olddecl)) + /* Don't copy tinfo from a non-templated friend (PR105761). */; else DECL_TEMPLATE_INFO (newdecl) = DECL_TEMPLATE_INFO (olddecl); } diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index e036f01..214ad84 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -11172,6 +11172,33 @@ outermost_tinst_level (void) return level; } +/* True iff T is a friend function declaration that is not itself a template + and is not defined in a class template. */ + +bool +non_templated_friend_p (tree t) +{ + if (t && TREE_CODE (t) == FUNCTION_DECL + && DECL_UNIQUE_FRIEND_P (t)) + { + tree ti = DECL_TEMPLATE_INFO (t); + if (!ti) + return true; + /* DECL_FRIEND_CONTEXT is set for a friend defined in class. */ + if (DECL_FRIEND_CONTEXT (t)) + return false; + /* Non-templated friends in a class template are still represented with a + TEMPLATE_DECL; check that its primary template is the befriending + class. Note that DECL_PRIMARY_TEMPLATE is null for + template friend A::f(); */ + tree tmpl = TI_TEMPLATE (ti); + tree primary = DECL_PRIMARY_TEMPLATE (tmpl); + return (primary && primary != tmpl); + } + else + return false; +} + /* DECL is a friend FUNCTION_DECL or TEMPLATE_DECL. ARGS is the vector of template arguments, as for tsubst. @@ -14096,7 +14123,7 @@ tsubst_function_decl (tree t, tree args, tsubst_flags_t complain, /* This special case arises when we have something like this: template struct S { - friend void f(int, double); + friend void f(int, double); }; Here, the DECL_TI_TEMPLATE for the friend declaration diff --git a/gcc/testsuite/g++.dg/modules/tpl-friend-2_a.C b/gcc/testsuite/g++.dg/modules/tpl-friend-2_a.C index 3acacf8..c12857f 100644 --- a/gcc/testsuite/g++.dg/modules/tpl-friend-2_a.C +++ b/gcc/testsuite/g++.dg/modules/tpl-friend-2_a.C @@ -16,5 +16,5 @@ template class TPL; // instantiate void foo (int, void *); // { dg-final { scan-lang-dump {Cluster members:\n \[0\]=decl definition '::template TPL'\n( \[.\]=[^\n]*'\n)* \[.\]=decl declaration '::template foo'\n( \[.\]=[^\n]*'\n)* \[.\]=binding '::TPL'} module } } -// { dg-final { scan-lang-dump {Cluster members:\n \[0\]=decl declaration '::foo'\n \[.\]=binding '::foo'} module } } +// { dg-final { scan-lang-dump {Cluster members:\n \[0\]=decl declaration '::foo'\n \[.\]=binding '::foo'} module } } // { dg-final { scan-lang-dump {Cluster members:\n \[0\]=specialization definition '::TPL'} module } } diff --git a/gcc/testsuite/g++.dg/template/friend74.C b/gcc/testsuite/g++.dg/template/friend74.C new file mode 100644 index 0000000..5170833 --- /dev/null +++ b/gcc/testsuite/g++.dg/template/friend74.C @@ -0,0 +1,8 @@ +// PR c++/105852 +// { dg-additional-options -w } + +template struct Local { friend Local False(int *); }; +Local loc; +Local False(int *); +void New() { False; } +Local False(int *) { return Local(); }