forked from OSchip/llvm-project
Diagnose friend function template redefinitions.
Friend function template defined in a class template becomes available if the enclosing class template is instantiated. Until the function template is used, it does not have a body, but still is considered a definition for the purpose of redeclaration checks. This change modifies redefinition check so that it can find the friend function template definitions in instantiated classes. Differential Revision: http://reviews.llvm.org/D21508 llvm-svn: 348473
This commit is contained in:
parent
1027249ec9
commit
acfcd78aec
|
@ -1065,11 +1065,11 @@ public:
|
|||
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 @@ public:
|
|||
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))
|
||||
|
|
|
@ -12737,6 +12737,29 @@ Sema::CheckForFunctionRedefinition(FunctionDecl *FD,
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
|
|
|
@ -1817,7 +1817,9 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
|
|||
// 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;
|
||||
|
|
|
@ -7,6 +7,7 @@ module A {}
|
|||
#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 @@ inline void g() { A<int> a; }
|
|||
void h() {
|
||||
A<int> a;
|
||||
a + a;
|
||||
func_1(a, 0);
|
||||
}
|
||||
|
|
|
@ -18,16 +18,3 @@ void f() {
|
|||
foo(x);
|
||||
bar(x);
|
||||
}
|
||||
|
||||
namespace PR39742 {
|
||||
template<typename>
|
||||
struct wrapper {
|
||||
template<typename>
|
||||
friend void friend_function_template() {}
|
||||
};
|
||||
|
||||
wrapper<bool> x;
|
||||
// FIXME: We should really error here because of the redefinition of
|
||||
// friend_function_template.
|
||||
wrapper<int> y;
|
||||
}
|
||||
|
|
|
@ -129,6 +129,83 @@ C22b<int> c22bi;
|
|||
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 {
|
||||
|
||||
|
@ -235,3 +312,15 @@ void func() {
|
|||
cache.insert();
|
||||
}
|
||||
}
|
||||
|
||||
namespace PR39742 {
|
||||
template<typename>
|
||||
struct wrapper {
|
||||
template<typename>
|
||||
friend void friend_function_template() {} // expected-error{{redefinition of 'friend_function_template'}}
|
||||
// expected-note@-1{{previous definition is here}}
|
||||
};
|
||||
|
||||
wrapper<bool> x;
|
||||
wrapper<int> y; // expected-note{{in instantiation of template class 'PR39742::wrapper<int>' requested here}}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue