Index: include/clang/AST/DeclTemplate.h =================================================================== --- include/clang/AST/DeclTemplate.h +++ include/clang/AST/DeclTemplate.h @@ -933,6 +933,15 @@ return getTemplatedDecl()->isThisDeclarationADefinition(); } + /// \brief Returns definition for this function template of null if no + /// definition was found. + /// + /// To properly handle function templates defined in friend declarations, the + /// function scans redeclaration chain and for each declaration from there + /// tries to find definition in the chains formed by InstantiatedFromMember. + /// + 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,27 @@ } } +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 and 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 @@ -8846,10 +8846,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 @@ -101,7 +101,6 @@ friend void func_12(int x = 0); // expected-error{{friend declaration specifying a default argument must be the only declaration}} }; - namespace pr22307 { struct t { @@ -170,3 +169,70 @@ template class Test; } + +// Case of template friend functions. + +template void func_21(T *x); +template +struct C21a { + template friend void func_21(T *x) {} +}; +template +struct C21b { + template friend void func_21(T *x) {} +}; + + +template inline void func_22(T *x) {} +template +struct C22a { + template friend void func_22(T *x) {} +}; +template +struct C22b { + template friend void func_22(T *x) {} +}; + + +template +struct C23a { + template friend void func_23(T *x) {} +}; +template +struct C23b { + template friend void func_23(T *x) {} +}; + + +template inline void func_24(T *x) {} // expected-note{{previous definition is here}} +template +struct C24 { + template friend void func_24(T *x) {} // expected-error{{redefinition of 'func_24'}} +}; + +C24 v24; // expected-note{{in instantiation of template class 'C24' requested here}} + + +template inline void func_25(T *x); +template +struct C25a { + template friend void func_25(T *x) {} // expected-note{{previous definition is here}} +}; +template +struct C25b { + template friend void func_25(T *x) {} // expected-error{{redefinition of 'func_25'}} +}; + +C25a v25a; +C25b v25b; // expected-note{{in instantiation of template class 'C25b' requested here}} + + +template void func_26(T *x); +template +struct C26 { + template friend void func_26(T *x) {} // expected-error{{redefinition of 'func_26'}} + // expected-note@-1{{previous definition is here}} +}; + +C26 v26a; +C26 v26b; //expected-note{{in instantiation of template class 'C26' requested here}}