diff options
-rw-r--r-- | lib/Sema/SemaTemplateInstantiateDecl.cpp | 22 | ||||
-rw-r--r-- | test/SemaTemplate/inject-templated-friend-post.cpp | 26 |
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 |