aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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