]> granicus.if.org Git - clang/commitdiff
RecursiveASTVisitor: Visit instantiations of member templates of class
authorRichard Smith <richard-llvm@metafoo.co.uk>
Tue, 24 Apr 2012 20:39:49 +0000 (20:39 +0000)
committerRichard Smith <richard-llvm@metafoo.co.uk>
Tue, 24 Apr 2012 20:39:49 +0000 (20:39 +0000)
templates. In an implicit instantiation of a member class, any member
templates don't get instantiated, so the existing check which only visited
the instantiations of a defined template skipped these templates'
instantiations.

Since there is only a single declaration of a member template of a class
template specialization, just use that to determine whether to visit the
instantiations. This introduces a slight inconsistency in that we will
visit the instantiations of such templates whether or not they are
defined, but we never visit a declared-but-not-defined instantiation, so
this turns out to not matter.

Patch by Daniel Jasper!

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

include/clang/AST/RecursiveASTVisitor.h
unittests/Tooling/RecursiveASTVisitorTest.cpp

index 465ed12dae4d8eb80b2c05f1865edf220bba0529..e91b68cd42155d6bc22f9899950c5ba1390f4c0c 100644 (file)
@@ -1436,7 +1436,8 @@ DEF_TRAVERSE_DECL(ClassTemplateDecl, {
     if (getDerived().shouldVisitTemplateInstantiations()) {
       // If this is the definition of the primary template, visit
       // instantiations which were formed from this pattern.
-      if (D->isThisDeclarationADefinition())
+      if (D->isThisDeclarationADefinition() ||
+          D->getInstantiatedFromMemberTemplate())
         TRY_TO(TraverseClassInstantiations(D, D));
     }
 
@@ -1489,7 +1490,8 @@ DEF_TRAVERSE_DECL(FunctionTemplateDecl, {
       //
       // In addition, we only traverse the function instantiations when
       // the function template is a function template definition.
-      if (D->isThisDeclarationADefinition()) {
+      if (D->isThisDeclarationADefinition() ||
+          D->getInstantiatedFromMemberTemplate()) {
         TRY_TO(TraverseFunctionInstantiations(D));
       }
     }
index 8ddae504a0aaa129a6629c4494f47672672abb15..6ef2786210f84348d073d942bc3683b949bbab20 100644 (file)
@@ -208,8 +208,7 @@ TEST(RecursiveASTVisitor, VisitsCallInTemplateInstantiation) {
     "void foo() { y<Y>(Y()); }"));
 }
 
-/* FIXME:
-TEST(RecursiveASTVisitor, VisitsCallInNestedTemplateInstantiation) {
+TEST(RecursiveASTVisitor, VisitsCallInNestedFunctionTemplateInstantiation) {
   CXXMemberCallVisitor Visitor;
   Visitor.ExpectMatch("Y::x", 4, 5);
   EXPECT_TRUE(Visitor.runOver(
@@ -221,7 +220,24 @@ TEST(RecursiveASTVisitor, VisitsCallInNestedTemplateInstantiation) {
     "};\n"
     "void foo() { Z<Y>::f<int>(); }"));
 }
-*/
+
+TEST(RecursiveASTVisitor, VisitsCallInNestedClassTemplateInstantiation) {
+  CXXMemberCallVisitor Visitor;
+  Visitor.ExpectMatch("A::x", 5, 7);
+  EXPECT_TRUE(Visitor.runOver(
+    "template <typename T1> struct X {\n"
+    "  template <typename T2> struct Y {\n"
+    "    void f() {\n"
+    "      T2 y;\n"
+    "      y.x();\n"
+    "    }\n"
+    "  };\n"
+    "};\n"
+    "struct A { void x(); };\n"
+    "int main() {\n"
+    "  (new X<A>::Y<A>())->f();\n"
+    "}"));
+}
 
 /* FIXME: According to Richard Smith this is a bug in the AST.
 TEST(RecursiveASTVisitor, VisitsBaseClassTemplateArgumentsInInstantiation) {
@@ -236,4 +252,3 @@ TEST(RecursiveASTVisitor, VisitsBaseClassTemplateArgumentsInInstantiation) {
 */
 
 } // end namespace clang
-