Index: include/clang/AST/DeclTemplate.h =================================================================== --- include/clang/AST/DeclTemplate.h +++ include/clang/AST/DeclTemplate.h @@ -908,6 +908,8 @@ return getTemplatedDecl()->isThisDeclarationADefinition(); } + FunctionTemplateDecl *getDefinition() const; + /// \brief Return the specialization with the provided arguments if it exists, /// otherwise return the insertion point. FunctionDecl *findSpecialization(ArrayRef Args, Index: lib/AST/DeclTemplate.cpp =================================================================== --- lib/AST/DeclTemplate.cpp +++ lib/AST/DeclTemplate.cpp @@ -289,6 +289,34 @@ } } +/// \brief Returns definition for this function template of null if no +/// definition found. +/// +/// This function scans not only redeclarations but also templates from which +/// these declarations are instantiated, if the function template was +/// instantiated from another template. +/// +FunctionTemplateDecl *FunctionTemplateDecl::getDefinition() const { + for (auto *R : redecls()) { + FunctionTemplateDecl *F = cast(R); + if (F->isThisDeclarationADefinition()) + return F; + + // If template does not have a body, probably it is instantiated from + // another template, which is not used yet. + if (FunctionTemplateDecl *P = F->getInstantiatedFromMemberTemplate()) { + // If we have hit a point where the user provided a specialization of + // this template, we're done looking. + if (F->isMemberSpecialization()) + return F; + if (FunctionTemplateDecl *Def = P->getDefinition()) + return Def; + } + } + + return nullptr; +} + llvm::FoldingSetVector & FunctionTemplateDecl::getSpecializations() const { LoadLazySpecializations(); Index: lib/Sema/SemaDecl.cpp =================================================================== --- lib/Sema/SemaDecl.cpp +++ lib/Sema/SemaDecl.cpp @@ -8807,10 +8807,23 @@ if (FunctionTemplateDecl *OldTemplateDecl = dyn_cast(OldDecl)) { - NewFD->setPreviousDeclaration(OldTemplateDecl->getTemplatedDecl()); FunctionTemplateDecl *NewTemplateDecl = NewFD->getDescribedFunctionTemplate(); assert(NewTemplateDecl && "Template/non-template mismatch"); + Redeclaration = shouldLinkDependentDeclWithPrevious(NewTemplateDecl, + OldTemplateDecl); + if (Redeclaration && + (NewTemplateDecl->getFriendObjectKind() != Decl::FOK_None || + OldTemplateDecl->getFriendObjectKind() != Decl::FOK_None)) + if (FunctionTemplateDecl *NewDef = NewTemplateDecl->getDefinition()) + if (FunctionTemplateDecl *OldDef = OldTemplateDecl->getDefinition()) { + Diag(NewDef->getLocation(), diag::err_redefinition) + << NewDef->getDeclName(); + Diag(OldDef->getLocation(), diag::note_previous_definition); + Redeclaration = false; + } + if (Redeclaration) + NewFD->setPreviousDeclaration(OldTemplateDecl->getTemplatedDecl()); if (CXXMethodDecl *Method = dyn_cast(NewTemplateDecl->getTemplatedDecl())) { Method->setAccess(OldTemplateDecl->getAccess()); Index: test/SemaCXX/friend2.cpp =================================================================== --- test/SemaCXX/friend2.cpp +++ test/SemaCXX/friend2.cpp @@ -91,6 +91,73 @@ friend int func10(int); // expected-error{{functions that differ only in their return type cannot be overloaded}} }; +// Case of template friend functions. + +template void func_11(T *x); +template +struct C11a { + template friend void func_11(T *x) {} +}; +template +struct C11b { + template friend void func_11(T *x) {} +}; + + +template inline void func_12(T *x) {} +template +struct C12a { + template friend void func_12(T *x) {} +}; +template +struct C12b { + template friend void func_12(T *x) {} +}; + + +template +struct C13a { + template friend void func_13(T *x) {} +}; +template +struct C13b { + template friend void func_13(T *x) {} +}; + + +template inline void func_14(T *x) {} // expected-note{{previous definition is here}} +template +struct C14 { + template friend void func_14(T *x) {} // expected-error{{redefinition of 'func_14'}} +}; + +C14 v14; // expected-note{{in instantiation of template class 'C14' requested here}} + + +template inline void func_15(T *x); +template +struct C15a { + template friend void func_15(T *x) {} // expected-note{{previous definition is here}} +}; +template +struct C15b { + template friend void func_15(T *x) {} // expected-error{{redefinition of 'func_15'}} +}; + +C15a v15a; +C15b v15b; // expected-note{{in instantiation of template class 'C15b' requested here}} + + +template void func_16(T *x); +template +struct C16 { + template friend void func_16(T *x) {} // expected-error{{redefinition of 'func_16'}} + // expected-note@-1{{previous definition is here}} +}; + +C16 v16a; +C16 v16b; //expected-note{{in instantiation of template class 'C16' requested here}} + namespace pr22307 {