Since olddecl isn't a definition, it doesn't get DECL_FRIEND_CONTEXT, so we need to copy it from newdecl when we merge the declarations.
Tested x86_64-pc-linux-gnu, applying to trunk. PR c++/101894 gcc/cp/ChangeLog: * decl.cc (duplicate_decls): Copy DECL_FRIEND_CONTEXT. gcc/testsuite/ChangeLog: * g++.dg/lookup/friend22.C: New test. --- gcc/cp/decl.cc | 5 +++++ gcc/testsuite/g++.dg/lookup/friend22.C | 7 +++++++ 2 files changed, 12 insertions(+) create mode 100644 gcc/testsuite/g++.dg/lookup/friend22.C diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc index 69f60a6dc0f..0ff13e99595 100644 --- a/gcc/cp/decl.cc +++ b/gcc/cp/decl.cc @@ -2344,6 +2344,9 @@ duplicate_decls (tree newdecl, tree olddecl, bool hiding, bool was_hidden) for (parm = DECL_ARGUMENTS (old_result); parm; parm = DECL_CHAIN (parm)) DECL_CONTEXT (parm) = old_result; + + if (tree fc = DECL_FRIEND_CONTEXT (new_result)) + SET_DECL_FRIEND_CONTEXT (old_result, fc); } } @@ -2667,6 +2670,8 @@ duplicate_decls (tree newdecl, tree olddecl, bool hiding, bool was_hidden) otherwise it is a DECL_FRIEND_CONTEXT. */ if (DECL_VIRTUAL_P (newdecl)) SET_DECL_THUNKS (newdecl, DECL_THUNKS (olddecl)); + else if (tree fc = DECL_FRIEND_CONTEXT (newdecl)) + SET_DECL_FRIEND_CONTEXT (olddecl, fc); } else if (VAR_P (newdecl)) { diff --git a/gcc/testsuite/g++.dg/lookup/friend22.C b/gcc/testsuite/g++.dg/lookup/friend22.C new file mode 100644 index 00000000000..f52a7d7bad5 --- /dev/null +++ b/gcc/testsuite/g++.dg/lookup/friend22.C @@ -0,0 +1,7 @@ +// PR c++/101894 + +struct A +{ + template<int> friend void foo(); + template<int> friend void foo() {} +}; base-commit: 2f0610acbc056052a108e4a46911fc21d0dca2ab prerequisite-patch-id: 74ea9d22f5f8e4ebddcda6cbb7a371bcb08f0488 -- 2.27.0