[PATCH] D21508: Diagnose friend function template redefinitions
This revision was automatically updated to reflect the committed changes. Closed by commit rL348473: Diagnose friend function template redefinitions. (authored by sepavloff, committed by ). Herald added a subscriber: llvm-commits. Changed prior to commit: https://reviews.llvm.org/D21508?vs=176763&id=176938#toc Repository: rL LLVM CHANGES SINCE LAST ACTION https://reviews.llvm.org/D21508/new/ https://reviews.llvm.org/D21508 Files: cfe/trunk/include/clang/AST/DeclBase.h cfe/trunk/lib/Sema/SemaDecl.cpp cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp cfe/trunk/test/Modules/friend-definition.cpp cfe/trunk/test/SemaCXX/friend-template-redecl.cpp cfe/trunk/test/SemaCXX/friend2.cpp Index: cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp === --- cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -1817,7 +1817,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 (FunctionTemplateDecl *FT = Function->getDescribedFunctionTemplate()) + FT->setObjectOfFriendDecl(); DC->makeDeclVisibleInContext(PrincipalDecl); bool QueuedInstantiation = false; Index: cfe/trunk/lib/Sema/SemaDecl.cpp === --- cfe/trunk/lib/Sema/SemaDecl.cpp +++ cfe/trunk/lib/Sema/SemaDecl.cpp @@ -12737,6 +12737,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() && + "More than one definition in redeclaration chain"); + if (D->getFriendObjectKind() != Decl::FOK_None) +if (FunctionTemplateDecl *FT = + D->getInstantiatedFromMemberTemplate()) { + if (FT->isThisDeclarationADefinition()) { +Definition = D->getTemplatedDecl(); +break; + } +} +} + } +} + if (!Definition) return; Index: cfe/trunk/include/clang/AST/DeclBase.h === --- cfe/trunk/include/clang/AST/DeclBase.h +++ cfe/trunk/include/clang/AST/DeclBase.h @@ -1065,11 +1065,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(); @@ -1082,7 +1082,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: cfe/trunk/test/SemaCXX/friend-template-redecl.cpp === --- cfe/trunk/test/SemaCXX/friend-template-redecl.cpp +++ cfe/trunk/test/SemaCXX/friend-template-redecl.cpp @@ -18,16 +18,3 @@ foo(x); bar(x); } - -namespace PR39742 { -template -struct wrapper { - template - friend void friend_function_template() {} -}; - -wrapper x; -// FIXME: We should really error here because of the redefinition of -// friend_function_template. -wrapper y; -} Index: cfe/trunk/test/SemaCXX/friend2.cpp === --- cfe/trunk/test/SemaCXX/friend2.cpp +++ cfe/trunk/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 {
[PATCH] D21508: Diagnose friend function template redefinitions
rsmith accepted this revision. rsmith marked an inline comment as done. rsmith added a comment. This revision is now accepted and ready to land. Thanks (and sorry for dropping the ball on this review). Repository: rC Clang CHANGES SINCE LAST ACTION https://reviews.llvm.org/D21508/new/ https://reviews.llvm.org/D21508 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D21508: Diagnose friend function template redefinitions
sepavloff updated this revision to Diff 176763. sepavloff added a comment. Updated patch The fix for https://bugs.llvm.org/show_bug.cgi?id=39742 put a test case, which is not a valid code. The error is detected with this patch, tests are updated accordingly. Repository: rC Clang CHANGES SINCE LAST ACTION https://reviews.llvm.org/D21508/new/ https://reviews.llvm.org/D21508 Files: include/clang/AST/DeclBase.h lib/Sema/SemaDecl.cpp lib/Sema/SemaTemplateInstantiateDecl.cpp test/Modules/friend-definition.cpp test/SemaCXX/friend-template-redecl.cpp test/SemaCXX/friend2.cpp 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 { @@ -235,3 +312,15 @@ cache.insert(); } } + +namespace PR39742 { +template +struct wrapper { + template + friend void friend_function_template() {} // expected-error{{redefinition of 'friend_function_template'}} + // expected-note@-1{{previous definition is here}} +}; + +wrapper x; +wrapper y; // expected-note{{in instantiation of template class 'PR39742::wrapper' requested here}} +} Index: test/SemaCXX/friend-template-redecl.cpp === --- test/SemaCXX/friend-template-redecl.cpp +++ test/SemaCXX/friend-template-redecl.cpp @@ -18,14 +18,3 @@ foo(x); bar(x); } - -namespace PR39742 { -template -struct wrapper { - template - friend void friend_function_template() {} -}; - -wrapper x; -wrapper y; -} Index: test/Modules/friend-definition.cpp === --- test/Modules/friend-definition.cpp +++ test/Modules/friend-definition.cpp @@ -7,6 +7,7 @@ #pragma clang module begin A template struct A { friend A operator+(const A&, const A&) { return {}; } + template friend void func_1(const A&, const T2 &) {} }; #pragma clang module end #pragma clang module endbuild @@ -36,4 +37,5 @@ void h() { A a; a + a; + func_1(a, 0); } Index: lib/Sema/SemaTemplateInstantiateDecl.cpp === --- lib/Sema/SemaTemplateInstantiateDecl.cpp +++ lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -1817,7 +1817,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 (FunctionTemplateDecl *FT = Function->getDescribedFunctionTemplate()) + FT->setObjectOfFriendDecl(); DC->makeDeclVisibleInContext(PrincipalDecl); bool QueuedInstantiation = false; Index: lib/Sema/SemaDecl.cpp === --- lib/Sema/SemaDecl.cpp +++ lib/Sema/SemaDecl.cpp @@ -12744,6 +12744,29 @@ } } } + + if (!Definition) +// Similar to friend functions a friend function template may be a +// definition and do not have a b
[PATCH] D21508: Diagnose friend function template redefinitions
sepavloff updated this revision to Diff 160298. sepavloff added a comment. Rebased the patch Repository: rC Clang https://reviews.llvm.org/D21508 Files: include/clang/AST/DeclBase.h lib/Sema/SemaDecl.cpp lib/Sema/SemaTemplateInstantiateDecl.cpp test/Modules/friend-definition.cpp test/SemaCXX/friend2.cpp 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 { Index: test/Modules/friend-definition.cpp === --- test/Modules/friend-definition.cpp +++ test/Modules/friend-definition.cpp @@ -7,6 +7,7 @@ #pragma clang module begin A template struct A { friend A operator+(const A&, const A&) { return {}; } + template friend void func_1(const A&, const T2 &) {} }; #pragma clang module end #pragma clang module endbuild @@ -36,4 +37,5 @@ void h() { A a; a + a; + func_1(a, 0); } Index: lib/Sema/SemaTemplateInstantiateDecl.cpp === --- lib/Sema/SemaTemplateInstantiateDecl.cpp +++ lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -1793,7 +1793,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 (FunctionTemplateDecl *FT = Function->getDescribedFunctionTemplate()) + FT->setObjectOfFriendDecl(); DC->makeDeclVisibleInContext(PrincipalDecl); bool QueuedInstantiation = false; Index: lib/Sema/SemaDecl.cpp === --- lib/Sema/SemaDecl.cpp +++ lib/Sema/SemaDecl.cpp @@ -12654,6 +12654,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() && + "More than one definition in redeclaration chain"); + if (D->getFriendObjectKind() != Decl::FOK_None) +if (FunctionTemplateDecl *FT = + D->getInstantiatedFromMemberTemplate()) { + if (FT->isThisDeclarationADefinition()) { +Definition = D->getTemplatedDecl(); +break; + } +} +} + } +} + if (!Definition) return; Index: include/clang/AST/DeclBase.h === --- include/clang/AST/DeclBase.h +++ include/clang/AST/DeclBase.h @@ -1078,11 +1078,11 @@ unsigned OldNS = IdentifierNamespace; assert((OldNS & (IDNS_Tag | IDNS_Ordinary | IDNS_TagFriend | IDNS_OrdinaryFr
[PATCH] D21508: Diagnose friend function template redefinitions
sepavloff added a comment. Other compilers successfully recognize errors (checked using https://godbolt.org/). For instance, the code: template inline void func_35(T *x); template struct C35a { template friend void func_35(T *x) {} }; template struct C35b { template friend void func_35(T *x) {} }; C35a v35a; C35b v35b; is rejected by MSVC 19: example.cpp (7): error C2995: 'void func_37(T *)': function template has already been defined (1): note: see declaration of 'func_37' Microsoft (R) C/C++ Optimizing Compiler Version 19.10.25017 for x64 Copyright (C) Microsoft Corporation. All rights reserved. Compiler returned: 2 by gcc 7.3: :7:27: error: redefinition of 'template void func_37(T*)' template void func_37(T *x) {} ^~~ :1:27: note: 'template void func_37(T*)' previously declared here template void func_37(T *x); ^~~ Compiler returned: 1 and icc 18: (7): error: function template "func_37" has already been defined template void func_37(T *x) {} ^ compilation aborted for (code 2) Compiler returned: 2 Repository: rC Clang https://reviews.llvm.org/D21508 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D21508: Diagnose friend function template redefinitions
sepavloff updated this revision to Diff 138303. sepavloff added a comment. Updated patch - Rebased relative to recent ToT - Removed the change in `FunctionDecl::getTemplateInstantiationPattern()`, as it is not necessary for error detection, - Added test for use in module. Repository: rC Clang https://reviews.llvm.org/D21508 Files: include/clang/AST/DeclBase.h lib/Sema/SemaDecl.cpp lib/Sema/SemaTemplateInstantiateDecl.cpp test/Modules/friend-definition.cpp test/SemaCXX/friend2.cpp 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 { Index: test/Modules/friend-definition.cpp === --- test/Modules/friend-definition.cpp +++ test/Modules/friend-definition.cpp @@ -7,6 +7,7 @@ #pragma clang module begin A template struct A { friend A operator+(const A&, const A&) { return {}; } + template friend void func_1(const A&, const T2 &) {} }; #pragma clang module end #pragma clang module endbuild @@ -36,4 +37,5 @@ void h() { A a; a + a; + func_1(a, 0); } 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 (FunctionTemplateDecl *FT = Function->getDescribedFunctionTemplate()) + FT->setObjectOfFriendDecl(); DC->makeDeclVisibleInContext(PrincipalDecl); bool QueuedInstantiation = false; Index: lib/Sema/SemaDecl.cpp === --- lib/Sema/SemaDecl.cpp +++ lib/Sema/SemaDecl.cpp @@ -12321,6 +12321,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() && + "More than one definition in redeclaration chain"); + if (D->getFriendObjectKind() != Decl::FOK_None) +if (FunctionTemplateDecl *FT = + D->getInstantiatedFromMemberTemplate()) { + if (FT->isThisDeclarationADefinition()) { +Definition = D->getTemplatedDecl(); +break; + } +} +} + } +} + if (!Definition) return; Index: include/clang/AST/DeclBase.h === --- include/clang/AST/DeclBase.h +++ include/clang/AST
[PATCH] D21508: Diagnose friend function template redefinitions
sepavloff updated this revision to Diff 115539. sepavloff added a comment. Rebased https://reviews.llvm.org/D21508 Files: include/clang/AST/DeclBase.h lib/AST/Decl.cpp lib/Sema/SemaDecl.cpp lib/Sema/SemaTemplateInstantiateDecl.cpp test/SemaCXX/friend2.cpp 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 { 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: 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/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: 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_
[PATCH] D21508: Diagnose friend function template redefinitions
sepavloff updated this revision to Diff 107091. sepavloff added a comment. Simplified patch https://reviews.llvm.org/D21508 Files: include/clang/AST/DeclBase.h lib/AST/Decl.cpp lib/Sema/SemaDecl.cpp lib/Sema/SemaTemplateInstantiateDecl.cpp test/SemaCXX/friend2.cpp 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 { 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: lib/Sema/SemaDecl.cpp === --- lib/Sema/SemaDecl.cpp +++ lib/Sema/SemaDecl.cpp @@ -11990,6 +11990,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/AST/Decl.cpp === --- lib/AST/Decl.cpp +++ lib/AST/Decl.cpp @@ -3288,6 +3288,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: include/clang/AST/DeclBase.h === --- include/clang/AST/DeclBase.h +++ include/clang/AST/DeclBase.h @@ -1032,11 +1032,11 @@ unsigned OldNS = IdentifierNamespace; assert((OldNS & (IDNS_Tag | IDNS_Ordinary | IDNS_TagFriend | IDNS_OrdinaryFriend | -
[PATCH] D21508: Diagnose friend function template redefinitions
sepavloff updated this revision to Diff 106912. sepavloff edited the summary of this revision. sepavloff added a comment. Aligned implementation with https://reviews.llvm.org/D30170. https://reviews.llvm.org/D21508 Files: include/clang/AST/DeclBase.h lib/AST/Decl.cpp lib/Sema/SemaDecl.cpp lib/Sema/SemaTemplateInstantiateDecl.cpp test/SemaCXX/friend2.cpp 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 { 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: lib/Sema/SemaDecl.cpp === --- lib/Sema/SemaDecl.cpp +++ lib/Sema/SemaDecl.cpp @@ -11962,6 +11962,22 @@ return MissingPrototype; } +static FunctionTemplateDecl *findRedefinition(FunctionTemplateDecl *FTD) { + FunctionTemplateDecl *UninstantiatedDef = nullptr; + for (auto I : FTD->redecls()) { +auto D = cast(I); +if (D != FTD) { + if (D->isThisDeclarationADefinition()) +return D; + if (FunctionTemplateDecl *Orig = D->getInstantiatedFromMemberTemplate()) { +if (Orig->isThisDeclarationADefinition() || findRedefinition(Orig)) + UninstantiatedDef = D; + } +} + } + return UninstantiatedDef; +} + void Sema::CheckForFunctionRedefinition(FunctionDecl *FD, const FunctionDecl *EffectiveDefinition, @@ -11990,6 +12006,31 @@ } } } + + if (!Definition) +if (FunctionTemplateDecl *FTD = FD->getDescribedFunctionTemplate()) { + if (FunctionTemplateDecl *DefTD = findRedefinition(FTD)) { +const FunctionDecl *Def = DefTD->getTemplatedDecl(); +// If the found definition is a template with uninstantiated body, it +// can be replaced in specialization: +// +//template struct X { +// template void f(T, U) { } +//}; +//template<> template void X::f(int x, U y) { } +// +// In this example the specialization 'X' contains declaration of +// 'f', which is considered a definition by 'isDefined' because it is +// obtained by instantiation of 'X::f', which has a body. +// +if (isa(FTD->getDeclContext()) && +!Def->isThisDeclarationADefinition() && +Def->getFriendObjectKind() == Decl::FOK_None) + return; +Definition = Def; + } +} + if (!Definition)