]> granicus.if.org Git - clang/commitdiff
And Again: Teach TreeTransform how to transform nested generic lambdas.
authorFaisal Vali <faisalv@yahoo.com>
Wed, 23 Oct 2013 06:44:28 +0000 (06:44 +0000)
committerFaisal Vali <faisalv@yahoo.com>
Wed, 23 Oct 2013 06:44:28 +0000 (06:44 +0000)
A previous attempt http://lists.cs.uiuc.edu/pipermail/cfe-commits/Week-of-Mon-20130930/090049.html resulted in PR 17476, and was reverted,

The original TransformLambdaExpr (pre generic-lambdas) transformed the TypeSourceInfo of the Call operator in its own instantiation scope via TransformType.  This resulted in the parameters of the call operator being mapped to their transformed counterparts in an instantiation scope that would get popped off.
Then a call to TransformFunctionParameters would add the parameters and their transformed mappings (but newly created ones!) to the current instantiation scope. This would result in a disconnect between the new call operator's TSI parameters and those used to construct the call operator declaration. This was ok in the non-generic lambda world - but would cause issues with nested transformations (when non-generic and generics were interleaved) in the generic lambda world - that I somewhat kludged around initially - but this resulted in PR17476.

The new approach seems cleaner. We only do the transformation of the TypeSourceInfo - but we make sure to do it in the current instantiation scope so we don't lose the untransformed to transformed mappings of the ParmVarDecls when they get created.

Another attempt caused a test to fail (http://lists.cs.uiuc.edu/pipermail/cfe-commits/Week-of-Mon-20131021/091533.html) and also had to be reverted - my apologies - in my haste, i did not run all the tests - argh!

Now all the tests seem to pass - but a Fixme has been added - since I suspect Richard will find the fix a little inelegant ;) I shall try and work on a more elegant fix once I have had a chance to discuss with Richard or Doug at a later date.

Hopefully the third time;s a charm *fingers crossed*

This does not yet include capturing.

Please see test file for examples.

This patch was LGTM'd by Doug:
http://llvm-reviews.chandlerc.com/D1784

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@193230 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 f13b14bd0f1bcf654c87552f4899c5271b3d39bb..3c621dafab9dc33e02337e8dab5356fe25827c5f 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,36 @@ namespace {
     }
 
     ExprResult TransformLambdaScope(LambdaExpr *E,
-                                    CXXMethodDecl *CallOperator) {
-      CallOperator->setInstantiationOfMemberFunction(E->getCallOperator(),
-                                                     TSK_ImplicitInstantiation);
-      return TreeTransform<TemplateInstantiator>::
-         TransformLambdaScope(E, CallOperator);
+                                    CXXMethodDecl *NewCallOperator) {
+      CXXMethodDecl *const OldCallOperator = E->getCallOperator();   
+      // In the generic lambda case, we set the NewTemplate to be considered
+      // an "instantiation" of the OldTemplate.
+      if (FunctionTemplateDecl *const NewCallOperatorTemplate = 
+            NewCallOperator->getDescribedFunctionTemplate()) {
+        
+        FunctionTemplateDecl *const OldCallOperatorTemplate = 
+                              OldCallOperator->getDescribedFunctionTemplate();
+        NewCallOperatorTemplate->setInstantiatedFromMemberTemplate(
+                                                     OldCallOperatorTemplate);
+        // Mark the NewCallOperatorTemplate a specialization.  
+        NewCallOperatorTemplate->setMemberSpecialization();
+      } else 
+        // For a non-generic lambda we set the NewCallOperator to 
+        // be an instantiation of the OldCallOperator.
+        NewCallOperator->setInstantiationOfMemberFunction(OldCallOperator,
+                                                    TSK_ImplicitInstantiation);
+      
+      return inherited::TransformLambdaScope(E, NewCallOperator);
+    }
+    TemplateParameterList *TransformTemplateParameterList(\r
+                              TemplateParameterList *OrigTPL)  {
+      if (!OrigTPL || !OrigTPL->size()) return OrigTPL;
+         
+      DeclContext *Owner = OrigTPL->getParam(0)->getDeclContext();
+      TemplateDeclInstantiator  DeclInstantiator(getSema(), 
+                        /* DeclContext *Owner */ Owner, TemplateArgs);
+      return DeclInstantiator.SubstTemplateParams(OrigTPL); 
     }
