Teach TreeTransform and family how to transform generic lambdas within templates and nested within themselves.
This does not yet include capturing (that is next).
Please see test file for examples.
This patch was LGTM'd by Doug:
http://llvm-reviews.chandlerc.com/D1784
http://lists.cs.uiuc.edu/pipermail/cfe-commits/Week-of-Mon-20130930/090048.html
When I first committed this patch - a bunch of buildbots were unable to compile the code that VS2010 seemed to compile. Seems like there was a dependency on Sema/Template.h which VS did not seem to need, but I have now added for the other compilers. It still compiles on Visual Studio 2010 - lets hope the buildbots remain quiet (please!)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@191879 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp
index 32111ba..29481d6 100644
--- a/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/lib/Sema/SemaTemplateInstantiate.cpp
@@ -14,6 +14,7 @@
#include "TreeTransform.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/ASTLambda.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/Expr.h"
#include "clang/Basic/LangOptions.h"
@@ -130,6 +131,11 @@
assert(Function->getPrimaryTemplate() && "No function template?");
if (Function->getPrimaryTemplate()->isMemberSpecialization())
break;
+
+ // If this function is a generic lambda specialization, we are done.
+ if (isGenericLambdaCallOperatorSpecialization(Function))
+ break;
+
} else if (FunctionTemplateDecl *FunTmpl
= Function->getDescribedFunctionTemplate()) {
// Add the "injected" template arguments.
@@ -911,13 +917,56 @@
}
ExprResult TransformLambdaScope(LambdaExpr *E,
- CXXMethodDecl *CallOperator) {
- CallOperator->setInstantiationOfMemberFunction(E->getCallOperator(),
- TSK_ImplicitInstantiation);
- return TreeTransform<TemplateInstantiator>::
- TransformLambdaScope(E, CallOperator);
- }
+ CXXMethodDecl *NewCallOperator) {
+ // If a lambda is undergoing transformation for instance in the
+ // call to foo('a') below:
+ // template<class T> void foo(T t) {
+ // auto L1 = [](T a) { return a; };
+ // auto L2 = [](char b) { return b; };
+ // auto L3 = [](auto c) { return c; };
+ // }
+ // The AST nodes of the OldCallOperators within the primary template foo
+ // are connected to the NewCallOperators within the specialization of foo.
+ // - In the case of L1 and L2 we set the NewCallOperator to be considered
+ // an instantiation of the OldCallOperator.
+ // - In the generic lambda case, we set the NewTemplate to be considered
+ // an "instantiation" of the OldTemplate.
+ // See the documentation and use of get/setInstantiationOfMemberFunction
+ // and get/setInstantiatedFromMemberTemplate to appreciate the relevance
+ // of creating these links.
+ // And so it goes on and on with nested generic lambdas.
+ CXXMethodDecl *const OldCallOperator = E->getCallOperator();
+ FunctionTemplateDecl *const NewCallOperatorTemplate =
+ NewCallOperator->getDescribedFunctionTemplate();
+ FunctionTemplateDecl *const OldCallOperatorTemplate =
+ OldCallOperator->getDescribedFunctionTemplate();
+ if (!NewCallOperatorTemplate)
+ NewCallOperator->setInstantiationOfMemberFunction(OldCallOperator,
+ TSK_ImplicitInstantiation);
+ else {
+ NewCallOperatorTemplate->setInstantiatedFromMemberTemplate(
+ OldCallOperatorTemplate);
+ // Set this as a specialization so we don't go digging into the
+ // OldCallOperatorTemplate when retrieving the
+ // 'FunctionDecl::getTemplateInstantiationPattern()'
+ NewCallOperatorTemplate->setMemberSpecialization();
+ }
+ return inherited::TransformLambdaScope(E, NewCallOperator);
+ }
+ TemplateParameterList *TransformTemplateParameterList(
+ TemplateParameterList *OrigTPL) {
+ TemplateParameterList *NewTPL = 0;
+ if (OrigTPL) {
+ if (!OrigTPL->size()) return OrigTPL; // size 0, do nothing
+
+ DeclContext *Owner = OrigTPL->getParam(0)->getDeclContext();
+ TemplateDeclInstantiator DeclInstantiator(getSema(),
+ /* DeclContext *Owner */ Owner, TemplateArgs);
+ NewTPL = DeclInstantiator.SubstTemplateParams(OrigTPL);
+ }
+ return NewTPL;
+ }
private:
ExprResult transformNonTypeTemplateParmRef(NonTypeTemplateParmDecl *parm,
SourceLocation loc,