From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 2122) id 44F2538CA68A; Wed, 8 Jun 2022 21:31:44 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 44F2538CA68A MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Type: text/plain; charset="utf-8" From: Jason Merrill To: gcc-cvs@gcc.gnu.org Subject: [gcc r11-10055] c++: redeclared hidden friend take 2 [PR105852] X-Act-Checkin: gcc X-Git-Author: Jason Merrill X-Git-Refname: refs/heads/releases/gcc-11 X-Git-Oldrev: ee9cd6d6e504cb67b27b1a5e39f965bafd62653b X-Git-Newrev: 3e39a0a4b71dce674ee30fe71590b0152663b6d8 Message-Id: <20220608213144.44F2538CA68A@sourceware.org> Date: Wed, 8 Jun 2022 21:31:44 +0000 (GMT) X-BeenThere: gcc-cvs@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-cvs mailing list List-Unsubscribe: , List-Archive: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 08 Jun 2022 21:31:44 -0000 https://gcc.gnu.org/g:3e39a0a4b71dce674ee30fe71590b0152663b6d8 commit r11-10055-g3e39a0a4b71dce674ee30fe71590b0152663b6d8 Author: Jason Merrill Date: Mon Jun 6 21:49:06 2022 -0400 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.c (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.c (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: --- gcc/cp/cp-tree.h | 1 + gcc/cp/decl.c | 16 ++++++--------- gcc/cp/pt.c | 29 ++++++++++++++++++++++++++- gcc/testsuite/g++.dg/modules/tpl-friend-2_a.C | 2 +- gcc/testsuite/g++.dg/template/friend74.C | 8 ++++++++ 5 files changed, 44 insertions(+), 12 deletions(-) diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index a2d8c1c77b3..fded2527e5e 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -7242,6 +7242,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.c b/gcc/cp/decl.c index df5361d1184..679ea9c8be7 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -2224,8 +2224,8 @@ duplicate_decls (tree newdecl, tree olddecl, bool hiding, bool was_hidden) check_no_redeclaration_friend_default_args (old_result, new_result); } - 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); @@ -2580,13 +2580,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) @@ -2594,8 +2588,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.c b/gcc/cp/pt.c index ec8bf229740..588c46504b4 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -11137,6 +11137,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. @@ -14079,7 +14106,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 3acacf8ee34..c12857fbf69 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 00000000000..51708334d81 --- /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(); }