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<typename T> void func_31(T *x);
+template<typename T1>
+struct C31a {
+ template<typename T> friend void func_31(T *x) {}
+};
+template<typename T1>
+struct C31b {
+ template<typename T> friend void func_31(T *x) {}
+};
+
+
+template<typename T> inline void func_32(T *x) {}
+template<typename T1>
+struct C32a {
+ template<typename T> friend void func_32(T *x) {}
+};
+template<typename T1>
+struct C32b {
+ template<typename T> friend void func_32(T *x) {}
+};
+
+
+template<typename T1>
+struct C33a {
+ template<typename T> friend void func_33(T *x) {}
+};
+template<typename T1>
+struct C33b {
+ template<typename T> friend void func_33(T *x) {}
+};
+
+
+template<typename T> inline void func_34(T *x) {} // expected-note{{previous definition is here}}
+template<typename T1>
+struct C34 {
+ template<typename T> friend void func_34(T *x) {} // expected-error{{redefinition of 'func_34'}}
+};
+
+C34<int> v34; // expected-note{{in instantiation of template class 'C34<int>' requested here}}
+
+
+template<typename T> inline void func_35(T *x);
+template<typename T1>
+struct C35a {
+ template<typename T> friend void func_35(T *x) {} // expected-note{{previous definition is here}}
+};
+template<typename T1>
+struct C35b {
+ template<typename T> friend void func_35(T *x) {} // expected-error{{redefinition of 'func_35'}}
+};
+
+C35a<int> v35a;
+C35b<int> v35b; // expected-note{{in instantiation of template class 'C35b<int>' requested here}}
+
+
+template<typename T> void func_36(T *x);
+template<typename T1>
+struct C36 {
+ template<typename T> friend void func_36(T *x) {} // expected-error{{redefinition of 'func_36'}}
+ // expected-note@-1{{previous definition is here}}
+};
+
+C36<int> v36a;
+C36<long> v36b; //expected-note{{in instantiation of template class 'C36<long>' requested here}}
+
+
+template<typename T> void func_37(T *x);
+template<typename T1>
+struct C37 {
+ template<typename T> friend void func_37(T *x) {} // expected-note{{previous definition is here}}
+};
+
+C37<int> v37;
+template<typename T> 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<typename T> struct A {
friend A operator+(const A&, const A&) { return {}; }
+ template<typename T2> friend void func_1(const A&, const T2 &) {}
};
#pragma clang module end
#pragma clang module endbuild
@@ -36,4 +37,5 @@
void h() {
A<int> 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<FunctionTemplateDecl>(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_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();
@@ -1095,7 +1095,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))
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits