diff options
Diffstat (limited to 'clang/lib')
-rw-r--r-- | clang/lib/Sema/SemaTemplateInstantiate.cpp | 61 | ||||
-rw-r--r-- | clang/lib/Sema/SemaTemplateInstantiateDecl.cpp | 24 | ||||
-rw-r--r-- | clang/lib/Sema/TreeTransform.h | 95 |
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> |