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

Faisal Vali faisalv at yahoo.com
Wed Oct 2 22:32:48 PDT 2013


Author: faisalv
Date: Thu Oct  3 00:32:48 2013
New Revision: 191875

URL: http://llvm.org/viewvc/llvm-project?rev=191875&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

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=191875&r1=191874&r2=191875&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp Thu Oct  3 00:32:48 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=191875&r1=191874&r2=191875&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp Thu Oct  3 00:32:48 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=191875&r1=191874&r2=191875&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/TreeTransform.h (original)
+++ cfe/trunk/lib/Sema/TreeTransform.h Thu Oct  3 00:32:48 2013
@@ -594,6 +594,11 @@ public:
   /// \brief Transform the captures and body of a lambda expression.
   ExprResult TransformLambdaScope(LambdaExpr *E, CXXMethodDecl *CallOperator);
 
+  TemplateParameterList *TransformTemplateParameterList(
+        TemplateParameterList *TPL) {
+    return TPL;
+  }
+
   ExprResult TransformAddressOfOperand(Expr *E);
   ExprResult TransformDependentScopeDeclRefExpr(DependentScopeDeclRefExpr *E,
                                                 bool IsAddressOfOperand);
@@ -4573,6 +4578,19 @@ template<typename Derived>
 QualType TreeTransform<Derived>::TransformDecltypeType(TypeLocBuilder &TLB,
                                                        DecltypeTypeLoc TL) {
   const DecltypeType *T = TL.getTypePtr();
+  // Don't transform a decltype construct that has already been transformed 
+  // into a non-dependent type.
+  // Allows the following to compile:
+  // auto L = [](auto a) {
+  //   return [](auto b) ->decltype(a) {
+  //     return b;
+  //  };
+  //};  
+  if (!T->isInstantiationDependentType()) {
+    DecltypeTypeLoc NewTL = TLB.push<DecltypeTypeLoc>(TL.getType());
+    NewTL.setNameLoc(TL.getNameLoc());
+    return NewTL.getType();
+  }
 
   // decltype expressions are not potentially evaluated contexts
   EnterExpressionEvaluationContext Unevaluated(SemaRef, Sema::Unevaluated, 0,
@@ -8284,24 +8302,27 @@ template<typename Derived>
 ExprResult
 TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
  
-  // FIXME: Implement nested generic lambda transformations.
-  if (E->isGenericLambda()) {
-    getSema().Diag(E->getIntroducerRange().getBegin(), 
-      diag::err_glambda_not_fully_implemented) 
-      << " template transformation of generic lambdas not implemented yet";
-    return ExprError();
-  }
-  // Transform the type of the lambda parameters and start the definition of
-  // the lambda itself.
-  TypeSourceInfo *MethodTy
-    = TransformType(E->getCallOperator()->getTypeSourceInfo());
-  if (!MethodTy)
+  getSema().PushLambdaScope();
+  LambdaScopeInfo *LSI = getSema().getCurLambda();
+  TemplateParameterList *const OrigTPL = E->getTemplateParameterList();
+  TemplateParameterList *NewTPL = 0;
+  // Transform the template parameters, and add them to the 
+  // current instantiation scope.
+  if (OrigTPL) {
+      NewTPL = getDerived().TransformTemplateParameterList(OrigTPL);
+  }
+  LSI->GLTemplateParameterList = NewTPL;
+   // Transform the type of the lambda parameters and start the definition of
+   // the lambda itself.
+  TypeSourceInfo *OldCallOpTSI = E->getCallOperator()->getTypeSourceInfo(); 
+  TypeSourceInfo *NewCallOpTSI = TransformType(OldCallOpTSI);
+  if (!NewCallOpTSI)
     return ExprError();
 
   // Create the local class that will describe the lambda.
   CXXRecordDecl *Class
     = getSema().createLambdaClosureType(E->getIntroducerRange(),
-                                        MethodTy,
+                                        NewCallOpTSI,
                                         /*KnownDependent=*/false);
   getDerived().transformedLocalDecl(E->getLambdaClass(), Class);
 
@@ -8313,19 +8334,49 @@ TreeTransform<Derived>::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=191875&r1=191874&r2=191875&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 00:32:48 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=191875&r1=191874&r2=191875&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/cxx1y-generic-lambdas.cpp (original)
+++ cfe/trunk/test/SemaCXX/cxx1y-generic-lambdas.cpp Thu Oct  3 00:32:48 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





More information about the cfe-commits mailing list