[PATCH] Lost template argument information in DeclRefExprs

Stefan Moosbrugger stefanmoosbrugger at gmail.com
Tue Jan 27 04:24:58 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

http://reviews.llvm.org/D7195

Files:
  include/clang/Sema/Sema.h
  lib/Sema/SemaExpr.cpp
  lib/Sema/TreeTransform.h

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.

EMAIL PREFERENCES
  http://reviews.llvm.org/settings/panel/emailpreferences/
-------------- next part --------------
A non-text attachment was scrubbed...
Name: D7195.18806.patch
Type: text/x-patch
Size: 3184 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20150127/2bf62f32/attachment.bin>


More information about the cfe-commits mailing list