r191879 - Teach TreeTransform and family how to transform generic lambdas within templates and nested within themselves.
Rafael EspĂndola
rafael.espindola at gmail.com
Fri Oct 4 07:46:24 PDT 2013
Sorry, I reverted this because of llvm.org/pr17476.
On 3 October 2013 02:29, Faisal Vali <faisalv at yahoo.com> wrote:
> Author: faisalv
> Date: Thu Oct 3 01:29:33 2013
> New Revision: 191879
>
> URL: http://llvm.org/viewvc/llvm-project?rev=191879&view=rev
> Log:
> 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!)
>
> Modified:
> cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp
> cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
> cfe/trunk/lib/Sema/TreeTransform.h
> cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/generic-lambda-unimplemented-1y.cpp
> cfe/trunk/test/SemaCXX/cxx1y-generic-lambdas.cpp
>
> Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp?rev=191879&r1=191878&r2=191879&view=diff
> ==============================================================================
> --- cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp (original)
> +++ cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp Thu Oct 3 01:29:33 2013
> @@ -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(Named
> 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,
>
> Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp?rev=191879&r1=191878&r2=191879&view=diff
> ==============================================================================
> --- cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp (original)
> +++ cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp Thu Oct 3 01:29:33 2013
> @@ -4171,6 +4171,30 @@ DeclContext *Sema::FindInstantiatedConte
> 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()) ||
>
> Modified: cfe/trunk/lib/Sema/TreeTransform.h
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/TreeTransform.h?rev=191879&r1=191878&r2=191879&view=diff
> ==============================================================================
> --- cfe/trunk/lib/Sema/TreeTransform.h (original)
> +++ cfe/trunk/lib/Sema/TreeTransform.h Thu Oct 3 01:29:33 2013
> @@ -33,6 +33,7 @@
> #include "clang/Sema/ScopeInfo.h"
> #include "clang/Sema/SemaDiagnostic.h"
> #include "clang/Sema/SemaInternal.h"
> +#include "clang/Sema/Template.h"
> #include "llvm/ADT/ArrayRef.h"
> #include "llvm/Support/ErrorHandling.h"
> #include <algorithm>
> @@ -594,6 +595,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 +4579,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 +8303,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 +8335,49 @@ TreeTransform<Derived>::TransformLambdaE
> 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>
>
> Modified: cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/generic-lambda-unimplemented-1y.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/generic-lambda-unimplemented-1y.cpp?rev=191879&r1=191878&r2=191879&view=diff
> ==============================================================================
> --- cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/generic-lambda-unimplemented-1y.cpp (original)
> +++ cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/generic-lambda-unimplemented-1y.cpp Thu Oct 3 01:29:33 2013
> @@ -29,20 +29,3 @@ void test() {
>
> }
>
> -namespace nested_generic_lambdas {
> -void test() {
> - auto L = [](auto a) -> int {
> - auto M = [](auto b, decltype(a) b2) -> int { //expected-error{{unimplemented}}
> - return 1;
> - };
> - M(a, a);
> - };
> - L(3); //expected-note{{in instantiation of}}
> -}
> -template<class T> void foo(T) {
> - auto L = [](auto a) { return a; }; //expected-error{{unimplemented}}
> -}
> -template void foo(int); //expected-note{{in instantiation of}}
> -}
> -
> -
>
> Modified: cfe/trunk/test/SemaCXX/cxx1y-generic-lambdas.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/cxx1y-generic-lambdas.cpp?rev=191879&r1=191878&r2=191879&view=diff
> ==============================================================================
> --- cfe/trunk/test/SemaCXX/cxx1y-generic-lambdas.cpp (original)
> +++ cfe/trunk/test/SemaCXX/cxx1y-generic-lambdas.cpp Thu Oct 3 01:29:33 2013
> @@ -1,4 +1,4 @@
> -// RUN: %clang_cc1 -std=c++1y -verify -fsyntax-only -fblocks %s
> +// RUN: %clang_cc1 -std=c++1y -verify -fsyntax-only -fblocks -emit-llvm -o - %s
> // DONTRUNYET: %clang_cc1 -std=c++1y -verify -fsyntax-only -fblocks -fdelayed-template-parsing %s -DDELAYED_TEMPLATE_PARSING
> // DONTRUNYET: %clang_cc1 -std=c++1y -verify -fsyntax-only -fblocks -fms-extensions %s -DMS_EXTENSIONS
> // DONTRUNYET: %clang_cc1 -std=c++1y -verify -fsyntax-only -fblocks -fdelayed-template-parsing -fms-extensions %s -DMS_EXTENSIONS -DDELAYED_TEMPLATE_PARSING
> @@ -99,10 +99,8 @@ void test() {
> //expected-note{{candidate}}
> }
> }
> -
> }
>
> -
> namespace return_type_deduction_ok {
> auto l = [](auto a) ->auto { return a; }(2);
> auto l2 = [](auto a) ->decltype(auto) { return a; }(2);
> @@ -114,3 +112,479 @@ namespace generic_lambda_as_default_argu
> void test(int i = [](auto a)->int { return a; }(3)) {
> }
> }
> +
> +namespace nested_non_capturing_lambda_tests {
> +template<class ... Ts> void print(Ts ...) { }
> +int test() {
> +{
> + auto L = [](auto a) {
> + return [](auto b) {
> + return b;
> + };
> + };
> + auto M = L(3);
> + M(4.15);
> + }
> +{
> + int i = 10; //expected-note{{declared here}}
> + auto L = [](auto a) {
> + return [](auto b) { //expected-note{{begins here}}
> + i = b; //expected-error{{cannot be implicitly captured}}
> + return b;
> + };
> + };
> + auto M = L(3);
> + M(4.15); //expected-note{{instantiation}}
> + }
> + {
> + auto L = [](auto a) {
> + print("a = ", a, "\n");
> + return [](auto b) ->decltype(a) {
> + print("b = ", b, "\n");
> + return b;
> + };
> + };
> + auto M = L(3);
> + M(4.15);
> + }
> +
> +{
> + auto L = [](auto a) ->decltype(a) {
> + print("a = ", a, "\n");
> + return [](auto b) ->decltype(a) { //expected-error{{no viable conversion}}\
> + //expected-note{{candidate template ignored}}
> + print("b = ", b, "\n");
> + return b;
> + };
> + };
> + auto M = L(3); //expected-note{{in instantiation of}}
> + }
> +{
> + auto L = [](auto a) {
> + print("a = ", a, "\n");
> + return [](auto ... b) ->decltype(a) {
> + print("b = ", b ..., "\n");
> + return 4;
> + };
> + };
> + auto M = L(3);
> + M(4.15, 3, "fv");
> +}
> +
> +{
> + auto L = [](auto a) {
> + print("a = ", a, "\n");
> + return [](auto ... b) ->decltype(a) {
> + print("b = ", b ..., "\n");
> + return 4;
> + };
> + };
> + auto M = L(3);
> + int (*fp)(double, int, const char*) = M;
> + fp(4.15, 3, "fv");
> +}
> +
> +{
> + auto L = [](auto a) {
> + print("a = ", a, "\n");
> + return [](char b) {
> + return [](auto ... c) ->decltype(b) {
> + print("c = ", c ..., "\n");
> + return 42;
> + };
> + };
> + };
> + L(4);
> + auto M = L(3);
> + M('a');
> + auto N = M('x');
> + N("\n3 = ", 3, "\n6.14 = ", 6.14, "\n4'123'456 = ", 4'123'456);
> + char (*np)(const char*, int, const char*, double, const char*, int) = N;
> + np("\n3 = ", 3, "\n6.14 = ", 6.14, "\n4'123'456 = ", 4'123'456);
> +}
> +
> +
> +{
> + auto L = [](auto a) {
> + print("a = ", a, "\n");
> + return [](decltype(a) b) {
> + return [](auto ... c) ->decltype(b) {
> + print("c = ", c ..., "\n");
> + return 42;
> + };
> + };
> + };
> + L('4');
> + auto M = L('3');
> + M('a');
> + auto N = M('x');
> + N("\n3 = ", 3, "\n6.14 = ", 6.14, "\n4'123'456 = ", 4'123'456);
> + char (*np)(const char*, int, const char*, double, const char*, int) = N;
> + np("\n3 = ", 3, "\n6.14 = ", 6.14, "\n4'123'456 = ", 4'123'456);
> +}
> +
> +
> +{
> + struct X {
> + static void foo(double d) { }
> + void test() {
> + auto L = [](auto a) {
> + print("a = ", a, "\n");
> + foo(a);
> + return [](decltype(a) b) {
> + foo(b);
> + foo(sizeof(a) + sizeof(b));
> + return [](auto ... c) ->decltype(b) {
> + print("c = ", c ..., "\n");
> + foo(decltype(b){});
> + foo(sizeof(decltype(a)*) + sizeof(decltype(b)*));
> + return 42;
> + };
> + };
> + };
> + L('4');
> + auto M = L('3');
> + M('a');
> + auto N = M('x');
> + N("\n3 = ", 3, "\n6.14 = ", 6.14, "\n4'123'456 = ", 4'123'456);
> + char (*np)(const char*, int, const char*, double, const char*, int) = N;
> + np("\n3 = ", 3, "\n6.14 = ", 6.14, "\n4'123'456 = ", 4'123'456);
> + }
> +};
> +X x;
> +x.test();
> +}
> +// Make sure we can escape the function
> +{
> + struct X {
> + static void foo(double d) { }
> + auto test() {
> + auto L = [](auto a) {
> + print("a = ", a, "\n");
> + foo(a);
> + return [](decltype(a) b) {
> + foo(b);
> + foo(sizeof(a) + sizeof(b));
> + return [](auto ... c) ->decltype(b) {
> + print("c = ", c ..., "\n");
> + foo(decltype(b){});
> + foo(sizeof(decltype(a)*) + sizeof(decltype(b)*));
> + return 42;
> + };
> + };
> + };
> + return L;
> + }
> +};
> + X x;
> + auto L = x.test();
> + L('4');
> + auto M = L('3');
> + M('a');
> + auto N = M('x');
> + N("\n3 = ", 3, "\n6.14 = ", 6.14, "\n4'123'456 = ", 4'123'456);
> + char (*np)(const char*, int, const char*, double, const char*, int) = N;
> + np("\n3 = ", 3, "\n6.14 = ", 6.14, "\n4'123'456 = ", 4'123'456);
> +}
> +
> +{
> + struct X {
> + static void foo(double d) { }
> + auto test() {
> + auto L = [](auto a) {
> + print("a = ", a, "\n");
> + foo(a);
> + return [](decltype(a) b) {
> + foo(b);
> + foo(sizeof(a) + sizeof(b));
> + return [](auto ... c) {
> + print("c = ", c ..., "\n");
> + foo(decltype(b){});
> + foo(sizeof(decltype(a)*) + sizeof(decltype(b)*));
> + return [](decltype(c) ... d) ->decltype(a) { //expected-note{{candidate}}
> + print("d = ", d ..., "\n");
> + foo(decltype(b){});
> + foo(sizeof(decltype(a)*) + sizeof(decltype(b)*));
> + return decltype(a){};
> + };
> + };
> + };
> + };
> + return L;
> + }
> +};
> + X x;
> + auto L = x.test();
> + L('4');
> + auto M = L('3');
> + M('a');
> + auto N = M('x');
> + auto O = N("\n3 = ", 3, "\n6.14 = ", 6.14, "\n4'123'456 = ", 4'123'456);
> + char (*np)(const char*, int, const char*, double, const char*, int) = O;
> + np("\n3 = ", 3, "\n6.14 = ", 6.14, "\n4'123'456 = ", 4'123'456);
> + int (*np2)(const char*, int, const char*, double, const char*, int) = O; // expected-error{{no viable conversion}}
> +
> +}
> +} // end test()
> +
> +namespace wrapped_within_templates {
> +
> +namespace explicit_return {
> +template<class T> int fooT(T t) {
> + auto L = [](auto a) -> void {
> + auto M = [](char b) -> void {
> + auto N = [](auto c) -> void {
> + int x = 0;
> + x = sizeof(a);
> + x = sizeof(b);
> + x = sizeof(c);
> + };
> + N('a');
> + N(decltype(a){});
> + };
> + };
> + L(t);
> + L(3.14);
> + return 0;
> +}
> +
> +int run = fooT('a') + fooT(3.14);
> +
> +} // end explicit_return
> +
> +namespace implicit_return_deduction {
> +template<class T> auto fooT(T t) {
> + auto L = [](auto a) {
> + auto M = [](char b) {
> + auto N = [](auto c) {
> + int x = 0;
> + x = sizeof(a);
> + x = sizeof(b);
> + x = sizeof(c);
> + };
> + N('a');
> + N(decltype(a){});
> + };
> + };
> + L(t);
> + L(3.14);
> + return 0;
> +}
> +
> +int run = fooT('a') + fooT(3.14);
> +
> +template<class ... Ts> void print(Ts ... ts) { }
> +
> +template<class F, class ... Rest> using first = F;
> +
> +template<class ... Ts> auto fooV(Ts ... ts) {
> + auto L = [](auto ... a) {
> + auto M = [](decltype(a) ... b) {
> + auto N = [](auto c) {
> + int x = 0;
> + x = sizeof...(a);
> + x = sizeof...(b);
> + x = sizeof(c);
> + };
> + N('a');
> + N(N);
> + N(first<Ts...>{});
> + };
> + M(a...);
> + print("a = ", a..., "\n");
> + };
> + L(L, ts...);
> + print("ts = ", ts..., "\n");
> + return 0;
> +}
> +
> +int run2 = fooV(3.14, " ", '4', 5) + fooV("BC", 3, 2.77, 'A', float{}, short{}, unsigned{});
> +
> +} //implicit_return_deduction
> +
> +
> +} //wrapped_within_templates
> +
> +namespace at_ns_scope {
> + void foo(double d) { }
> + auto test() {
> + auto L = [](auto a) {
> + print("a = ", a, "\n");
> + foo(a);
> + return [](decltype(a) b) {
> + foo(b);
> + foo(sizeof(a) + sizeof(b));
> + return [](auto ... c) {
> + print("c = ", c ..., "\n");
> + foo(decltype(b){});
> + foo(sizeof(decltype(a)*) + sizeof(decltype(b)*));
> + return [](decltype(c) ... d) ->decltype(a) { //expected-note{{candidate}}
> + print("d = ", d ..., "\n");
> + foo(decltype(b){});
> + foo(sizeof(decltype(a)*) + sizeof(decltype(b)*));
> + return decltype(a){};
> + };
> + };
> + };
> + };
> + return L;
> + }
> +auto L = test();
> +auto L_test = L('4');
> +auto M = L('3');
> +auto M_test = M('a');
> +auto N = M('x');
> +auto O = N("\n3 = ", 3, "\n6.14 = ", 6.14, "\n4'123'456 = ", 4'123'456);
> +char (*np)(const char*, int, const char*, double, const char*, int) = O;
> +auto NP_result = np("\n3 = ", 3, "\n6.14 = ", 6.14, "\n4'123'456 = ", 4'123'456);
> +int (*np2)(const char*, int, const char*, double, const char*, int) = O; // expected-error{{no viable conversion}}
> +
> +
> +
> +}
> +
> +namespace variadic_tests_1 {
> +template<class ... Ts> void print(Ts ... ts) { }
> +
> +template<class F, class ... Rest> using FirstType = F;
> +template<class F, class ... Rest> F& FirstArg(F& f, Rest...) { return f; }
> +
> +template<class ... Ts> int fooV(Ts ... ts) {
> + auto L = [](auto ... a) -> void {
> + auto M = [](decltype(a) ... b) -> void {
> + auto N = [](auto c) -> void {
> + int x = 0;
> + x = sizeof...(a);
> + x = sizeof...(b);
> + x = sizeof(c);
> + };
> + N('a');
> + N(N);
> + N(FirstType<Ts...>{});
> + };
> + M(a...);
> + print("a = ", a..., "\n");
> + };
> + L(L, ts...);
> + print("ts = ", ts..., "\n");
> + return 0;
> +}
> +
> +int run2 = fooV(3.14, " ", '4', 5) + fooV("BC", 3, 2.77, 'A', float{}, short{}, unsigned{});
> +
> +namespace more_variadic_1 {
> +
> +template<class ... Ts> int fooV(Ts ... ts) {
> + auto L = [](auto ... a) {
> + auto M = [](decltype(a) ... b) -> void {
> + auto N = [](auto c) -> void {
> + int x = 0;
> + x = sizeof...(a);
> + x = sizeof...(b);
> + x = sizeof(c);
> + };
> + N('a');
> + N(N);
> + N(FirstType<Ts...>{});
> + };
> + M(a...);
> + return M;
> + };
> + auto M = L(L, ts...);
> + decltype(L(L, ts...)) (*fp)(decltype(L), decltype(ts) ...) = L;
> + void (*fp2)(decltype(L), decltype(ts) ...) = L(L, ts...);
> +
> + {
> + auto L = [](auto ... a) {
> + auto M = [](decltype(a) ... b) {
> + auto N = [](auto c) -> void {
> + int x = 0;
> + x = sizeof...(a);
> + x = sizeof...(b);
> + x = sizeof(c);
> + };
> + N('a');
> + N(N);
> + N(FirstType<Ts...>{});
> + return N;
> + };
> + M(a...);
> + return M;
> + };
> + auto M = L(L, ts...);
> + decltype(L(L, ts...)) (*fp)(decltype(L), decltype(ts) ...) = L;
> + fp(L, ts...);
> + decltype(L(L, ts...)(L, ts...)) (*fp2)(decltype(L), decltype(ts) ...) = L(L, ts...);
> + fp2 = fp(L, ts...);
> + void (*fp3)(char) = fp2(L, ts...);
> + fp3('a');
> + }
> + return 0;
> +}
> +
> +int run2 = fooV(3.14, " ", '4', 5) + fooV("BC", 3, 2.77, 'A', float{}, short{}, unsigned{});
> +
> +
> +} //end ns more_variadic_1
> +
> +} // end ns variadic_tests_1
> +
> +namespace at_ns_scope_within_class_member {
> + struct X {
> + static void foo(double d) { }
> + auto test() {
> + auto L = [](auto a) {
> + print("a = ", a, "\n");
> + foo(a);
> + return [](decltype(a) b) {
> + foo(b);
> + foo(sizeof(a) + sizeof(b));
> + return [](auto ... c) {
> + print("c = ", c ..., "\n");
> + foo(decltype(b){});
> + foo(sizeof(decltype(a)*) + sizeof(decltype(b)*));
> + return [](decltype(c) ... d) ->decltype(a) { //expected-note{{candidate}}
> + print("d = ", d ..., "\n");
> + foo(decltype(b){});
> + foo(sizeof(decltype(a)*) + sizeof(decltype(b)*));
> + return decltype(a){};
> + };
> + };
> + };
> + };
> + return L;
> + }
> +};
> +X x;
> +auto L = x.test();
> +auto L_test = L('4');
> +auto M = L('3');
> +auto M_test = M('a');
> +auto N = M('x');
> +auto O = N("\n3 = ", 3, "\n6.14 = ", 6.14, "\n4'123'456 = ", 4'123'456);
> +char (*np)(const char*, int, const char*, double, const char*, int) = O;
> +auto NP_result = np("\n3 = ", 3, "\n6.14 = ", 6.14, "\n4'123'456 = ", 4'123'456);
> +int (*np2)(const char*, int, const char*, double, const char*, int) = O; // expected-error{{no viable conversion}}
> +
> +} //end at_ns_scope_within_class_member
> +
> +
> +namespace nested_generic_lambdas_123 {
> +void test() {
> + auto L = [](auto a) -> int {
> + auto M = [](auto b, decltype(a) b2) -> int {
> + return 1;
> + };
> + M(a, a);
> + };
> + L(3);
> +}
> +template<class T> void foo(T) {
> + auto L = [](auto a) { return a; };
> +}
> +template void foo(int);
> +} // end ns nested_generic_lambdas_123
> +
> +
> +} // end ns nested_non_capturing_lambda_tests
> +
> \ No newline at end of file
>
>
> _______________________________________________
> cfe-commits mailing list
> cfe-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
More information about the cfe-commits
mailing list