r191879 - Teach TreeTransform and family how to transform generic lambdas within templates and nested within themselves.

Faisal Vali faisalv at gmail.com
Fri Oct 4 08:21:46 PDT 2013


no worries - will take a look at it hopefully either this evening or this
weekend!  I think it should be an easy fix.

sorry!

Faisal Vali



On Fri, Oct 4, 2013 at 9:46 AM, Rafael EspĂ­ndola <rafael.espindola at gmail.com
> wrote:

> 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
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20131004/9b34e115/attachment.html>


More information about the cfe-commits mailing list