thakis created this revision.
thakis added reviewers: rsmith, rnk.
thakis added a subscriber: cfe-commits.
Herald added subscribers: aemerson, klimek.

RecursiveASTVisitor::TraverseFunctionHelper() traverses a function's 
ParmVarDecls by going to the function's getTypeSourceInfo if it exists, and `
DEF_TRAVERSE_TYPELOC(FunctionProtoType` then goes to the function's 
ParmVarDecls.

For a function template that doesn't have parameters that explicitly depend on 
the template parameter, we used to be clever and not build a new 
TypeSourceInfo. That meant that when an instantiation of such a template is 
visited, its TypeSourceInfo would point to the ParmVarDecls of the template, 
not of the instantiation, which then confused clients of RecursiveASTVisitor.

So don't be clever for function templates that have parameters, even if none of 
the parameters depend on the type.

Fixes PR26257.

http://reviews.llvm.org/D16478

Files:
  lib/Sema/SemaTemplateInstantiate.cpp
  unittests/ASTMatchers/ASTMatchersTest.cpp

Index: lib/Sema/SemaTemplateInstantiate.cpp
===================================================================
--- lib/Sema/SemaTemplateInstantiate.cpp
+++ lib/Sema/SemaTemplateInstantiate.cpp
@@ -1512,20 +1512,22 @@
 }
 
 static bool NeedsInstantiationAsFunctionType(TypeSourceInfo *T) {
-  if (T->getType()->isInstantiationDependentType() || 
+  if (T->getType()->isInstantiationDependentType() ||
       T->getType()->isVariablyModifiedType())
     return true;
 
   TypeLoc TL = T->getTypeLoc().IgnoreParens();
   if (!TL.getAs<FunctionProtoTypeLoc>())
     return false;
 
   FunctionProtoTypeLoc FP = TL.castAs<FunctionProtoTypeLoc>();
+  bool AllParmsNull = true;
   for (unsigned I = 0, E = FP.getNumParams(); I != E; ++I) {
     ParmVarDecl *P = FP.getParam(I);
 
     // This must be synthesized from a typedef.
     if (!P) continue;
+    AllParmsNull = false;
 
     // The parameter's type as written might be dependent even if the
     // decayed type was not dependent.
@@ -1540,7 +1542,9 @@
       return true;
   }
 
-  return false;
+  // If there are any parameters, a new TypeSourceInfo that refers to the
+  // instantiated parameters must be built.
+  return !AllParmsNull && FP.getNumParams() > 0;
 }
 
 /// A form of SubstType intended specifically for instantiating the
@@ -1556,7 +1560,7 @@
   assert(!ActiveTemplateInstantiations.empty() &&
          "Cannot perform an instantiation without some context on the "
          "instantiation stack");
-  
+
   if (!NeedsInstantiationAsFunctionType(T))
     return T;
 
Index: unittests/ASTMatchers/ASTMatchersTest.cpp
===================================================================
--- unittests/ASTMatchers/ASTMatchersTest.cpp
+++ unittests/ASTMatchers/ASTMatchersTest.cpp
@@ -4225,6 +4225,17 @@
                       declRefExpr(to(decl(hasAncestor(decl()))))));
 }
 
+TEST(HasAncestor, NonParmDependentTemplateParmVarDeclRefExpr) {
+  EXPECT_TRUE(matches("struct PartitionAllocator {\n"
+                      "  template<typename T>\n"
+                      "  static int quantizedSize(int count) {\n"
+                      "    return count;\n"
+                      "  }\n"
+                      "  void f() { quantizedSize<int>(10); }\n"
+                      "};",
+                      declRefExpr(to(decl(hasAncestor(decl()))))));
+}
+
 TEST(HasParent, MatchesAllParents) {
   EXPECT_TRUE(matches(
       "template <typename T> struct C { static void f() { 42; } };"


Index: lib/Sema/SemaTemplateInstantiate.cpp
===================================================================
--- lib/Sema/SemaTemplateInstantiate.cpp
+++ lib/Sema/SemaTemplateInstantiate.cpp
@@ -1512,20 +1512,22 @@
 }
 
 static bool NeedsInstantiationAsFunctionType(TypeSourceInfo *T) {
-  if (T->getType()->isInstantiationDependentType() || 
+  if (T->getType()->isInstantiationDependentType() ||
       T->getType()->isVariablyModifiedType())
     return true;
 
   TypeLoc TL = T->getTypeLoc().IgnoreParens();
   if (!TL.getAs<FunctionProtoTypeLoc>())
     return false;
 
   FunctionProtoTypeLoc FP = TL.castAs<FunctionProtoTypeLoc>();
+  bool AllParmsNull = true;
   for (unsigned I = 0, E = FP.getNumParams(); I != E; ++I) {
     ParmVarDecl *P = FP.getParam(I);
 
     // This must be synthesized from a typedef.
     if (!P) continue;
+    AllParmsNull = false;
 
     // The parameter's type as written might be dependent even if the
     // decayed type was not dependent.
@@ -1540,7 +1542,9 @@
       return true;
   }
 
-  return false;
+  // If there are any parameters, a new TypeSourceInfo that refers to the
+  // instantiated parameters must be built.
+  return !AllParmsNull && FP.getNumParams() > 0;
 }
 
 /// A form of SubstType intended specifically for instantiating the
@@ -1556,7 +1560,7 @@
   assert(!ActiveTemplateInstantiations.empty() &&
          "Cannot perform an instantiation without some context on the "
          "instantiation stack");
-  
+
   if (!NeedsInstantiationAsFunctionType(T))
     return T;
 
Index: unittests/ASTMatchers/ASTMatchersTest.cpp
===================================================================
--- unittests/ASTMatchers/ASTMatchersTest.cpp
+++ unittests/ASTMatchers/ASTMatchersTest.cpp
@@ -4225,6 +4225,17 @@
                       declRefExpr(to(decl(hasAncestor(decl()))))));
 }
 
+TEST(HasAncestor, NonParmDependentTemplateParmVarDeclRefExpr) {
+  EXPECT_TRUE(matches("struct PartitionAllocator {\n"
+                      "  template<typename T>\n"
+                      "  static int quantizedSize(int count) {\n"
+                      "    return count;\n"
+                      "  }\n"
+                      "  void f() { quantizedSize<int>(10); }\n"
+                      "};",
+                      declRefExpr(to(decl(hasAncestor(decl()))))));
+}
+
 TEST(HasParent, MatchesAllParents) {
   EXPECT_TRUE(matches(
       "template <typename T> struct C { static void f() { 42; } };"
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to