sepavloff updated this revision to Diff 74218. sepavloff added a comment. Updated comments, NFC otherwise.
https://reviews.llvm.org/D21508 Files: include/clang/AST/DeclTemplate.h lib/AST/DeclTemplate.cpp lib/Sema/SemaDecl.cpp test/SemaCXX/friend2.cpp
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<int>; } + +// Case of template friend functions. + +template<typename T> void func_21(T *x); +template<typename T1> +struct C21a { + template<typename T> friend void func_21(T *x) {} +}; +template<typename T1> +struct C21b { + template<typename T> friend void func_21(T *x) {} +}; + + +template<typename T> inline void func_22(T *x) {} +template<typename T1> +struct C22a { + template<typename T> friend void func_22(T *x) {} +}; +template<typename T1> +struct C22b { + template<typename T> friend void func_22(T *x) {} +}; + + +template<typename T1> +struct C23a { + template<typename T> friend void func_23(T *x) {} +}; +template<typename T1> +struct C23b { + template<typename T> friend void func_23(T *x) {} +}; + + +template<typename T> inline void func_24(T *x) {} // expected-note{{previous definition is here}} +template<typename T1> +struct C24 { + template<typename T> friend void func_24(T *x) {} // expected-error{{redefinition of 'func_24'}} +}; + +C24<int> v24; // expected-note{{in instantiation of template class 'C24<int>' requested here}} + + +template<typename T> inline void func_25(T *x); +template<typename T1> +struct C25a { + template<typename T> friend void func_25(T *x) {} // expected-note{{previous definition is here}} +}; +template<typename T1> +struct C25b { + template<typename T> friend void func_25(T *x) {} // expected-error{{redefinition of 'func_25'}} +}; + +C25a<int> v25a; +C25b<int> v25b; // expected-note{{in instantiation of template class 'C25b<int>' requested here}} + + +template<typename T> void func_26(T *x); +template<typename T1> +struct C26 { + template<typename T> friend void func_26(T *x) {} // expected-error{{redefinition of 'func_26'}} + // expected-note@-1{{previous definition is here}} +}; + +C26<int> v26a; +C26<long> v26b; //expected-note{{in instantiation of template class 'C26<long>' requested here}} Index: lib/Sema/SemaDecl.cpp =================================================================== --- lib/Sema/SemaDecl.cpp +++ lib/Sema/SemaDecl.cpp @@ -8846,10 +8846,23 @@ if (FunctionTemplateDecl *OldTemplateDecl = dyn_cast<FunctionTemplateDecl>(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<CXXMethodDecl>(NewTemplateDecl->getTemplatedDecl())) { Method->setAccess(OldTemplateDecl->getAccess()); 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<FunctionTemplateDecl>(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<FunctionTemplateSpecializationInfo> & FunctionTemplateDecl::getSpecializations() const { LoadLazySpecializations(); 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<TemplateArgument> Args,
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits