[PATCH] Lost template argument information in DeclRefExprs

Stefan M. stefanmoosbrugger at gmail.com
Wed Jan 28 00:00:44 PST 2015


When calling a templated method in the body of another templated method
the template argument information of the call gets lost.

The example below shows this case. The templated test function calls the
templated foo function.

EXAMPLE:

template <typename U>
void foo() {
 //some body...
}

template <typename T>
void test() {
 foo<float>();
}

int main() {
 test<int>();
 return 0;
}

AST:
foo function AST

FunctionTemplateDecl 0x1618250 </tmp/test3.cpp:1:1, line:4:1> foo
|-TemplateTypeParmDecl 0x16180b0 <line:1:11, col:20> typename U
|-FunctionDecl 0x16181b0 <line:2:1, line:4:1> foo 'void (void)'
| `-CompoundStmt 0x1618298 <line:2:12, line:4:1>
`-FunctionDecl 0x1661680 <line:2:1, line:4:1> foo 'void (void)'
  |-TemplateArgument type 'float'
  `-CompoundStmt 0x1618298 <line:2:12, line:4:1>

test function AST

FunctionTemplateDecl 0x16614a0 <line:6:1, line:9:1> test
|-TemplateTypeParmDecl 0x16182b0 <line:6:11, col:20> typename T
|-FunctionDecl 0x1618350 <line:7:1, line:9:1> test 'void (void)'
| `-CompoundStmt 0x1661868 <line:7:13, line:9:1>
|   `-CallExpr 0x1661840 <line:8:2, col:13> 'void'
|     `-ImplicitCastExpr 0x1661828 <col:2, col:11> 'void (*)(void)'
<FunctionToPointerDecay>
|       `-DeclRefExpr 0x1661780 <col:2, col:11> 'void (void)' lvalue
Function 0x1661680 'foo' 'void (void)' (FunctionTemplate 0x1618250 'foo')
`-FunctionDecl 0x1661b70 <line:7:1, line:9:1> test 'void (void)'
  |-TemplateArgument type 'int'
  `-CompoundStmt 0x1661e40 <line:7:13, line:9:1>
    `-CallExpr 0x1661e18 <line:8:2, col:13> 'void'
      `-ImplicitCastExpr 0x1661e00 <col:2, col:11> 'void (*)(void)'
<FunctionToPointerDecay>
        `-DeclRefExpr 0x1661d90 <col:2, col:11> 'void (void)' lvalue
Function 0x1661680 'foo' 'void (void)'

main function AST

FunctionDecl 0x16618e0 <line:11:1, line:14:1> main 'int (void)'
`-CompoundStmt 0x1661d68 <line:11:12, line:14:1>
  |-CallExpr 0x1661d00 <line:12:2, col:12> 'void'
  | `-ImplicitCastExpr 0x1661ce8 <col:2, col:10> 'void (*)(void)'
<FunctionToPointerDecay>
  |   `-DeclRefExpr 0x1661c70 <col:2, col:10> 'void (void)' lvalue Function
0x1661b70 'test' 'void (void)' (FunctionTemplate 0x16614a0 'test')
  `-ReturnStmt 0x1661d48 <line:13:2, col:9>
    `-IntegerLiteral 0x1661d28 <col:9> 'int' 0

In the AST we can see a template instantiation of test<int> (0x1661b70),
and this template instantiation contains a call to foo<float> (0x1661680).
This call is visible in the CallExpr (0x1661e18) that captures a
DeclRefExpr (0x1661d90). The problem occurs when checking this DeclRefExpr
for explicit template arguments. The call to
declRef->hasExplicitTemplateArgs()
will always return false (even when it has explicit template arguments),
because
the template argument information is not passed to the instances of the
templated function.

In TreeTransform.h method RebuildDeclRefExpr
we can find a FIXME comment that says: loses template args.
The following patch should solve this issue.
Unit tests have been executed like described in
http://clang.llvm.org/hacking.html
and http://llvm.org/docs/TestingGuide.html#testsuiterun. I hope this is the
correct
way to test that the patch doesn't break anything else?!

Cheers,
Stefan Moosbrugger
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20150128/38bdbf32/attachment.html>
-------------- next part --------------
Index: include/clang/Sema/Sema.h
===================================================================
--- include/clang/Sema/Sema.h
+++ include/clang/Sema/Sema.h
@@ -3563,7 +3563,8 @@
   ExprResult BuildDeclarationNameExpr(const CXXScopeSpec &SS,
                                       LookupResult &R,
                                       bool NeedsADL,
-                                      bool AcceptInvalidDecl = false);
+                                      bool AcceptInvalidDecl = false,
+                                      const TemplateArgumentListInfo *TemplateArgs = nullptr);
   ExprResult BuildDeclarationNameExpr(
       const CXXScopeSpec &SS, const DeclarationNameInfo &NameInfo, NamedDecl *D,
       NamedDecl *FoundD = nullptr,
Index: lib/Sema/SemaExpr.cpp
===================================================================
--- lib/Sema/SemaExpr.cpp
+++ lib/Sema/SemaExpr.cpp
@@ -1621,6 +1621,13 @@
                             VarSpec->getTemplateKeywordLoc(), D,
                             RefersToCapturedVariable, NameInfo.getLoc(), Ty, VK,
                             FoundD, TemplateArgs);
+  } else if (isa<FunctionDecl>(D) && cast<FunctionDecl>(D)->isFunctionTemplateSpecialization()) {
+    FunctionDecl *FuncDecl =
+       cast<FunctionDecl>(D);
+    E = DeclRefExpr::Create(Context, SS ? SS->getWithLocInContext(Context)
+                                       : NestedNameSpecifierLoc(), 
+                            FuncDecl->getPointOfInstantiation(), D, RefersToCapturedVariable,
+                            NameInfo, Ty, VK, FoundD, TemplateArgs);
   } else {
     assert(!TemplateArgs && "No template arguments for non-variable"
                             " template specialization references");
@@ -2697,12 +2704,13 @@

 ExprResult Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS,
                                           LookupResult &R, bool NeedsADL,
-                                          bool AcceptInvalidDecl) {
+                                          bool AcceptInvalidDecl,
+                                          const TemplateArgumentListInfo *TemplateArgs) {
   // If this is a single, fully-resolved result and we don't need ADL,
   // just build an ordinary singleton decl ref.
   if (!NeedsADL && R.isSingleResult() && !R.getAsSingle<FunctionTemplateDecl>())
     return BuildDeclarationNameExpr(SS, R.getLookupNameInfo(), R.getFoundDecl(),
-                                    R.getRepresentativeDecl(), nullptr,
+                                    R.getRepresentativeDecl(), TemplateArgs,
                                     AcceptInvalidDecl);

   // We only need to check the declaration if there's exactly one
Index: lib/Sema/TreeTransform.h
===================================================================
--- lib/Sema/TreeTransform.h
+++ lib/Sema/TreeTransform.h
@@ -1736,9 +1736,7 @@
     CXXScopeSpec SS;
     SS.Adopt(QualifierLoc);

-    // FIXME: loses template args.
-
-    return getSema().BuildDeclarationNameExpr(SS, NameInfo, VD);
+    return getSema().BuildDeclarationNameExpr(SS, NameInfo, VD, nullptr, TemplateArgs);
   }

   /// \brief Build a new expression in parentheses.


More information about the cfe-commits mailing list