summaryrefslogtreecommitdiffstats
path: root/clang/lib
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib')
-rw-r--r--clang/lib/Sema/SemaTemplateInstantiate.cpp61
-rw-r--r--clang/lib/Sema/SemaTemplateInstantiateDecl.cpp24
-rw-r--r--clang/lib/Sema/TreeTransform.h95
3 files changed, 152 insertions, 28 deletions
diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp
index 32111bac3a4..29481d6c63b 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/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 @@ Sema::getTemplateInstantiationArgs(NamedDecl *D,
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 @@ namespace {
}
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,
diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 35f3616db6a..359fb73166d 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -4171,6 +4171,30 @@ DeclContext *Sema::FindInstantiatedContext(SourceLocation Loc, DeclContext* DC,
NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D,
const MultiLevelTemplateArgumentList &TemplateArgs) {
DeclContext *ParentDC = D->getDeclContext();
+
+ // If we have a parameter from a non-dependent context with a non-dependent
+ // type it obviously can not be mapped to a different instantiated decl.
+ // Consider the code below, with explicit return types, when N gets
+ // specialized ...:
+ // template<class T> void fooT(T t) {
+ // auto L = [](auto a) -> void {
+ // auto M = [](char b) -> void {
+ // auto N = [](auto c) -> void {
+ // int x = sizeof(a) + sizeof(b) +
+ // sizeof(c);
+ // };
+ // N('a');
+ // };
+ // };
+ // L(3.14);
+ // }
+ // fooT('a');
+ // ... without this check below, findInstantiationOf fails with
+ // an assertion violation.
+ if (isa<ParmVarDecl>(D) && !ParentDC->isDependentContext() &&
+ !cast<ParmVarDecl>(D)->getType()->isInstantiationDependentType())
+ return D;
+
if (isa<ParmVarDecl>(D) || isa<NonTypeTemplateParmDecl>(D) ||
isa<TemplateTypeParmDecl>(D) || isa<TemplateTemplateParmDecl>(D) ||
(ParentDC->isFunctionOrMethod() && ParentDC->isDependentContext()) ||
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index 977d0132b7e..bec956b6d72 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -594,6 +594,11 @@ public:
/// \brief Transform the captures and body of a lambda expression.
ExprResult TransformLambdaScope(LambdaExpr *E, CXXMethodDecl *CallOperator);
+ TemplateParameterList *TransformTemplateParameterList(
+ TemplateParameterList *TPL) {
+ return TPL;
+ }
+
ExprResult TransformAddressOfOperand(Expr *E);
ExprResult TransformDependentScopeDeclRefExpr(DependentScopeDeclRefExpr *E,
bool IsAddressOfOperand);
@@ -4573,6 +4578,19 @@ template<typename Derived>
QualType TreeTransform<Derived>::TransformDecltypeType(TypeLocBuilder &TLB,
DecltypeTypeLoc TL) {
const DecltypeType *T = TL.getTypePtr();
+ // Don't transform a decltype construct that has already been transformed
+ // into a non-dependent type.
+ // Allows the following to compile:
+ // auto L = [](auto a) {
+ // return [](auto b) ->decltype(a) {
+ // return b;
+ // };
+ //};
+ if (!T->isInstantiationDependentType()) {
+ DecltypeTypeLoc NewTL = TLB.push<DecltypeTypeLoc>(TL.getType());
+ NewTL.setNameLoc(TL.getNameLoc());
+ return NewTL.getType();
+ }
// decltype expressions are not potentially evaluated contexts
EnterExpressionEvaluationContext Unevaluated(SemaRef, Sema::Unevaluated, 0,
@@ -8284,24 +8302,27 @@ template<typename Derived>
ExprResult
TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
- // FIXME: Implement nested generic lambda transformations.
- if (E->isGenericLambda()) {
- getSema().Diag(E->getIntroducerRange().getBegin(),
- diag::err_glambda_not_fully_implemented)
- << " template transformation of generic lambdas not implemented yet";
- return ExprError();
- }
- // Transform the type of the lambda parameters and start the definition of
- // the lambda itself.
- TypeSourceInfo *MethodTy
- = TransformType(E->getCallOperator()->getTypeSourceInfo());
- if (!MethodTy)
+ getSema().PushLambdaScope();
+ LambdaScopeInfo *LSI = getSema().getCurLambda();
+ TemplateParameterList *const OrigTPL = E->getTemplateParameterList();
+ TemplateParameterList *NewTPL = 0;
+ // Transform the template parameters, and add them to the
+ // current instantiation scope.
+ if (OrigTPL) {
+ NewTPL = getDerived().TransformTemplateParameterList(OrigTPL);
+ }
+ LSI->GLTemplateParameterList = NewTPL;
+ // Transform the type of the lambda parameters and start the definition of
+ // the lambda itself.
+ TypeSourceInfo *OldCallOpTSI = E->getCallOperator()->getTypeSourceInfo();
+ TypeSourceInfo *NewCallOpTSI = TransformType(OldCallOpTSI);
+ if (!NewCallOpTSI)
return ExprError();
// Create the local class that will describe the lambda.
CXXRecordDecl *Class
= getSema().createLambdaClosureType(E->getIntroducerRange(),
- MethodTy,
+ NewCallOpTSI,
/*KnownDependent=*/false);
getDerived().transformedLocalDecl(E->getLambdaClass(), Class);
@@ -8313,19 +8334,49 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
E->getCallOperator()->param_size(),
0, ParamTypes, &Params))
return ExprError();
- getSema().PushLambdaScope();
- LambdaScopeInfo *LSI = getSema().getCurLambda();
- // TODO: Fix for nested lambdas
- LSI->GLTemplateParameterList = 0;
+
// Build the call operator.
- CXXMethodDecl *CallOperator
+ CXXMethodDecl *NewCallOperator
= getSema().startLambdaDefinition(Class, E->getIntroducerRange(),
- MethodTy,
+ NewCallOpTSI,
E->getCallOperator()->getLocEnd(),
Params);
- getDerived().transformAttrs(E->getCallOperator(), CallOperator);
-
- return getDerived().TransformLambdaScope(E, CallOperator);
+ LSI->CallOperator = NewCallOperator;
+ // Fix the Decl Contexts of the parameters within the call op function
+ // prototype.
+ getDerived().transformAttrs(E->getCallOperator(), NewCallOperator);
+
+ TypeLoc NewCallOpTL = NewCallOpTSI->getTypeLoc();
+ FunctionProtoTypeLoc NewFPTL = NewCallOpTL.castAs<FunctionProtoTypeLoc>();
+ ParmVarDecl **NewParamDeclArray = NewFPTL.getParmArray();
+ const unsigned NewNumArgs = NewFPTL.getNumArgs();
+ for (unsigned I = 0; I < NewNumArgs; ++I) {
+ NewParamDeclArray[I]->setOwningFunction(NewCallOperator);
+ }
+ // If this is a non-generic lambda, the parameters do not get added to the
+ // current instantiation scope, so add them. This feels kludgey.
+ // Anyway, it allows the following to compile when the enclosing template
+ // is specialized and the entire lambda expression has to be
+ // transformed. Without this FindInstantiatedDecl causes an assertion.
+ // template<class T> void foo(T t) {
+ // auto L = [](auto a) {
+ // auto M = [](char b) { <-- note: non-generic lambda
+ // auto N = [](auto c) {
+ // int x = sizeof(a);
+ // x = sizeof(b); <-- specifically this line
+ // x = sizeof(c);
+ // };
+ // };
+ // };
+ // }
+ // foo('a');
+ //
+ if (!E->isGenericLambda()) {
+ for (unsigned I = 0; I < NewNumArgs; ++I)
+ SemaRef.CurrentInstantiationScope->InstantiatedLocal(
+ NewParamDeclArray[I], NewParamDeclArray[I]);
+ }
+ return getDerived().TransformLambdaScope(E, NewCallOperator);
}
template<typename Derived>
OpenPOWER on IntegriCloud