aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGabor Greif <ggreif@gmail.com>2010-08-30 21:10:05 +0000
committerGabor Greif <ggreif@gmail.com>2010-08-30 21:10:05 +0000
commitab297ac4d3f7c078a34c75493b840ef6b5801be3 (patch)
tree4c8a964e6cb5c7c00a1f39dce402d8023e45f2a6
parent75f21af57f3dce1577d6c27bbe7bb45b49ced732 (diff)
fix dual aspect of PR8007,
namely when the friend function prototype is already used at the point of the template definition that is supposed to inject the friend function. Testcase verifies four scenarios. I would like receive some code review for this. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@112524 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--lib/Sema/SemaTemplateInstantiateDecl.cpp22
-rw-r--r--test/SemaTemplate/inject-templated-friend-post.cpp26
2 files changed, 37 insertions, 11 deletions
diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp
index e2dfb29c1b..6653e2e8ca 100644
--- a/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -1166,7 +1166,9 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
PrincipalDecl->setObjectOfFriendDecl(PrevDecl != 0);
DC->makeDeclVisibleInContext(PrincipalDecl, /*Recoverable=*/ false);
-
+
+ bool queuedInstantiation = false;
+
if (!SemaRef.getLangOptions().CPlusPlus0x &&
D->isThisDeclarationADefinition()) {
// Check for a function body.
@@ -1185,7 +1187,22 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
R != REnd; ++R) {
if (*R == Function)
continue;
- if (R->getFriendObjectKind() != Decl::FOK_None) {
+ switch (R->getFriendObjectKind()) {
+ case Decl::FOK_None:
+ if (!queuedInstantiation && R->isUsed(false)) {
+ if (MemberSpecializationInfo *MSInfo
+ = Function->getMemberSpecializationInfo()) {
+ if (MSInfo->getPointOfInstantiation().isInvalid()) {
+ SourceLocation Loc = R->getLocation(); // FIXME
+ MSInfo->setPointOfInstantiation(Loc);
+ SemaRef.PendingLocalImplicitInstantiations.push_back(
+ std::make_pair(Function, Loc));
+ queuedInstantiation = true;
+ }
+ }
+ }
+ break;
+ default:
if (const FunctionDecl *RPattern
= R->getTemplateInstantiationPattern())
if (RPattern->hasBody(RPattern)) {
@@ -1198,7 +1215,6 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
}
}
}
-
}
if (Function->isOverloadedOperator() && !DC->isRecord() &&
diff --git a/test/SemaTemplate/inject-templated-friend-post.cpp b/test/SemaTemplate/inject-templated-friend-post.cpp
index bbb80d15fc..aae7c01681 100644
--- a/test/SemaTemplate/inject-templated-friend-post.cpp
+++ b/test/SemaTemplate/inject-templated-friend-post.cpp
@@ -1,8 +1,9 @@
// RUN: %clang %s -S -emit-llvm -o - | grep -e "define linkonce_odr.*_ZlsR11std_ostreamRK8StreamerI3FooE"
+// RUN: %clang %s -S -emit-llvm -o - -DPROTOTYPE | grep -e "define linkonce_odr.*_ZlsR11std_ostreamRK8StreamerI3FooE"
// RUN: %clang -cc1 %s -DREDEFINE -verify
+// RUN: %clang -cc1 %s -DPROTOTYPE -DREDEFINE -verify
// PR8007: friend function not instantiated, reordered version.
// Corresponds to http://gcc.gnu.org/bugzilla/show_bug.cgi?id=38392
-// XFAIL: *
struct std_ostream
{
@@ -17,6 +18,7 @@ struct Streamer;
typedef struct Foo {} Foo;
std_ostream& operator << (std_ostream&, const Streamer<Foo>&);
+
void test(const Streamer<Foo>& foo)
{
cout << foo;
@@ -38,6 +40,21 @@ struct Streamer
void operator () (std_ostream&) const;
};
+#ifdef PROTOTYPE
+std_ostream& operator << (std_ostream&, const Streamer<Foo>&);
+#endif
+
+#ifdef INSTANTIATE
+template struct Streamer<Foo>;
+#endif
+
+#ifdef REDEFINE
+std_ostream& operator << (std_ostream& o, const Streamer<Foo>&) // expected-note{{is here}}
+{
+ return o;
+}
+#endif
+
template <>
void Streamer<Foo>::operator () (std_ostream& o) const // expected-note{{requested here}}
{
@@ -49,10 +66,3 @@ int main(void)
test(foo);
}
-#ifdef REDEFINE
-std_ostream& operator << (std_ostream& o, const Streamer<Foo>&) // expected-note{{is here}}
-{
- // Sema should flag this as a redefinition
- return o;
-}
-#endif