diff --git a/clang/include/clang/AST/DeclBase.h b/clang/include/clang/AST/DeclBase.h index 9c245f4e7034..8405a43fa098 100644 --- a/clang/include/clang/AST/DeclBase.h +++ b/clang/include/clang/AST/DeclBase.h @@ -1065,11 +1065,11 @@ public: unsigned OldNS = IdentifierNamespace; assert((OldNS & (IDNS_Tag | IDNS_Ordinary | IDNS_TagFriend | IDNS_OrdinaryFriend | - IDNS_LocalExtern)) && + IDNS_LocalExtern | IDNS_NonMemberOperator)) && "namespace includes neither ordinary nor tag"); assert(!(OldNS & ~(IDNS_Tag | IDNS_Ordinary | IDNS_Type | IDNS_TagFriend | IDNS_OrdinaryFriend | - IDNS_LocalExtern)) && + IDNS_LocalExtern | IDNS_NonMemberOperator)) && "namespace includes other than ordinary or tag"); Decl *Prev = getPreviousDecl(); @@ -1082,7 +1082,8 @@ public: IdentifierNamespace |= IDNS_Tag | IDNS_Type; } - if (OldNS & (IDNS_Ordinary | IDNS_OrdinaryFriend | IDNS_LocalExtern)) { + if (OldNS & (IDNS_Ordinary | IDNS_OrdinaryFriend | + IDNS_LocalExtern | IDNS_NonMemberOperator)) { IdentifierNamespace |= IDNS_OrdinaryFriend; if (PerformFriendInjection || (Prev && Prev->getIdentifierNamespace() & IDNS_Ordinary)) diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 083089fc9947..a4545f2ff633 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -12737,6 +12737,29 @@ Sema::CheckForFunctionRedefinition(FunctionDecl *FD, } } } + + if (!Definition) + // Similar to friend functions a friend function template may be a + // definition and do not have a body if it is instantiated in a class + // template. + if (FunctionTemplateDecl *FTD = FD->getDescribedFunctionTemplate()) { + for (auto I : FTD->redecls()) { + auto D = cast(I); + if (D != FTD) { + assert(!D->isThisDeclarationADefinition() && + "More than one definition in redeclaration chain"); + if (D->getFriendObjectKind() != Decl::FOK_None) + if (FunctionTemplateDecl *FT = + D->getInstantiatedFromMemberTemplate()) { + if (FT->isThisDeclarationADefinition()) { + Definition = D->getTemplatedDecl(); + break; + } + } + } + } + } + if (!Definition) return; diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index f880d4616a89..8f9af03a0469 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -1817,7 +1817,9 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, // If the original function was part of a friend declaration, // inherit its namespace state and add it to the owner. if (isFriend) { - PrincipalDecl->setObjectOfFriendDecl(); + Function->setObjectOfFriendDecl(); + if (FunctionTemplateDecl *FT = Function->getDescribedFunctionTemplate()) + FT->setObjectOfFriendDecl(); DC->makeDeclVisibleInContext(PrincipalDecl); bool QueuedInstantiation = false; diff --git a/clang/test/Modules/friend-definition.cpp b/clang/test/Modules/friend-definition.cpp index 8588cbd9c6f4..32329d0e3e1c 100644 --- a/clang/test/Modules/friend-definition.cpp +++ b/clang/test/Modules/friend-definition.cpp @@ -7,6 +7,7 @@ module A {} #pragma clang module begin A template struct A { friend A operator+(const A&, const A&) { return {}; } + template friend void func_1(const A&, const T2 &) {} }; #pragma clang module end #pragma clang module endbuild @@ -36,4 +37,5 @@ inline void g() { A a; } void h() { A a; a + a; + func_1(a, 0); } diff --git a/clang/test/SemaCXX/friend-template-redecl.cpp b/clang/test/SemaCXX/friend-template-redecl.cpp index 2e4068cffaff..3e05964fb288 100644 --- a/clang/test/SemaCXX/friend-template-redecl.cpp +++ b/clang/test/SemaCXX/friend-template-redecl.cpp @@ -18,16 +18,3 @@ void f() { foo(x); bar(x); } - -namespace PR39742 { -template -struct wrapper { - template - friend void friend_function_template() {} -}; - -wrapper x; -// FIXME: We should really error here because of the redefinition of -// friend_function_template. -wrapper y; -} diff --git a/clang/test/SemaCXX/friend2.cpp b/clang/test/SemaCXX/friend2.cpp index 8eacdeb19c62..6d3b545904e4 100644 --- a/clang/test/SemaCXX/friend2.cpp +++ b/clang/test/SemaCXX/friend2.cpp @@ -129,6 +129,83 @@ C22b c22bi; void func_22() {} // expected-error{{redefinition of 'func_22'}} +// Case of template friend functions. + +template void func_31(T *x); +template +struct C31a { + template friend void func_31(T *x) {} +}; +template +struct C31b { + template friend void func_31(T *x) {} +}; + + +template inline void func_32(T *x) {} +template +struct C32a { + template friend void func_32(T *x) {} +}; +template +struct C32b { + template friend void func_32(T *x) {} +}; + + +template +struct C33a { + template friend void func_33(T *x) {} +}; +template +struct C33b { + template friend void func_33(T *x) {} +}; + + +template inline void func_34(T *x) {} // expected-note{{previous definition is here}} +template +struct C34 { + template friend void func_34(T *x) {} // expected-error{{redefinition of 'func_34'}} +}; + +C34 v34; // expected-note{{in instantiation of template class 'C34' requested here}} + + +template inline void func_35(T *x); +template +struct C35a { + template friend void func_35(T *x) {} // expected-note{{previous definition is here}} +}; +template +struct C35b { + template friend void func_35(T *x) {} // expected-error{{redefinition of 'func_35'}} +}; + +C35a v35a; +C35b v35b; // expected-note{{in instantiation of template class 'C35b' requested here}} + + +template void func_36(T *x); +template +struct C36 { + template friend void func_36(T *x) {} // expected-error{{redefinition of 'func_36'}} + // expected-note@-1{{previous definition is here}} +}; + +C36 v36a; +C36 v36b; //expected-note{{in instantiation of template class 'C36' requested here}} + + +template void func_37(T *x); +template +struct C37 { + template friend void func_37(T *x) {} // expected-note{{previous definition is here}} +}; + +C37 v37; +template void func_37(T *x) {} // expected-error{{redefinition of 'func_37'}} + namespace pr22307 { @@ -235,3 +312,15 @@ void func() { cache.insert(); } } + +namespace PR39742 { +template +struct wrapper { + template + friend void friend_function_template() {} // expected-error{{redefinition of 'friend_function_template'}} + // expected-note@-1{{previous definition is here}} +}; + +wrapper x; +wrapper y; // expected-note{{in instantiation of template class 'PR39742::wrapper' requested here}} +}