]> granicus.if.org Git - clang/commitdiff
fix dual aspect of PR8007,
authorGabor Greif <ggreif@gmail.com>
Mon, 30 Aug 2010 21:10:05 +0000 (21:10 +0000)
committerGabor Greif <ggreif@gmail.com>
Mon, 30 Aug 2010 21:10:05 +0000 (21:10 +0000)
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

lib/Sema/SemaTemplateInstantiateDecl.cpp
test/SemaTemplate/inject-templated-friend-post.cpp

index e2dfb29c1b9fc7883774ab439466833583ba9e16..6653e2e8ca7c38df9aeefe7fb7b90ce87585a497 100644 (file)
@@ -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() &&
index bbb80d15fc6421ef68aead730883c3797610bb77..aae7c01681e9adac97e56d0a447e64a52a27dd3d 100644 (file)
@@ -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