Index: include/clang/AST/DeclBase.h =================================================================== --- include/clang/AST/DeclBase.h +++ include/clang/AST/DeclBase.h @@ -1034,11 +1034,11 @@ 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(); @@ -1051,7 +1051,8 @@ 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)) Index: lib/AST/Decl.cpp =================================================================== --- lib/AST/Decl.cpp +++ lib/AST/Decl.cpp @@ -3267,6 +3267,14 @@ if (auto *MFD = getInstantiatedFromMemberFunction()) return getDefinitionOrSelf(MFD); + if (FunctionTemplateDecl *TD = getDescribedFunctionTemplate()) { + if (TD->getFriendObjectKind() != FOK_None) { + while (FunctionTemplateDecl *FT = TD->getInstantiatedFromMemberTemplate()) + TD = FT; + return TD->getTemplatedDecl(); + } + } + return nullptr; } Index: lib/Sema/SemaDecl.cpp =================================================================== --- lib/Sema/SemaDecl.cpp +++ lib/Sema/SemaDecl.cpp @@ -12004,6 +12004,29 @@ } } } + + 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() && + "Underlying function declaration must be a definition"); + if (D->getFriendObjectKind() != Decl::FOK_None) + if (FunctionTemplateDecl *FT = + D->getInstantiatedFromMemberTemplate()) { + if (FT->isThisDeclarationADefinition()) { + Definition = D->getTemplatedDecl(); + break; + } + } + } + } + } + if (!Definition) return; Index: lib/Sema/SemaTemplateInstantiateDecl.cpp =================================================================== --- lib/Sema/SemaTemplateInstantiateDecl.cpp +++ lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -1795,7 +1795,9 @@ // 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 (FunctionTemplate) + FunctionTemplate->setObjectOfFriendDecl(); DC->makeDeclVisibleInContext(PrincipalDecl); bool QueuedInstantiation = false; Index: test/SemaCXX/friend2.cpp =================================================================== --- test/SemaCXX/friend2.cpp +++ test/SemaCXX/friend2.cpp @@ -129,6 +129,83 @@ 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 {