]> granicus.if.org Git - clang/commitdiff
Teach TreeTransform and family how to transform generic lambdas within templates...
authorFaisal Vali <faisalv@yahoo.com>
Thu, 3 Oct 2013 06:29:33 +0000 (06:29 +0000)
committerFaisal Vali <faisalv@yahoo.com>
Thu, 3 Oct 2013 06:29:33 +0000 (06:29 +0000)
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!)

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@191879 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Sema/SemaTemplateInstantiate.cpp
lib/Sema/SemaTemplateInstantiateDecl.cpp
lib/Sema/TreeTransform.h
test/CXX/expr/expr.prim/expr.prim.lambda/generic-lambda-unimplemented-1y.cpp
test/SemaCXX/cxx1y-generic-lambdas.cpp

index 32111bac3a49c9163305fa8e0251acc639b62be1..29481d6c63bc8f29f5af5aa461c65b617741aba9 100644 (file)
@@ -14,6 +14,7 @@
 #include "TreeTransform.h"
 #include "clang/AST/ASTConsumer.h"
 #include "clang/AST/ASTContext.h"
+#include "clang/AST/ASTLambda.h"
 #include "clang/AST/DeclTemplate.h"
 #include "clang/AST/Expr.h"
 #include "clang/Basic/LangOptions.h"
@@ -130,6 +131,11 @@ Sema::getTemplateInstantiationArgs(NamedDecl *D,
         assert(Function->getPrimaryTemplate() && "No function template?");
         if (Function->getPrimaryTemplate()->isMemberSpecialization())
           break;
+
+        // If this function is a generic lambda specialization, we are done.
+        if (isGenericLambdaCallOperatorSpecialization(Function))
+          break;
+
       } else if (FunctionTemplateDecl *FunTmpl
                                    = Function->getDescribedFunctionTemplate()) {
         // Add the "injected" template arguments.
@@ -911,13 +917,56 @@ namespace {
     }
 
     ExprResult TransformLambdaScope(LambdaExpr *E,
-                                    CXXMethodDecl *CallOperator) {
-      CallOperator->setInstantiationOfMemberFunction(E->getCallOperator(),
-                                                     TSK_ImplicitInstantiation);
-      return TreeTransform<TemplateInstantiator>::
-         TransformLambdaScope(E, CallOperator);
+                                    CXXMethodDecl *NewCallOperator) {
+      // If a lambda is undergoing transformation for instance in the
+      // call to foo('a') below:
+      //  template<class T> void foo(T t) {
+      //    auto L1 = [](T a) { return a; };\r
+      //    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(\r
+                              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,
index 35f3616db6a017c2d749541c7e83ba03113a2b77..359fb73166d91502505d12eaf19ba5a14cd70812 100644 (file)
@@ -4171,6 +4171,30 @@ DeclContext *Sema::FindInstantiatedContext(SourceLocation Loc, DeclContext* DC,
 NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D,
                           const MultiLevelTemplateArgumentList &TemplateArgs) {
   DeclContext *ParentDC = D->getDeclContext();
+
+  // If we have a parameter from a non-dependent context with a non-dependent
+  // type it obviously can not be mapped to a different instantiated decl.
+  // Consider the code below, with explicit return types, when N gets
+  // specialized ...:
+  // template<class T> void fooT(T t) {
+  //   auto L = [](auto a) -> void { 
+  //     auto M = [](char b) -> void {
+  //       auto N = [](auto c) -> void {
+  //         int x = sizeof(a) + sizeof(b) +
+  //                 sizeof(c);
+  //       };  
+  //       N('a');
+  //     };    
+  //   };
+  //   L(3.14);
+  // }
+  // fooT('a'); 
+  // ... without this check below, findInstantiationOf fails with
+  // an assertion violation.
+  if (isa<ParmVarDecl>(D) && !ParentDC->isDependentContext() &&
+      !cast<ParmVarDecl>(D)->getType()->isInstantiationDependentType())
+    return D;
+
   if (isa<ParmVarDecl>(D) || isa<NonTypeTemplateParmDecl>(D) ||
       isa<TemplateTypeParmDecl>(D) || isa<TemplateTemplateParmDecl>(D) ||
       (ParentDC->isFunctionOrMethod() && ParentDC->isDependentContext()) ||
index 977d0132b7e0de214dee6b5580b21514717112a3..7c343635a7f552551916b17abb0f804e472d5109 100644 (file)
@@ -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>::TransformLambdaExpr(LambdaExpr *E) {
         E->getCallOperator()->param_size(),
         0, ParamTypes, &Params))
     return ExprError();
-  getSema().PushLambdaScope();
-  LambdaScopeInfo *LSI = getSema().getCurLambda();
-  // TODO: Fix for nested lambdas
-  LSI->GLTemplateParameterList = 0;
+
   // Build the call operator.
-  CXXMethodDecl *CallOperator
+  CXXMethodDecl *NewCallOperator
     = getSema().startLambdaDefinition(Class, E->getIntroducerRange(),
-                                      MethodTy,
+                                      NewCallOpTSI,
                                       E->getCallOperator()->getLocEnd(),
                                       Params);
-  getDerived().transformAttrs(E->getCallOperator(), CallOperator);
-
-  return getDerived().TransformLambdaScope(E, CallOperator);
+  LSI->CallOperator = NewCallOperator;
+  // Fix the Decl Contexts of the parameters within the call op function 
+  // prototype.
+  getDerived().transformAttrs(E->getCallOperator(), NewCallOperator);
+  
+  TypeLoc NewCallOpTL = NewCallOpTSI->getTypeLoc();
+  FunctionProtoTypeLoc NewFPTL = NewCallOpTL.castAs<FunctionProtoTypeLoc>();
+  ParmVarDecl **NewParamDeclArray = NewFPTL.getParmArray();
+  const unsigned NewNumArgs = NewFPTL.getNumArgs();
+  for (unsigned I = 0; I < NewNumArgs; ++I) {
+      NewParamDeclArray[I]->setOwningFunction(NewCallOperator);
+  }
+  // If this is a non-generic lambda, the parameters do not get added to the
+  // current instantiation scope, so add them.  This feels kludgey.
+  // Anyway, it allows the following to compile when the enclosing template
+  // is specialized and the entire lambda expression has to be
+  // transformed.  Without this FindInstantiatedDecl causes an assertion.
+  // template<class T> void foo(T t) {
+  //    auto L = [](auto a) { 
+  //      auto M = [](char b) { <-- note: non-generic lambda
+  //        auto N = [](auto c) {
+  //          int x = sizeof(a);        
+  //          x = sizeof(b); <-- specifically this line
+  //          x = sizeof(c);
+  //        };  
+  //      };    
+  //    };
+  //  }
+  //  foo('a');
+  //
+  if (!E->isGenericLambda()) {
+    for (unsigned I = 0; I < NewNumArgs; ++I)
+      SemaRef.CurrentInstantiationScope->InstantiatedLocal(
+                                   NewParamDeclArray[I], NewParamDeclArray[I]);
+  }
+  return getDerived().TransformLambdaScope(E, NewCallOperator);
 }
 
 template<typename Derived>
index a43a98bb18f859a939a46d630561c6d238e9e9bc..92dd7ad1876c54aeaf50314782899dc8571fd5f2 100644 (file)
@@ -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}}
-}
-
-
index b66825a536dc3939b7df65135325df5f42847984..c5da672f1daa9f8477b7a0a795edf231b37b17b7 100644 (file)
@@ -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_argument_ok {
   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