sepavloff updated this revision to Diff 61989. sepavloff added a comment. Make more correct template function definition lookup
Lookup is made recursive to cover more cases. http://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 @@ -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<typename T> void func_11(T *x); +template<typename T1> +struct C11a { + template<typename T> friend void func_11(T *x) {} +}; +template<typename T1> +struct C11b { + template<typename T> friend void func_11(T *x) {} +}; + + +template<typename T> inline void func_12(T *x) {} +template<typename T1> +struct C12a { + template<typename T> friend void func_12(T *x) {} +}; +template<typename T1> +struct C12b { + template<typename T> friend void func_12(T *x) {} +}; + + +template<typename T1> +struct C13a { + template<typename T> friend void func_13(T *x) {} +}; +template<typename T1> +struct C13b { + template<typename T> friend void func_13(T *x) {} +}; + + +template<typename T> inline void func_14(T *x) {} // expected-note{{previous definition is here}} +template<typename T1> +struct C14 { + template<typename T> friend void func_14(T *x) {} // expected-error{{redefinition of 'func_14'}} +}; + +C14<int> v14; // expected-note{{in instantiation of template class 'C14<int>' requested here}} + + +template<typename T> inline void func_15(T *x); +template<typename T1> +struct C15a { + template<typename T> friend void func_15(T *x) {} // expected-note{{previous definition is here}} +}; +template<typename T1> +struct C15b { + template<typename T> friend void func_15(T *x) {} // expected-error{{redefinition of 'func_15'}} +}; + +C15a<int> v15a; +C15b<int> v15b; // expected-note{{in instantiation of template class 'C15b<int>' requested here}} + + +template<typename T> void func_16(T *x); +template<typename T1> +struct C16 { + template<typename T> friend void func_16(T *x) {} // expected-error{{redefinition of 'func_16'}} + // expected-note@-1{{previous definition is here}} +}; + +C16<int> v16a; +C16<long> v16b; //expected-note{{in instantiation of template class 'C16<long>' requested here}} + namespace pr22307 { Index: lib/Sema/SemaDecl.cpp =================================================================== --- lib/Sema/SemaDecl.cpp +++ lib/Sema/SemaDecl.cpp @@ -8807,10 +8807,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,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<FunctionTemplateDecl>(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<FunctionTemplateSpecializationInfo> & FunctionTemplateDecl::getSpecializations() const { LoadLazySpecializations(); 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<TemplateArgument> Args,
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits