]> granicus.if.org Git - clang/commitdiff
Patch over yet more problems with friend declarations which were provoking
authorJohn McCall <rjmccall@apple.com>
Thu, 17 Dec 2009 23:21:11 +0000 (23:21 +0000)
committerJohn McCall <rjmccall@apple.com>
Thu, 17 Dec 2009 23:21:11 +0000 (23:21 +0000)
problems on LLVM-Code-Syntax.  This proved remarkably easy to "fix" once
I settled on how I was going to approach it.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@91633 91177308-0d34-0410-b5e6-96231b3b80d8

lib/AST/DeclCXX.cpp
lib/Sema/SemaTemplate.cpp
lib/Sema/SemaTemplateInstantiateDecl.cpp
test/SemaCXX/friend.cpp

index 292a3ed630cac1ea9ee0cf1618e64d5a9b71e238..986b81c0f85b79f2e9cc89bfa7f9ea1499cb93a6 100644 (file)
@@ -874,7 +874,11 @@ FriendDecl *FriendDecl::Create(ASTContext &C, DeclContext *DC,
            isa<CXXRecordDecl>(D) ||
            isa<FunctionTemplateDecl>(D) ||
            isa<ClassTemplateDecl>(D));
-    assert(D->getFriendObjectKind());
+
+    // As a temporary hack, we permit template instantiation to point
+    // to the original declaration when instantiating members.
+    assert(D->getFriendObjectKind() ||
+           (cast<CXXRecordDecl>(DC)->getTemplateSpecializationKind()));
   }
 #endif
 
index ac1b1ec0eed0f978967e3c40c4ae72dfec4250b3..c1d828fe45e9fe4d3808af04b389eb62d8a1d547 100644 (file)
@@ -691,6 +691,26 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK,
   if (Previous.begin() != Previous.end())
     PrevDecl = *Previous.begin();
 
+  // If there is a previous declaration with the same name, check
+  // whether this is a valid redeclaration.
+  ClassTemplateDecl *PrevClassTemplate
+    = dyn_cast_or_null<ClassTemplateDecl>(PrevDecl);
+
+  // We may have found the injected-class-name of a class template,
+  // class template partial specialization, or class template specialization. 
+  // In these cases, grab the template that is being defined or specialized.
+  if (!PrevClassTemplate && PrevDecl && isa<CXXRecordDecl>(PrevDecl) && 
+      cast<CXXRecordDecl>(PrevDecl)->isInjectedClassName()) {
+    PrevDecl = cast<CXXRecordDecl>(PrevDecl->getDeclContext());
+    PrevClassTemplate 
+      = cast<CXXRecordDecl>(PrevDecl)->getDescribedClassTemplate();
+    if (!PrevClassTemplate && isa<ClassTemplateSpecializationDecl>(PrevDecl)) {
+      PrevClassTemplate
+        = cast<ClassTemplateSpecializationDecl>(PrevDecl)
+            ->getSpecializedTemplate();
+    }
+  }
+
   if (PrevDecl && TUK == TUK_Friend) {
     // C++ [namespace.memdef]p3:
     //   [...] When looking for a prior declaration of a class or a function 
@@ -708,7 +728,7 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK,
       // Declarations in outer scopes don't matter. However, the outermost
       // context we computed is the semantic context for our new 
       // declaration.
-      PrevDecl = 0;
+      PrevDecl = PrevClassTemplate = 0;
       SemanticContext = OutermostContext;
     }
     
@@ -717,30 +737,10 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK,
       // class template to the template in scope, because that would perform
       // checking of the template parameter lists that can't be performed
       // until the outer context is instantiated.
-      PrevDecl = 0;
+      PrevDecl = PrevClassTemplate = 0;
     }
   } else if (PrevDecl && !isDeclInScope(PrevDecl, SemanticContext, S))
-    PrevDecl = 0;
-
-  // If there is a previous declaration with the same name, check
-  // whether this is a valid redeclaration.
-  ClassTemplateDecl *PrevClassTemplate
-    = dyn_cast_or_null<ClassTemplateDecl>(PrevDecl);
-
-  // We may have found the injected-class-name of a class template,
-  // class template partial specialization, or class template specialization. 
-  // In these cases, grab the template that is being defined or specialized.
-  if (!PrevClassTemplate && PrevDecl && isa<CXXRecordDecl>(PrevDecl) && 
-      cast<CXXRecordDecl>(PrevDecl)->isInjectedClassName()) {
-    PrevDecl = cast<CXXRecordDecl>(PrevDecl->getDeclContext());
-    PrevClassTemplate 
-      = cast<CXXRecordDecl>(PrevDecl)->getDescribedClassTemplate();
-    if (!PrevClassTemplate && isa<ClassTemplateSpecializationDecl>(PrevDecl)) {
-      PrevClassTemplate
-        = cast<ClassTemplateSpecializationDecl>(PrevDecl)
-            ->getSpecializedTemplate();
-    }
-  }
+    PrevDecl = PrevClassTemplate = 0;
 
   if (PrevClassTemplate) {
     // Ensure that the template parameter lists are compatible.
index 69982be84b908d12d87eb9e3a9bc50e3171fdb6f..2ca4810055e8727ee65740d547ce04b26a01322a 100644 (file)
@@ -396,7 +396,13 @@ Decl *TemplateDeclInstantiator::VisitFriendDecl(FriendDecl *D) {
     // FIXME: We have a problem here, because the nested call to Visit(ND)
     // will inject the thing that the friend references into the current
     // owner, which is wrong.
-    Decl *NewND = Visit(ND);
+    Decl *NewND;
+
+    // Hack to make this work almost well pending a rewrite.
+    if (ND->getDeclContext()->isRecord())
+      NewND = SemaRef.FindInstantiatedDecl(ND, TemplateArgs);
+    else
+      NewND = Visit(ND);
     if (!NewND) return 0;
 
     FU = cast<NamedDecl>(NewND);
index edb0dd53fe4e33b56b48111fce890135d17ebb1c..dc13570718b480669d1ffed4f3346f2db64ec7a6 100644 (file)
@@ -15,3 +15,17 @@ namespace test0 {
     friend void ns::f(int a);
   };
 }
+
+// Test derived from LLVM's Registry.h
+namespace test1 {
+  template <class T> struct Outer {
+    void foo(T);
+    struct Inner {
+      friend void Outer::foo(T);
+    };
+  };
+
+  void test() {
+    (void) Outer<int>::Inner();
+  }
+}