<div>no worries - will take a look at it hopefully either this evening or this weekend!  I think it should be an easy fix.</div>
<div> </div>
<div>sorry!</div>
<div> </div>
<div>Faisal Vali<br><br></div><br><br>
<div class="gmail_quote">On Fri, Oct 4, 2013 at 9:46 AM, Rafael Espíndola <span dir="ltr"><<a href="mailto:rafael.espindola@gmail.com" target="_blank">rafael.espindola@gmail.com</a>></span> wrote:<br>
<blockquote style="BORDER-LEFT:#ccc 1px solid;MARGIN:0px 0px 0px 0.8ex;PADDING-LEFT:1ex" class="gmail_quote">Sorry, I reverted this because of <a href="http://llvm.org/pr17476" target="_blank">llvm.org/pr17476</a>.<br><br>
On 3 October 2013 02:29, Faisal Vali <<a href="mailto:faisalv@yahoo.com">faisalv@yahoo.com</a>> wrote:<br>> Author: faisalv<br>> Date: Thu Oct  3 01:29:33 2013<br>> New Revision: 191879<br>><br>> URL: <a href="http://llvm.org/viewvc/llvm-project?rev=191879&view=rev" target="_blank">http://llvm.org/viewvc/llvm-project?rev=191879&view=rev</a><br>
> Log:<br>> Teach TreeTransform and family how to transform generic lambdas within templates and nested within themselves.<br>><br>> This does not yet include capturing (that is next).<br>><br>> Please see test file for examples.<br>
><br>> This patch was LGTM'd by Doug:<br>> <a href="http://llvm-reviews.chandlerc.com/D1784" target="_blank">http://llvm-reviews.chandlerc.com/D1784</a><br>> <a href="http://lists.cs.uiuc.edu/pipermail/cfe-commits/Week-of-Mon-20130930/090048.html" target="_blank">http://lists.cs.uiuc.edu/pipermail/cfe-commits/Week-of-Mon-20130930/090048.html</a><br>
><br>> 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!)<br>
><br>> Modified:<br>>     cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp<br>>     cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp<br>>     cfe/trunk/lib/Sema/TreeTransform.h<br>>     cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/generic-lambda-unimplemented-1y.cpp<br>
>     cfe/trunk/test/SemaCXX/cxx1y-generic-lambdas.cpp<br>><br>> Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp<br>> URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp?rev=191879&r1=191878&r2=191879&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp?rev=191879&r1=191878&r2=191879&view=diff</a><br>
> ==============================================================================<br>> --- cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp (original)<br>> +++ cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp Thu Oct  3 01:29:33 2013<br>
> @@ -14,6 +14,7 @@<br>>  #include "TreeTransform.h"<br>>  #include "clang/AST/ASTConsumer.h"<br>>  #include "clang/AST/ASTContext.h"<br>> +#include "clang/AST/ASTLambda.h"<br>
>  #include "clang/AST/DeclTemplate.h"<br>>  #include "clang/AST/Expr.h"<br>>  #include "clang/Basic/LangOptions.h"<br>> @@ -130,6 +131,11 @@ Sema::getTemplateInstantiationArgs(Named<br>
>          assert(Function->getPrimaryTemplate() && "No function template?");<br>>          if (Function->getPrimaryTemplate()->isMemberSpecialization())<br>>            break;<br>> +<br>
> +        // If this function is a generic lambda specialization, we are done.<br>> +        if (isGenericLambdaCallOperatorSpecialization(Function))<br>> +          break;<br>> +<br>>        } else if (FunctionTemplateDecl *FunTmpl<br>
>                                     = Function->getDescribedFunctionTemplate()) {<br>>          // Add the "injected" template arguments.<br>> @@ -911,13 +917,56 @@ namespace {<br>>      }<br>><br>
>      ExprResult TransformLambdaScope(LambdaExpr *E,<br>> -                                    CXXMethodDecl *CallOperator) {<br>> -      CallOperator->setInstantiationOfMemberFunction(E->getCallOperator(),<br>
> -                                                     TSK_ImplicitInstantiation);<br>> -      return TreeTransform<TemplateInstantiator>::<br>> -         TransformLambdaScope(E, CallOperator);<br>> +                                    CXXMethodDecl *NewCallOperator) {<br>
> +      // If a lambda is undergoing transformation for instance in the<br>> +      // call to foo('a') below:<br>> +      //  template<class T> void foo(T t) {<br>> +      //    auto L1 = [](T a) { return a; };<br>
> +      //    auto L2 = [](char b) { return b; };<br>> +      //    auto L3 = [](auto c) { return c; };<br>> +      //  }<br>> +      // The AST nodes of the OldCallOperators within the primary template foo<br>
> +      // are connected to the NewCallOperators within the specialization of foo.<br>> +      //  - In the case of L1 and L2 we set the NewCallOperator to be considered<br>> +      //    an instantiation of the OldCallOperator.<br>
> +      //  - In the generic lambda case, we set the NewTemplate to be considered<br>> +      //    an "instantiation" of the OldTemplate.<br>> +      // See the documentation and use of get/setInstantiationOfMemberFunction<br>
> +      // and get/setInstantiatedFromMemberTemplate to appreciate the relevance<br>> +      // of creating these links.<br>> +      // And so it goes on and on with nested generic lambdas.<br>> +      CXXMethodDecl *const OldCallOperator = E->getCallOperator();<br>
> +      FunctionTemplateDecl *const NewCallOperatorTemplate =<br>> +          NewCallOperator->getDescribedFunctionTemplate();<br>> +      FunctionTemplateDecl *const OldCallOperatorTemplate =<br>> +          OldCallOperator->getDescribedFunctionTemplate();<br>
> +<br>> +      if (!NewCallOperatorTemplate)<br>> +        NewCallOperator->setInstantiationOfMemberFunction(OldCallOperator,<br>> +                                                    TSK_ImplicitInstantiation);<br>
> +      else {<br>> +        NewCallOperatorTemplate->setInstantiatedFromMemberTemplate(<br>> +                                                      OldCallOperatorTemplate);<br>> +        // Set this as a specialization so we don't go digging into the<br>
> +        // OldCallOperatorTemplate when retrieving the<br>> +        // 'FunctionDecl::getTemplateInstantiationPattern()'<br>> +        NewCallOperatorTemplate->setMemberSpecialization();<br>> +      }<br>
> +      return inherited::TransformLambdaScope(E, NewCallOperator);<br>> +    }<br>> +    TemplateParameterList *TransformTemplateParameterList(<br>> +                              TemplateParameterList *OrigTPL)  {<br>
> +      TemplateParameterList *NewTPL = 0;<br>> +      if (OrigTPL) {<br>> +        if (!OrigTPL->size()) return OrigTPL; // size 0, do nothing<br>> +<br>> +        DeclContext *Owner = OrigTPL->getParam(0)->getDeclContext();<br>
> +        TemplateDeclInstantiator  DeclInstantiator(getSema(),<br>> +                          /* DeclContext *Owner */ Owner, TemplateArgs);<br>> +        NewTPL = DeclInstantiator.SubstTemplateParams(OrigTPL);<br>
> +      }<br>> +      return NewTPL;<br>>      }<br>> -<br>>    private:<br>>      ExprResult transformNonTypeTemplateParmRef(NonTypeTemplateParmDecl *parm,<br>>                                                 SourceLocation loc,<br>
><br>> Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp<br>> URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp?rev=191879&r1=191878&r2=191879&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp?rev=191879&r1=191878&r2=191879&view=diff</a><br>
> ==============================================================================<br>> --- cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp (original)<br>> +++ cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp Thu Oct  3 01:29:33 2013<br>
> @@ -4171,6 +4171,30 @@ DeclContext *Sema::FindInstantiatedConte<br>>  NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D,<br>>                            const MultiLevelTemplateArgumentList &TemplateArgs) {<br>
>    DeclContext *ParentDC = D->getDeclContext();<br>> +<br>> +  // If we have a parameter from a non-dependent context with a non-dependent<br>> +  // type it obviously can not be mapped to a different instantiated decl.<br>
> +  // Consider the code below, with explicit return types, when N gets<br>> +  // specialized ...:<br>> +  // template<class T> void fooT(T t) {<br>> +  //   auto L = [](auto a) -> void {<br>> +  //     auto M = [](char b) -> void {<br>
> +  //       auto N = [](auto c) -> void {<br>> +  //         int x = sizeof(a) + sizeof(b) +<br>> +  //                 sizeof(c);<br>> +  //       };<br>> +  //       N('a');<br>> +  //     };<br>
> +  //   };<br>> +  //   L(3.14);<br>> +  // }<br>> +  // fooT('a');<br>> +  // ... without this check below, findInstantiationOf fails with<br>> +  // an assertion violation.<br>> +  if (isa<ParmVarDecl>(D) && !ParentDC->isDependentContext() &&<br>
> +      !cast<ParmVarDecl>(D)->getType()->isInstantiationDependentType())<br>> +    return D;<br>> +<br>>    if (isa<ParmVarDecl>(D) || isa<NonTypeTemplateParmDecl>(D) ||<br>>        isa<TemplateTypeParmDecl>(D) || isa<TemplateTemplateParmDecl>(D) ||<br>
>        (ParentDC->isFunctionOrMethod() && ParentDC->isDependentContext()) ||<br>><br>> Modified: cfe/trunk/lib/Sema/TreeTransform.h<br>> URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/TreeTransform.h?rev=191879&r1=191878&r2=191879&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/TreeTransform.h?rev=191879&r1=191878&r2=191879&view=diff</a><br>
> ==============================================================================<br>> --- cfe/trunk/lib/Sema/TreeTransform.h (original)<br>> +++ cfe/trunk/lib/Sema/TreeTransform.h Thu Oct  3 01:29:33 2013<br>> @@ -33,6 +33,7 @@<br>
>  #include "clang/Sema/ScopeInfo.h"<br>>  #include "clang/Sema/SemaDiagnostic.h"<br>>  #include "clang/Sema/SemaInternal.h"<br>> +#include "clang/Sema/Template.h"<br>>  #include "llvm/ADT/ArrayRef.h"<br>
>  #include "llvm/Support/ErrorHandling.h"<br>>  #include <algorithm><br>> @@ -594,6 +595,11 @@ public:<br>>    /// \brief Transform the captures and body of a lambda expression.<br>>    ExprResult TransformLambdaScope(LambdaExpr *E, CXXMethodDecl *CallOperator);<br>
><br>> +  TemplateParameterList *TransformTemplateParameterList(<br>> +        TemplateParameterList *TPL) {<br>> +    return TPL;<br>> +  }<br>> +<br>>    ExprResult TransformAddressOfOperand(Expr *E);<br>
>    ExprResult TransformDependentScopeDeclRefExpr(DependentScopeDeclRefExpr *E,<br>>                                                  bool IsAddressOfOperand);<br>> @@ -4573,6 +4579,19 @@ template<typename Derived><br>
>  QualType TreeTransform<Derived>::TransformDecltypeType(TypeLocBuilder &TLB,<br>>                                                         DecltypeTypeLoc TL) {<br>>    const DecltypeType *T = TL.getTypePtr();<br>
> +  // Don't transform a decltype construct that has already been transformed<br>> +  // into a non-dependent type.<br>> +  // Allows the following to compile:<br>> +  // auto L = [](auto a) {<br>> +  //   return [](auto b) ->decltype(a) {<br>
> +  //     return b;<br>> +  //  };<br>> +  //};<br>> +  if (!T->isInstantiationDependentType()) {<br>> +    DecltypeTypeLoc NewTL = TLB.push<DecltypeTypeLoc>(TL.getType());<br>> +    NewTL.setNameLoc(TL.getNameLoc());<br>
> +    return NewTL.getType();<br>> +  }<br>><br>>    // decltype expressions are not potentially evaluated contexts<br>>    EnterExpressionEvaluationContext Unevaluated(SemaRef, Sema::Unevaluated, 0,<br>> @@ -8284,24 +8303,27 @@ template<typename Derived><br>
>  ExprResult<br>>  TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {<br>><br>> -  // FIXME: Implement nested generic lambda transformations.<br>> -  if (E->isGenericLambda()) {<br>> -    getSema().Diag(E->getIntroducerRange().getBegin(),<br>
> -      diag::err_glambda_not_fully_implemented)<br>> -      << " template transformation of generic lambdas not implemented yet";<br>> -    return ExprError();<br>> -  }<br>> -  // Transform the type of the lambda parameters and start the definition of<br>
> -  // the lambda itself.<br>> -  TypeSourceInfo *MethodTy<br>> -    = TransformType(E->getCallOperator()->getTypeSourceInfo());<br>> -  if (!MethodTy)<br>> +  getSema().PushLambdaScope();<br>> +  LambdaScopeInfo *LSI = getSema().getCurLambda();<br>
> +  TemplateParameterList *const OrigTPL = E->getTemplateParameterList();<br>> +  TemplateParameterList *NewTPL = 0;<br>> +  // Transform the template parameters, and add them to the<br>> +  // current instantiation scope.<br>
> +  if (OrigTPL) {<br>> +      NewTPL = getDerived().TransformTemplateParameterList(OrigTPL);<br>> +  }<br>> +  LSI->GLTemplateParameterList = NewTPL;<br>> +   // Transform the type of the lambda parameters and start the definition of<br>
> +   // the lambda itself.<br>> +  TypeSourceInfo *OldCallOpTSI = E->getCallOperator()->getTypeSourceInfo();<br>> +  TypeSourceInfo *NewCallOpTSI = TransformType(OldCallOpTSI);<br>> +  if (!NewCallOpTSI)<br>
>      return ExprError();<br>><br>>    // Create the local class that will describe the lambda.<br>>    CXXRecordDecl *Class<br>>      = getSema().createLambdaClosureType(E->getIntroducerRange(),<br>> -                                        MethodTy,<br>
> +                                        NewCallOpTSI,<br>>                                          /*KnownDependent=*/false);<br>>    getDerived().transformedLocalDecl(E->getLambdaClass(), Class);<br>><br>
> @@ -8313,19 +8335,49 @@ TreeTransform<Derived>::TransformLambdaE<br>>          E->getCallOperator()->param_size(),<br>>          0, ParamTypes, &Params))<br>>      return ExprError();<br>> -  getSema().PushLambdaScope();<br>
> -  LambdaScopeInfo *LSI = getSema().getCurLambda();<br>> -  // TODO: Fix for nested lambdas<br>> -  LSI->GLTemplateParameterList = 0;<br>> +<br>>    // Build the call operator.<br>> -  CXXMethodDecl *CallOperator<br>
> +  CXXMethodDecl *NewCallOperator<br>>      = getSema().startLambdaDefinition(Class, E->getIntroducerRange(),<br>> -                                      MethodTy,<br>> +                                      NewCallOpTSI,<br>
>                                        E->getCallOperator()->getLocEnd(),<br>>                                        Params);<br>> -  getDerived().transformAttrs(E->getCallOperator(), CallOperator);<br>
> -<br>> -  return getDerived().TransformLambdaScope(E, CallOperator);<br>> +  LSI->CallOperator = NewCallOperator;<br>> +  // Fix the Decl Contexts of the parameters within the call op function<br>> +  // prototype.<br>
> +  getDerived().transformAttrs(E->getCallOperator(), NewCallOperator);<br>> +<br>> +  TypeLoc NewCallOpTL = NewCallOpTSI->getTypeLoc();<br>> +  FunctionProtoTypeLoc NewFPTL = NewCallOpTL.castAs<FunctionProtoTypeLoc>();<br>
> +  ParmVarDecl **NewParamDeclArray = NewFPTL.getParmArray();<br>> +  const unsigned NewNumArgs = NewFPTL.getNumArgs();<br>> +  for (unsigned I = 0; I < NewNumArgs; ++I) {<br>> +      NewParamDeclArray[I]->setOwningFunction(NewCallOperator);<br>
> +  }<br>> +  // If this is a non-generic lambda, the parameters do not get added to the<br>> +  // current instantiation scope, so add them.  This feels kludgey.<br>> +  // Anyway, it allows the following to compile when the enclosing template<br>
> +  // is specialized and the entire lambda expression has to be<br>> +  // transformed.  Without this FindInstantiatedDecl causes an assertion.<br>> +  // template<class T> void foo(T t) {<br>> +  //    auto L = [](auto a) {<br>
> +  //      auto M = [](char b) { <-- note: non-generic lambda<br>> +  //        auto N = [](auto c) {<br>> +  //          int x = sizeof(a);<br>> +  //          x = sizeof(b); <-- specifically this line<br>
> +  //          x = sizeof(c);<br>> +  //        };<br>> +  //      };<br>> +  //    };<br>> +  //  }<br>> +  //  foo('a');<br>> +  //<br>> +  if (!E->isGenericLambda()) {<br>> +    for (unsigned I = 0; I < NewNumArgs; ++I)<br>
> +      SemaRef.CurrentInstantiationScope->InstantiatedLocal(<br>> +                                   NewParamDeclArray[I], NewParamDeclArray[I]);<br>> +  }<br>> +  return getDerived().TransformLambdaScope(E, NewCallOperator);<br>
>  }<br>><br>>  template<typename Derived><br>><br>> Modified: cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/generic-lambda-unimplemented-1y.cpp<br>> URL: <a href="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" target="_blank">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</a><br>
> ==============================================================================<br>> --- cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/generic-lambda-unimplemented-1y.cpp (original)<br>> +++ cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/generic-lambda-unimplemented-1y.cpp Thu Oct  3 01:29:33 2013<br>
> @@ -29,20 +29,3 @@ void test() {<br>><br>>  }<br>><br>> -namespace nested_generic_lambdas {<br>> -void test() {<br>> -  auto L = [](auto a) -> int {<br>> -    auto M = [](auto b, decltype(a) b2) -> int { //expected-error{{unimplemented}}<br>
> -      return 1;<br>> -    };<br>> -    M(a, a);<br>> -  };<br>> -  L(3); //expected-note{{in instantiation of}}<br>> -}<br>> -template<class T> void foo(T) {<br>> - auto L = [](auto a) { return a; }; //expected-error{{unimplemented}}<br>
> -}<br>> -template void foo(int); //expected-note{{in instantiation of}}<br>> -}<br>> -<br>> -<br>><br>> Modified: cfe/trunk/test/SemaCXX/cxx1y-generic-lambdas.cpp<br>> URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/cxx1y-generic-lambdas.cpp?rev=191879&r1=191878&r2=191879&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/cxx1y-generic-lambdas.cpp?rev=191879&r1=191878&r2=191879&view=diff</a><br>
> ==============================================================================<br>> --- cfe/trunk/test/SemaCXX/cxx1y-generic-lambdas.cpp (original)<br>> +++ cfe/trunk/test/SemaCXX/cxx1y-generic-lambdas.cpp Thu Oct  3 01:29:33 2013<br>
> @@ -1,4 +1,4 @@<br>> -// RUN: %clang_cc1 -std=c++1y -verify -fsyntax-only -fblocks %s<br>> +// RUN: %clang_cc1 -std=c++1y -verify -fsyntax-only -fblocks -emit-llvm -o - %s<br>>  // DONTRUNYET: %clang_cc1 -std=c++1y -verify -fsyntax-only -fblocks -fdelayed-template-parsing %s -DDELAYED_TEMPLATE_PARSING<br>
>  // DONTRUNYET: %clang_cc1 -std=c++1y -verify -fsyntax-only -fblocks -fms-extensions %s -DMS_EXTENSIONS<br>>  // DONTRUNYET: %clang_cc1 -std=c++1y -verify -fsyntax-only -fblocks -fdelayed-template-parsing -fms-extensions %s -DMS_EXTENSIONS -DDELAYED_TEMPLATE_PARSING<br>
> @@ -99,10 +99,8 @@ void test() {<br>>                                                    //expected-note{{candidate}}<br>>    }<br>>  }<br>> -<br>>  }<br>><br>> -<br>>  namespace return_type_deduction_ok {<br>
>   auto l = [](auto a) ->auto { return a; }(2);<br>>   auto l2 = [](auto a) ->decltype(auto) { return a; }(2);<br>> @@ -114,3 +112,479 @@ namespace generic_lambda_as_default_argu<br>>    void test(int i = [](auto a)->int { return a; }(3)) {<br>
>    }<br>>  }<br>> +<br>> +namespace nested_non_capturing_lambda_tests {<br>> +template<class ... Ts> void print(Ts ...) { }<br>> +int test() {<br>> +{<br>> +  auto L = [](auto a) {<br>> +    return [](auto b) {<br>
> +      return b;<br>> +    };<br>> +  };<br>> +  auto M = L(3);<br>> +  M(4.15);<br>> + }<br>> +{<br>> +  int i = 10; //expected-note{{declared here}}<br>> +  auto L = [](auto a) {<br>> +    return [](auto b) { //expected-note{{begins here}}<br>
> +      i = b;  //expected-error{{cannot be implicitly captured}}<br>> +      return b;<br>> +    };<br>> +  };<br>> +  auto M = L(3);<br>> +  M(4.15); //expected-note{{instantiation}}<br>> + }<br>> + {<br>
> +  auto L = [](auto a) {<br>> +    print("a = ", a, "\n");<br>> +    return [](auto b) ->decltype(a) {<br>> +      print("b = ", b, "\n");<br>> +      return b;<br>
> +    };<br>> +  };<br>> +  auto M = L(3);<br>> +  M(4.15);<br>> + }<br>> +<br>> +{<br>> +  auto L = [](auto a) ->decltype(a) {<br>> +    print("a = ", a, "\n");<br>> +    return [](auto b) ->decltype(a) { //expected-error{{no viable conversion}}\<br>
> +                                      //expected-note{{candidate template ignored}}<br>> +      print("b = ", b, "\n");<br>> +      return b;<br>> +    };<br>> +  };<br>> +  auto M = L(3); //expected-note{{in instantiation of}}<br>
> + }<br>> +{<br>> +  auto L = [](auto a) {<br>> +    print("a = ", a, "\n");<br>> +    return [](auto ... b) ->decltype(a) {<br>> +      print("b = ", b ..., "\n");<br>
> +      return 4;<br>> +    };<br>> +  };<br>> +  auto M = L(3);<br>> +  M(4.15, 3, "fv");<br>> +}<br>> +<br>> +{<br>> +  auto L = [](auto a) {<br>> +    print("a = ", a, "\n");<br>
> +    return [](auto ... b) ->decltype(a) {<br>> +      print("b = ", b ..., "\n");<br>> +      return 4;<br>> +    };<br>> +  };<br>> +  auto M = L(3);<br>> +  int (*fp)(double, int, const char*) = M;<br>
> +  fp(4.15, 3, "fv");<br>> +}<br>> +<br>> +{<br>> +  auto L = [](auto a) {<br>> +    print("a = ", a, "\n");<br>> +    return [](char b) {<br>> +      return [](auto ... c) ->decltype(b) {<br>
> +        print("c = ", c ..., "\n");<br>> +        return 42;<br>> +      };<br>> +    };<br>> +  };<br>> +  L(4);<br>> +  auto M = L(3);<br>> +  M('a');<br>> +  auto N = M('x');<br>
> +  N("\n3 = ", 3, "\n6.14 = ", 6.14, "\n4'123'456 = ", 4'123'456);<br>> +  char (*np)(const char*, int, const char*, double, const char*, int) = N;<br>> +  np("\n3 = ", 3, "\n6.14 = ", 6.14, "\n4'123'456 = ", 4'123'456);<br>
> +}<br>> +<br>> +<br>> +{<br>> +  auto L = [](auto a) {<br>> +    print("a = ", a, "\n");<br>> +    return [](decltype(a) b) {<br>> +      return [](auto ... c) ->decltype(b) {<br>
> +        print("c = ", c ..., "\n");<br>> +        return 42;<br>> +      };<br>> +    };<br>> +  };<br>> +  L('4');<br>> +  auto M = L('3');<br>> +  M('a');<br>
> +  auto N = M('x');<br>> +  N("\n3 = ", 3, "\n6.14 = ", 6.14, "\n4'123'456 = ", 4'123'456);<br>> +  char (*np)(const char*, int, const char*, double, const char*, int) = N;<br>
> +  np("\n3 = ", 3, "\n6.14 = ", 6.14, "\n4'123'456 = ", 4'123'456);<br>> +}<br>> +<br>> +<br>> +{<br>> + struct X {<br>> +  static void foo(double d) { }<br>
> +  void test() {<br>> +    auto L = [](auto a) {<br>> +      print("a = ", a, "\n");<br>> +      foo(a);<br>> +      return [](decltype(a) b) {<br>> +        foo(b);<br>> +        foo(sizeof(a) + sizeof(b));<br>
> +        return [](auto ... c) ->decltype(b) {<br>> +          print("c = ", c ..., "\n");<br>> +          foo(decltype(b){});<br>> +          foo(sizeof(decltype(a)*) + sizeof(decltype(b)*));<br>
> +          return 42;<br>> +        };<br>> +      };<br>> +    };<br>> +    L('4');<br>> +    auto M = L('3');<br>> +    M('a');<br>> +    auto N = M('x');<br>> +    N("\n3 = ", 3, "\n6.14 = ", 6.14, "\n4'123'456 = ", 4'123'456);<br>
> +    char (*np)(const char*, int, const char*, double, const char*, int) = N;<br>> +    np("\n3 = ", 3, "\n6.14 = ", 6.14, "\n4'123'456 = ", 4'123'456);<br>> +  }<br>
> +};<br>> +X x;<br>> +x.test();<br>> +}<br>> +// Make sure we can escape the function<br>> +{<br>> + struct X {<br>> +  static void foo(double d) { }<br>> +  auto test() {<br>> +    auto L = [](auto a) {<br>
> +      print("a = ", a, "\n");<br>> +      foo(a);<br>> +      return [](decltype(a) b) {<br>> +        foo(b);<br>> +        foo(sizeof(a) + sizeof(b));<br>> +        return [](auto ... c) ->decltype(b) {<br>
> +          print("c = ", c ..., "\n");<br>> +          foo(decltype(b){});<br>> +          foo(sizeof(decltype(a)*) + sizeof(decltype(b)*));<br>> +          return 42;<br>> +        };<br>
> +      };<br>> +    };<br>> +    return L;<br>> +  }<br>> +};<br>> +  X x;<br>> +  auto L = x.test();<br>> +  L('4');<br>> +  auto M = L('3');<br>> +  M('a');<br>> +  auto N = M('x');<br>
> +  N("\n3 = ", 3, "\n6.14 = ", 6.14, "\n4'123'456 = ", 4'123'456);<br>> +  char (*np)(const char*, int, const char*, double, const char*, int) = N;<br>> +  np("\n3 = ", 3, "\n6.14 = ", 6.14, "\n4'123'456 = ", 4'123'456);<br>
> +}<br>> +<br>> +{<br>> + struct X {<br>> +  static void foo(double d) { }<br>> +  auto test() {<br>> +    auto L = [](auto a) {<br>> +      print("a = ", a, "\n");<br>> +      foo(a);<br>
> +      return [](decltype(a) b) {<br>> +        foo(b);<br>> +        foo(sizeof(a) + sizeof(b));<br>> +        return [](auto ... c) {<br>> +          print("c = ", c ..., "\n");<br>> +          foo(decltype(b){});<br>
> +          foo(sizeof(decltype(a)*) + sizeof(decltype(b)*));<br>> +          return [](decltype(c) ... d) ->decltype(a) { //expected-note{{candidate}}<br>> +            print("d = ", d ..., "\n");<br>
> +            foo(decltype(b){});<br>> +            foo(sizeof(decltype(a)*) + sizeof(decltype(b)*));<br>> +            return decltype(a){};<br>> +          };<br>> +        };<br>> +      };<br>> +    };<br>
> +    return L;<br>> +  }<br>> +};<br>> +  X x;<br>> +  auto L = x.test();<br>> +  L('4');<br>> +  auto M = L('3');<br>> +  M('a');<br>> +  auto N = M('x');<br>> +  auto O = N("\n3 = ", 3, "\n6.14 = ", 6.14, "\n4'123'456 = ", 4'123'456);<br>
> +  char (*np)(const char*, int, const char*, double, const char*, int) = O;<br>> +  np("\n3 = ", 3, "\n6.14 = ", 6.14, "\n4'123'456 = ", 4'123'456);<br>> +  int (*np2)(const char*, int, const char*, double, const char*, int) = O; // expected-error{{no viable conversion}}<br>
> +<br>> +}<br>> +} // end test()<br>> +<br>> +namespace wrapped_within_templates {<br>> +<br>> +namespace explicit_return {<br>> +template<class T> int fooT(T t) {<br>> +  auto L = [](auto a) -> void {<br>
> +    auto M = [](char b) -> void {<br>> +      auto N = [](auto c) -> void {<br>> +        int x = 0;<br>> +        x = sizeof(a);<br>> +        x = sizeof(b);<br>> +        x = sizeof(c);<br>> +      };<br>
> +      N('a');<br>> +      N(decltype(a){});<br>> +    };<br>> +  };<br>> +  L(t);<br>> +  L(3.14);<br>> +  return 0;<br>> +}<br>> +<br>> +int run = fooT('a') + fooT(3.14);<br>
> +<br>> +} // end explicit_return<br>> +<br>> +namespace implicit_return_deduction {<br>> +template<class T> auto fooT(T t) {<br>> +  auto L = [](auto a)  {<br>> +    auto M = [](char b)  {<br>
> +      auto N = [](auto c)  {<br>> +        int x = 0;<br>> +        x = sizeof(a);<br>> +        x = sizeof(b);<br>> +        x = sizeof(c);<br>> +      };<br>> +      N('a');<br>> +      N(decltype(a){});<br>
> +    };<br>> +  };<br>> +  L(t);<br>> +  L(3.14);<br>> +  return 0;<br>> +}<br>> +<br>> +int run = fooT('a') + fooT(3.14);<br>> +<br>> +template<class ... Ts> void print(Ts ... ts) { }<br>
> +<br>> +template<class F, class ... Rest> using first = F;<br>> +<br>> +template<class ... Ts> auto fooV(Ts ... ts) {<br>> +  auto L = [](auto ... a) {<br>> +    auto M = [](decltype(a) ... b) {<br>
> +      auto N = [](auto c) {<br>> +        int x = 0;<br>> +        x = sizeof...(a);<br>> +        x = sizeof...(b);<br>> +        x = sizeof(c);<br>> +      };<br>> +      N('a');<br>> +      N(N);<br>
> +      N(first<Ts...>{});<br>> +    };<br>> +    M(a...);<br>> +    print("a = ", a..., "\n");<br>> +  };<br>> +  L(L, ts...);<br>> +  print("ts = ", ts..., "\n");<br>
> +  return 0;<br>> +}<br>> +<br>> +int run2 = fooV(3.14, " ", '4', 5) + fooV("BC", 3, 2.77, 'A', float{}, short{}, unsigned{});<br>> +<br>> +} //implicit_return_deduction<br>
> +<br>> +<br>> +} //wrapped_within_templates<br>> +<br>> +namespace at_ns_scope {<br>> +  void foo(double d) { }<br>> +  auto test() {<br>> +    auto L = [](auto a) {<br>> +      print("a = ", a, "\n");<br>
> +      foo(a);<br>> +      return [](decltype(a) b) {<br>> +        foo(b);<br>> +        foo(sizeof(a) + sizeof(b));<br>> +        return [](auto ... c) {<br>> +          print("c = ", c ..., "\n");<br>
> +          foo(decltype(b){});<br>> +          foo(sizeof(decltype(a)*) + sizeof(decltype(b)*));<br>> +          return [](decltype(c) ... d) ->decltype(a) { //expected-note{{candidate}}<br>> +            print("d = ", d ..., "\n");<br>
> +            foo(decltype(b){});<br>> +            foo(sizeof(decltype(a)*) + sizeof(decltype(b)*));<br>> +            return decltype(a){};<br>> +          };<br>> +        };<br>> +      };<br>> +    };<br>
> +    return L;<br>> +  }<br>> +auto L = test();<br>> +auto L_test = L('4');<br>> +auto M = L('3');<br>> +auto M_test = M('a');<br>> +auto N = M('x');<br>> +auto O = N("\n3 = ", 3, "\n6.14 = ", 6.14, "\n4'123'456 = ", 4'123'456);<br>
> +char (*np)(const char*, int, const char*, double, const char*, int) = O;<br>> +auto NP_result = np("\n3 = ", 3, "\n6.14 = ", 6.14, "\n4'123'456 = ", 4'123'456);<br>> +int (*np2)(const char*, int, const char*, double, const char*, int) = O; // expected-error{{no viable conversion}}<br>
> +<br>> +<br>> +<br>> +}<br>> +<br>> +namespace variadic_tests_1 {<br>> +template<class ... Ts> void print(Ts ... ts) { }<br>> +<br>> +template<class F, class ... Rest> using FirstType = F;<br>
> +template<class F, class ... Rest> F& FirstArg(F& f, Rest...) { return f; }<br>> +<br>> +template<class ... Ts> int fooV(Ts ... ts) {<br>> +  auto L = [](auto ... a) -> void {<br>> +    auto M = [](decltype(a) ... b) -> void {<br>
> +      auto N = [](auto c) -> void {<br>> +        int x = 0;<br>> +        x = sizeof...(a);<br>> +        x = sizeof...(b);<br>> +        x = sizeof(c);<br>> +      };<br>> +      N('a');<br>
> +      N(N);<br>> +      N(FirstType<Ts...>{});<br>> +    };<br>> +    M(a...);<br>> +    print("a = ", a..., "\n");<br>> +  };<br>> +  L(L, ts...);<br>> +  print("ts = ", ts..., "\n");<br>
> +  return 0;<br>> +}<br>> +<br>> +int run2 = fooV(3.14, " ", '4', 5) + fooV("BC", 3, 2.77, 'A', float{}, short{}, unsigned{});<br>> +<br>> +namespace more_variadic_1 {<br>
> +<br>> +template<class ... Ts> int fooV(Ts ... ts) {<br>> +  auto L = [](auto ... a) {<br>> +    auto M = [](decltype(a) ... b) -> void {<br>> +      auto N = [](auto c) -> void {<br>> +        int x = 0;<br>
> +        x = sizeof...(a);<br>> +        x = sizeof...(b);<br>> +        x = sizeof(c);<br>> +      };<br>> +      N('a');<br>> +      N(N);<br>> +      N(FirstType<Ts...>{});<br>> +    };<br>
> +    M(a...);<br>> +    return M;<br>> +  };<br>> +  auto M = L(L, ts...);<br>> +  decltype(L(L, ts...)) (*fp)(decltype(L), decltype(ts) ...) = L;<br>> +  void (*fp2)(decltype(L), decltype(ts) ...) = L(L, ts...);<br>
> +<br>> +  {<br>> +    auto L = [](auto ... a) {<br>> +      auto M = [](decltype(a) ... b) {<br>> +        auto N = [](auto c) -> void {<br>> +          int x = 0;<br>> +          x = sizeof...(a);<br>
> +          x = sizeof...(b);<br>> +          x = sizeof(c);<br>> +        };<br>> +        N('a');<br>> +        N(N);<br>> +        N(FirstType<Ts...>{});<br>> +        return N;<br>> +      };<br>
> +      M(a...);<br>> +      return M;<br>> +    };<br>> +    auto M = L(L, ts...);<br>> +    decltype(L(L, ts...)) (*fp)(decltype(L), decltype(ts) ...) = L;<br>> +    fp(L, ts...);<br>> +    decltype(L(L, ts...)(L, ts...)) (*fp2)(decltype(L), decltype(ts) ...) = L(L, ts...);<br>
> +    fp2 = fp(L, ts...);<br>> +    void (*fp3)(char) = fp2(L, ts...);<br>> +    fp3('a');<br>> +  }<br>> +  return 0;<br>> +}<br>> +<br>> +int run2 = fooV(3.14, " ", '4', 5) + fooV("BC", 3, 2.77, 'A', float{}, short{}, unsigned{});<br>
> +<br>> +<br>> +} //end ns more_variadic_1<br>> +<br>> +} // end ns variadic_tests_1<br>> +<br>> +namespace at_ns_scope_within_class_member {<br>> + struct X {<br>> +  static void foo(double d) { }<br>
> +  auto test() {<br>> +    auto L = [](auto a) {<br>> +      print("a = ", a, "\n");<br>> +      foo(a);<br>> +      return [](decltype(a) b) {<br>> +        foo(b);<br>> +        foo(sizeof(a) + sizeof(b));<br>
> +        return [](auto ... c) {<br>> +          print("c = ", c ..., "\n");<br>> +          foo(decltype(b){});<br>> +          foo(sizeof(decltype(a)*) + sizeof(decltype(b)*));<br>> +          return [](decltype(c) ... d) ->decltype(a) { //expected-note{{candidate}}<br>
> +            print("d = ", d ..., "\n");<br>> +            foo(decltype(b){});<br>> +            foo(sizeof(decltype(a)*) + sizeof(decltype(b)*));<br>> +            return decltype(a){};<br>
> +          };<br>> +        };<br>> +      };<br>> +    };<br>> +    return L;<br>> +  }<br>> +};<br>> +X x;<br>> +auto L = x.test();<br>> +auto L_test = L('4');<br>> +auto M = L('3');<br>
> +auto M_test = M('a');<br>> +auto N = M('x');<br>> +auto O = N("\n3 = ", 3, "\n6.14 = ", 6.14, "\n4'123'456 = ", 4'123'456);<br>> +char (*np)(const char*, int, const char*, double, const char*, int) = O;<br>
> +auto NP_result = np("\n3 = ", 3, "\n6.14 = ", 6.14, "\n4'123'456 = ", 4'123'456);<br>> +int (*np2)(const char*, int, const char*, double, const char*, int) = O; // expected-error{{no viable conversion}}<br>
> +<br>> +} //end at_ns_scope_within_class_member<br>> +<br>> +<br>> +namespace nested_generic_lambdas_123 {<br>> +void test() {<br>> +  auto L = [](auto a) -> int {<br>> +    auto M = [](auto b, decltype(a) b2) -> int {<br>
> +      return 1;<br>> +    };<br>> +    M(a, a);<br>> +  };<br>> +  L(3);<br>> +}<br>> +template<class T> void foo(T) {<br>> + auto L = [](auto a) { return a; };<br>> +}<br>> +template void foo(int);<br>
> +} // end ns nested_generic_lambdas_123<br>> +<br>> +<br>> +} // end ns nested_non_capturing_lambda_tests<br>> +<br>> \ No newline at end of file<br>><br>><br>> _______________________________________________<br>
> cfe-commits mailing list<br>> <a href="mailto:cfe-commits@cs.uiuc.edu">cfe-commits@cs.uiuc.edu</a><br>> <a href="http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits" target="_blank">http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits</a><br>
</blockquote></div><br>