-
   private:
     ExprResult transformNonTypeTemplateParmRef(NonTypeTemplateParmDecl *parm,
                                                SourceLocation loc,
index d1512c271c0166773ebcf1fba5230205f12d2ba9..3989c56ccd8d63b5bad4cba2496db83b749028b4 100644 (file)
@@ -4174,6 +4174,25 @@ DeclContext *Sema::FindInstantiatedContext(SourceLocation Loc, DeclContext* DC,
 NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D,
                           const MultiLevelTemplateArgumentList &TemplateArgs) {
   DeclContext *ParentDC = D->getDeclContext();
+  // FIXME: Parmeters of pointer to functions (y below) that are themselves 
+  // parameters (p below) can have their ParentDC set to the translation-unit
+  // - thus we can not consistently check if the ParentDC of such a parameter 
+  // is Dependent or/and a FunctionOrMethod.
+  // For e.g. this code, during Template argument deduction tries to 
+  // find an instantiated decl for (T y) when the ParentDC for y is
+  // the translation unit.  
+  //   e.g. template <class T> void Foo(auto (*p)(T y) -> decltype(y())) {} 
+  //   float baz(float(*)()) { return 0.0; }\r
+  //   Foo(baz);
+  // The better fix here is perhaps to ensure that a ParmVarDecl, by the time
+  // it gets here, always has a FunctionOrMethod as its ParentDC??
+  // For now:
+  //  - as long as we have a ParmVarDecl whose parent is non-dependent and
+  //    whose type is not instantiation dependent, do nothing to the decl
+  //  - otherwise find its instantiated decl.
+  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 97e12d77a194258b6a84a996df755e5a7a6ffddf..3ac13bb08a6b4f51d89a9f3670482b869a9137f2 100644 (file)
@@ -593,6 +593,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);
@@ -8267,48 +8272,100 @@ 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();
+  getSema().PushLambdaScope();
+  LambdaScopeInfo *LSI = getSema().getCurLambda();
+  // Transform the template parameters, and add them to the current
+  // instantiation scope. The null case is handled correctly.
+  LSI->GLTemplateParameterList = getDerived().TransformTemplateParameterList(
+      E->getTemplateParameterList());
+
+  // Check to see if the TypeSourceInfo of the call operator needs to
+  // be transformed, and if so do the transformation in the 
+  // CurrentInstantiationScope.
+
+  TypeSourceInfo *OldCallOpTSI = E->getCallOperator()->getTypeSourceInfo();
+  FunctionProtoTypeLoc OldCallOpFPTL = 
+      OldCallOpTSI->getTypeLoc().getAs<FunctionProtoTypeLoc>();
+  TypeSourceInfo *NewCallOpTSI = 0;
+  
+  const bool CallOpWasAlreadyTransformed = 
+      getDerived().AlreadyTransformed(OldCallOpTSI->getType()); 
+  
+  // Use the Old Call Operator's TypeSourceInfo if it is already transformed.
+  if (CallOpWasAlreadyTransformed)  
+    NewCallOpTSI = OldCallOpTSI;  
+  else {
+    // Transform the TypeSourceInfo of the Original Lambda's Call Operator.
+    // The transformation MUST be done in the CurrentInstantiationScope since
+    // it introduces a mapping of the original to the newly created 
+    // transformed parameters.
+
+    TypeLocBuilder NewCallOpTLBuilder;
+    QualType NewCallOpType = TransformFunctionProtoType(NewCallOpTLBuilder, 
+                                                        OldCallOpFPTL, 
+                                                        0, 0);
+    NewCallOpTSI = NewCallOpTLBuilder.getTypeSourceInfo(getSema().Context,
+                                                        NewCallOpType);
+  }
+  // Extract the ParmVarDecls from the NewCallOpTSI and add them to
+  // the vector below - this will be used to synthesize the 
+  // NewCallOperator.  Additionally, add the parameters of the untransformed 
+  // lambda call operator to the CurrentInstantiationScope.
+  SmallVector<ParmVarDecl *, 4> Params;  
+  {
+    FunctionProtoTypeLoc NewCallOpFPTL = 
+        NewCallOpTSI->getTypeLoc().castAs<FunctionProtoTypeLoc>();
+    ParmVarDecl **NewParamDeclArray = NewCallOpFPTL.getParmArray();
+    const unsigned NewNumArgs = NewCallOpFPTL.getNumArgs();
+
+    for (unsigned I = 0; I < NewNumArgs; ++I) {
+      // If this call operator's type does not require transformation, 
+      // the parameters do not get added to the current instantiation scope, 
+      // - so ADD them! This allows the following to compile when the enclosing
+      // template is specialized and the entire lambda expression has to be
+      // transformed. 
+      // 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 (CallOpWasAlreadyTransformed)
+        getDerived().transformedLocalDecl(NewParamDeclArray[I],
+                                          NewParamDeclArray[I]);
+      // Add to Params array, so these parameters can be used to create
+      // the newly transformed call operator.
+      Params.push_back(NewParamDeclArray[I]);
+    }
   }
-  // Transform the type of the lambda parameters and start the definition of
-  // the lambda itself.
-  TypeSourceInfo *MethodTy
-    = TransformType(E->getCallOperator()->getTypeSourceInfo());
-  if (!MethodTy)
+
+  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);
 
-  // Transform lambda parameters.
-  SmallVector<QualType, 4> ParamTypes;
-  SmallVector<ParmVarDecl *, 4> Params;
-  if (getDerived().TransformFunctionTypeParams(E->getLocStart(),
-        E->getCallOperator()->param_begin(),
-        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);
+  LSI->CallOperator = NewCallOperator;
+
+  getDerived().transformAttrs(E->getCallOperator(), NewCallOperator);
 
-  return getDerived().TransformLambdaScope(E, CallOperator);
+  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..64b9ff14215e2bad5d004786f043045e190001af 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,516 @@ 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
+
+namespace PR17476 {
+struct string {
+  string(const char *__s) { }
+  string &operator+=(const string &__str) { return *this; }
+};
+
+template <class T> 
+void finalizeDefaultAtomValues() {
+  auto startEnd = [](const char * sym) -> void {
+    string start("__");
+    start += sym;
+  };
+  startEnd("preinit_array");
+}
+
+void f() { finalizeDefaultAtomValues<char>(); }
+
+} 
+
+namespace PR17476_variant {
+struct string {
+  string(const char *__s) { }
+  string &operator+=(const string &__str) { return *this; }
+};
+
+template <class T> 
+void finalizeDefaultAtomValues() {
+  auto startEnd = [](const T *sym) -> void {
+    string start("__");
+    start += sym;
+  };
+  startEnd("preinit_array");
+}
+
+void f() { finalizeDefaultAtomValues<char>(); }
+
+} 
\ No newline at end of file