]> granicus.if.org Git - clang/commitdiff
PR12057: Allow variadic template pack expansions to cross lambda boundaries.
authorRichard Smith <richard-llvm@metafoo.co.uk>
Wed, 25 Jul 2012 03:56:55 +0000 (03:56 +0000)
committerRichard Smith <richard-llvm@metafoo.co.uk>
Wed, 25 Jul 2012 03:56:55 +0000 (03:56 +0000)
Rather than adding a ContainsUnexpandedParameterPack bit to essentially every
AST node, we tunnel the bit directly up to the surrounding lambda expression
when we reach a context where an unexpanded pack can not normally appear.
Thus any statement or declaration within a lambda can now potentially contain
an unexpanded parameter pack.

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

12 files changed:
include/clang/AST/ExprCXX.h
include/clang/Sema/ScopeInfo.h
include/clang/Sema/Sema.h
include/clang/Sema/Template.h
lib/AST/ExprCXX.cpp
lib/Sema/SemaLambda.cpp
lib/Sema/SemaTemplateInstantiate.cpp
lib/Sema/SemaTemplateVariadic.cpp
lib/Sema/TreeTransform.h
test/CXX/expr/expr.prim/expr.prim.lambda/blocks.mm
test/CXX/expr/expr.prim/expr.prim.lambda/p23.cpp
test/SemaCXX/lambda-expressions.cpp

index 1e2e7af4336bcfad9416aa82cebc432720f1a538..7a1ca21e92b3f378bddcf41aa7493d652b893071 100644 (file)
@@ -1254,7 +1254,8 @@ private:
              ArrayRef<Expr *> CaptureInits,
              ArrayRef<VarDecl *> ArrayIndexVars,
              ArrayRef<unsigned> ArrayIndexStarts,
-             SourceLocation ClosingBrace);
+             SourceLocation ClosingBrace,
+             bool ContainsUnexpandedParameterPack);
 
   /// \brief Construct an empty lambda expression.
   LambdaExpr(EmptyShell Empty, unsigned NumCaptures, bool HasArrayIndexVars)
@@ -1292,7 +1293,8 @@ public:
                             ArrayRef<Expr *> CaptureInits,
                             ArrayRef<VarDecl *> ArrayIndexVars,
                             ArrayRef<unsigned> ArrayIndexStarts,
-                            SourceLocation ClosingBrace);
+                            SourceLocation ClosingBrace,
+                            bool ContainsUnexpandedParameterPack);
 
   /// \brief Construct a new lambda expression that will be deserialized from
   /// an external source.
index 97c76a584f30bad588ec4b22813ce3e7e34cfe28..37d7cae56bb8ed3d2a6869ab6cfc19ff00cb3a96 100644 (file)
@@ -344,6 +344,9 @@ public:
   /// \brief Whether any of the capture expressions requires cleanups.
   bool ExprNeedsCleanups;
 
+  /// \brief Whether the lambda contains an unexpanded parameter pack.
+  bool ContainsUnexpandedParameterPack;
+
   /// \brief Variables used to index into by-copy array captures.
   llvm::SmallVector<VarDecl *, 4> ArrayIndexVars;
 
@@ -355,7 +358,7 @@ public:
                   CXXMethodDecl *CallOperator)
     : CapturingScopeInfo(Diag, ImpCap_None), Lambda(Lambda),
       CallOperator(CallOperator), NumExplicitCaptures(0), Mutable(false),
-      ExprNeedsCleanups(false)
+      ExprNeedsCleanups(false), ContainsUnexpandedParameterPack(false)
   {
     Kind = SK_Lambda;
   }
index a3be78c4df8d5a90062b7e6521cb3af7182ee505..e5b3b5a012c84140e89599faf804462d563bdd05 100644 (file)
@@ -5003,7 +5003,9 @@ public:
   /// parameter packs.
   ///
   /// \param Unexpanded the set of unexpanded parameter packs.
-  void DiagnoseUnexpandedParameterPacks(SourceLocation Loc,
+  ///
+  /// \returns true if an error occurred, false otherwise.
+  bool DiagnoseUnexpandedParameterPacks(SourceLocation Loc,
                                         UnexpandedParameterPackContext UPPC,
                                   ArrayRef<UnexpandedParameterPack> Unexpanded);
 
index 87d71b89952572e056c6070f70a1ea315aea2e26..273374dfd8b04b9c4433ed27ddd99362eb0e9f84 100644 (file)
@@ -372,8 +372,10 @@ namespace clang {
   public:
     TemplateDeclInstantiator(Sema &SemaRef, DeclContext *Owner,
                              const MultiLevelTemplateArgumentList &TemplateArgs)
-      : SemaRef(SemaRef), SubstIndex(SemaRef, -1), Owner(Owner), 
-        TemplateArgs(TemplateArgs), LateAttrs(0), StartingScope(0) { }
+      : SemaRef(SemaRef),
+        SubstIndex(SemaRef, SemaRef.ArgumentPackSubstitutionIndex),
+        Owner(Owner), TemplateArgs(TemplateArgs), LateAttrs(0), StartingScope(0)
+    { }
 
     // FIXME: Once we get closer to completion, replace these manually-written
     // declarations with automatically-generated ones from
index 73347b2e01d68a7db1422d7732fa51be51037c10..fc52649b9c1b24be86304c8c1f3b329e7f6b71e6 100644 (file)
@@ -790,10 +790,11 @@ LambdaExpr::LambdaExpr(QualType T,
                        ArrayRef<Expr *> CaptureInits,
                        ArrayRef<VarDecl *> ArrayIndexVars,
                        ArrayRef<unsigned> ArrayIndexStarts,
-                       SourceLocation ClosingBrace)
+                       SourceLocation ClosingBrace,
+                       bool ContainsUnexpandedParameterPack)
   : Expr(LambdaExprClass, T, VK_RValue, OK_Ordinary,
          T->isDependentType(), T->isDependentType(), T->isDependentType(),
-         /*ContainsUnexpandedParameterPack=*/false),
+         ContainsUnexpandedParameterPack),
     IntroducerRange(IntroducerRange),
     NumCaptures(Captures.size()),
     CaptureDefault(CaptureDefault),
@@ -850,7 +851,8 @@ LambdaExpr *LambdaExpr::Create(ASTContext &Context,
                                ArrayRef<Expr *> CaptureInits,
                                ArrayRef<VarDecl *> ArrayIndexVars,
                                ArrayRef<unsigned> ArrayIndexStarts,
-                               SourceLocation ClosingBrace) {
+                               SourceLocation ClosingBrace,
+                               bool ContainsUnexpandedParameterPack) {
   // Determine the type of the expression (i.e., the type of the
   // function object we're creating).
   QualType T = Context.getTypeDeclType(Class);
@@ -863,7 +865,7 @@ LambdaExpr *LambdaExpr::Create(ASTContext &Context,
   return new (Mem) LambdaExpr(T, IntroducerRange, CaptureDefault, 
                               Captures, ExplicitParams, ExplicitResultType,
                               CaptureInits, ArrayIndexVars, ArrayIndexStarts,
-                              ClosingBrace);
+                              ClosingBrace, ContainsUnexpandedParameterPack);
 }
 
 LambdaExpr *LambdaExpr::CreateDeserialized(ASTContext &C, unsigned NumCaptures,
index 25d27f44eec1c24959d3007bf983a944151b586c..3a10c2af9157e8dabb4de87d47036f920a01dade 100644 (file)
@@ -375,6 +375,7 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
   TypeSourceInfo *MethodTyInfo;
   bool ExplicitParams = true;
   bool ExplicitResultType = true;
+  bool ContainsUnexpandedParameterPack = false;
   SourceLocation EndLoc;
   llvm::ArrayRef<ParmVarDecl *> Params;
   if (ParamInfo.getNumTypeObjects() == 0) {
@@ -416,21 +417,8 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
                                            Proto.getNumArgs());
 
     // Check for unexpanded parameter packs in the method type.
-    // FIXME: We should allow unexpanded parameter packs here, but that would,
-    // in turn, make the lambda expression contain unexpanded parameter packs.
-    if (DiagnoseUnexpandedParameterPack(Intro.Range.getBegin(), MethodTyInfo,
-                                        UPPC_Lambda)) {
-      // Drop the parameters.
-      Params = llvm::ArrayRef<ParmVarDecl *>();
-      FunctionProtoType::ExtProtoInfo EPI;
-      EPI.HasTrailingReturn = false;
-      EPI.TypeQuals |= DeclSpec::TQ_const;
-      QualType MethodTy = Context.getFunctionType(Context.DependentTy,
-                                                  /*Args=*/0, /*NumArgs=*/0, EPI);
-      MethodTyInfo = Context.getTrivialTypeSourceInfo(MethodTy);
-      ExplicitParams = false;
-      ExplicitResultType = false;
-    }
+    if (MethodTyInfo->getType()->containsUnexpandedParameterPack())
+      ContainsUnexpandedParameterPack = true;
   }
   
   CXXMethodDecl *Method = startLambdaDefinition(Class, Intro.Range,
@@ -571,8 +559,7 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
         // Just ignore the ellipsis.
       }
     } else if (Var->isParameterPack()) {
-      Diag(C->Loc, diag::err_lambda_unexpanded_pack);
-      continue;
+      ContainsUnexpandedParameterPack = true;
     }
     
     TryCaptureKind Kind = C->Kind == LCK_ByRef ? TryCapture_ExplicitByRef :
@@ -581,6 +568,8 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
   }
   finishLambdaExplicitCaptures(LSI);
 
+  LSI->ContainsUnexpandedParameterPack = ContainsUnexpandedParameterPack;
+
   // Add lambda parameters into scope.
   addLambdaParameters(Method, CurScope);
 
@@ -743,6 +732,7 @@ ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body,
   bool ExplicitParams;
   bool ExplicitResultType;
   bool LambdaExprNeedsCleanups;
+  bool ContainsUnexpandedParameterPack;
   llvm::SmallVector<VarDecl *, 4> ArrayIndexVars;
   llvm::SmallVector<unsigned, 4> ArrayIndexStarts;
   {
@@ -753,6 +743,7 @@ ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body,
     ExplicitParams = LSI->ExplicitParams;
     ExplicitResultType = !LSI->HasImplicitReturnType;
     LambdaExprNeedsCleanups = LSI->ExprNeedsCleanups;
+    ContainsUnexpandedParameterPack = LSI->ContainsUnexpandedParameterPack;
     ArrayIndexVars.swap(LSI->ArrayIndexVars);
     ArrayIndexStarts.swap(LSI->ArrayIndexStarts);
     
@@ -867,7 +858,8 @@ ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body,
                                           CaptureDefault, Captures, 
                                           ExplicitParams, ExplicitResultType,
                                           CaptureInits, ArrayIndexVars, 
-                                          ArrayIndexStarts, Body->getLocEnd());
+                                          ArrayIndexStarts, Body->getLocEnd(),
+                                          ContainsUnexpandedParameterPack);
 
   // C++11 [expr.prim.lambda]p2:
   //   A lambda-expression shall not appear in an unevaluated operand
index d009e2f81b7317a0e40e40738882c529aec5aec2..082b2e847fe7f19e4ab7ff88dbb3ebc8c94161b7 100644 (file)
@@ -838,6 +838,19 @@ namespace {
       return move(Result);
     }
 
+    ExprResult TransformLambdaExpr(LambdaExpr *E) {
+      LocalInstantiationScope Scope(SemaRef, /*CombineWithOuterScope=*/true);
+      return TreeTransform<TemplateInstantiator>::TransformLambdaExpr(E);
+    }
+
+    ExprResult TransformLambdaScope(LambdaExpr *E,
+                                    CXXMethodDecl *CallOperator) {
+      CallOperator->setInstantiationOfMemberFunction(E->getCallOperator(),
+                                                     TSK_ImplicitInstantiation);
+      return TreeTransform<TemplateInstantiator>::
+         TransformLambdaScope(E, CallOperator);
+    }
+
   private:
     ExprResult transformNonTypeTemplateParmRef(NonTypeTemplateParmDecl *parm,
                                                SourceLocation loc,
index 0d0f992bedfd84e3821f2d0c5fcfec87a7d2376a..aece90b78590a05d7678645c6255807b0315ea0f 100644 (file)
@@ -12,6 +12,7 @@
 #include "clang/Sema/Sema.h"
 #include "clang/Sema/Lookup.h"
 #include "clang/Sema/ParsedTemplate.h"
+#include "clang/Sema/ScopeInfo.h"
 #include "clang/Sema/SemaInternal.h"
 #include "clang/Sema/Template.h"
 #include "clang/AST/Expr.h"
@@ -34,10 +35,12 @@ namespace {
 
     SmallVectorImpl<UnexpandedParameterPack> &Unexpanded;
 
+    bool InLambda;
+
   public:
     explicit CollectUnexpandedParameterPacksVisitor(
                   SmallVectorImpl<UnexpandedParameterPack> &Unexpanded)
-      : Unexpanded(Unexpanded) { }
+      : Unexpanded(Unexpanded), InLambda(false) { }
 
     bool shouldWalkTypesOfTypeLocs() const { return false; }
     
@@ -107,17 +110,17 @@ namespace {
     /// \brief Suppress traversal into statements and expressions that
     /// do not contain unexpanded parameter packs.
     bool TraverseStmt(Stmt *S) { 
-      if (Expr *E = dyn_cast_or_null<Expr>(S))
-        if (E->containsUnexpandedParameterPack())
-          return inherited::TraverseStmt(E);
+      Expr *E = dyn_cast_or_null<Expr>(S);
+      if ((E && E->containsUnexpandedParameterPack()) || InLambda)
+        return inherited::TraverseStmt(S);
 
-      return true; 
+      return true;
     }
 
     /// \brief Suppress traversal into types that do not contain
     /// unexpanded parameter packs.
     bool TraverseType(QualType T) {
-      if (!T.isNull() && T->containsUnexpandedParameterPack())
+      if ((!T.isNull() && T->containsUnexpandedParameterPack()) || InLambda)
         return inherited::TraverseType(T);
 
       return true;
@@ -126,8 +129,9 @@ namespace {
     /// \brief Suppress traversel into types with location information
     /// that do not contain unexpanded parameter packs.
     bool TraverseTypeLoc(TypeLoc TL) {
-      if (!TL.getType().isNull() && 
-          TL.getType()->containsUnexpandedParameterPack())
+      if ((!TL.getType().isNull() && 
+           TL.getType()->containsUnexpandedParameterPack()) ||
+          InLambda)
         return inherited::TraverseTypeLoc(TL);
 
       return true;
@@ -136,10 +140,10 @@ namespace {
     /// \brief Suppress traversal of non-parameter declarations, since
     /// they cannot contain unexpanded parameter packs.
     bool TraverseDecl(Decl *D) { 
-      if (D && isa<ParmVarDecl>(D))
+      if ((D && isa<ParmVarDecl>(D)) || InLambda)
         return inherited::TraverseDecl(D);
 
-      return true; 
+      return true;
     }
 
     /// \brief Suppress traversal of template argument pack expansions.
@@ -157,17 +161,57 @@ namespace {
       
       return inherited::TraverseTemplateArgumentLoc(ArgLoc);
     }
+
+    /// \brief Note whether we're traversing a lambda containing an unexpanded
+    /// parameter pack. In this case, the unexpanded pack can occur anywhere,
+    /// including all the places where we normally wouldn't look. Within a
+    /// lambda, we don't propagate the 'contains unexpanded parameter pack' bit
+    /// outside an expression.
+    bool TraverseLambdaExpr(LambdaExpr *Lambda) {
+      // The ContainsUnexpandedParameterPack bit on a lambda is always correct,
+      // even if it's contained within another lambda.
+      if (!Lambda->containsUnexpandedParameterPack())
+        return true;
+
+      bool WasInLambda = InLambda;
+      InLambda = true;
+
+      // If any capture names a function parameter pack, that pack is expanded
+      // when the lambda is expanded.
+      for (LambdaExpr::capture_iterator I = Lambda->capture_begin(),
+                                        E = Lambda->capture_end(); I != E; ++I)
+        if (VarDecl *VD = I->getCapturedVar())
+          if (VD->isParameterPack())
+            Unexpanded.push_back(std::make_pair(VD, I->getLocation()));
+
+      inherited::TraverseLambdaExpr(Lambda);
+
+      InLambda = WasInLambda;
+      return true;
+    }
   };
 }
 
 /// \brief Diagnose all of the unexpanded parameter packs in the given
 /// vector.
-void
+bool
 Sema::DiagnoseUnexpandedParameterPacks(SourceLocation Loc,
                                        UnexpandedParameterPackContext UPPC,
                                  ArrayRef<UnexpandedParameterPack> Unexpanded) {
   if (Unexpanded.empty())
-    return;
+    return false;
+
+  // If we are within a lambda expression, that lambda contains an unexpanded
+  // parameter pack, and we are done.
+  // FIXME: Store 'Unexpanded' on the lambda so we don't need to recompute it
+  // later.
+  for (unsigned N = FunctionScopes.size(); N; --N) {
+    if (sema::LambdaScopeInfo *LSI =
+          dyn_cast<sema::LambdaScopeInfo>(FunctionScopes[N-1])) {
+      LSI->ContainsUnexpandedParameterPack = true;
+      return false;
+    }
+  }
   
   SmallVector<SourceLocation, 4> Locations;
   SmallVector<IdentifierInfo *, 4> Names;
@@ -200,6 +244,7 @@ Sema::DiagnoseUnexpandedParameterPacks(SourceLocation Loc,
 
   for (unsigned I = 0, N = Locations.size(); I != N; ++I)
     DB << SourceRange(Locations[I]);
+  return true;
 }
 
 bool Sema::DiagnoseUnexpandedParameterPack(SourceLocation Loc, 
@@ -215,8 +260,7 @@ bool Sema::DiagnoseUnexpandedParameterPack(SourceLocation Loc,
   CollectUnexpandedParameterPacksVisitor(Unexpanded).TraverseTypeLoc(
                                                               T->getTypeLoc());
   assert(!Unexpanded.empty() && "Unable to find unexpanded parameter packs");
-  DiagnoseUnexpandedParameterPacks(Loc, UPPC, Unexpanded);
-  return true;
+  return DiagnoseUnexpandedParameterPacks(Loc, UPPC, Unexpanded);
 }
 
 bool Sema::DiagnoseUnexpandedParameterPack(Expr *E,
@@ -230,8 +274,7 @@ bool Sema::DiagnoseUnexpandedParameterPack(Expr *E,
   SmallVector<UnexpandedParameterPack, 2> Unexpanded;
   CollectUnexpandedParameterPacksVisitor(Unexpanded).TraverseStmt(E);
   assert(!Unexpanded.empty() && "Unable to find unexpanded parameter packs");
-  DiagnoseUnexpandedParameterPacks(E->getLocStart(), UPPC, Unexpanded);
-  return true;
+  return DiagnoseUnexpandedParameterPacks(E->getLocStart(), UPPC, Unexpanded);
 }
 
 bool Sema::DiagnoseUnexpandedParameterPack(const CXXScopeSpec &SS,
@@ -247,9 +290,8 @@ bool Sema::DiagnoseUnexpandedParameterPack(const CXXScopeSpec &SS,
   CollectUnexpandedParameterPacksVisitor(Unexpanded)
     .TraverseNestedNameSpecifier(SS.getScopeRep());
   assert(!Unexpanded.empty() && "Unable to find unexpanded parameter packs");
-  DiagnoseUnexpandedParameterPacks(SS.getRange().getBegin(), 
-                                   UPPC, Unexpanded);
-  return true;
+  return DiagnoseUnexpandedParameterPacks(SS.getRange().getBegin(),
+                                          UPPC, Unexpanded);
 }
 
 bool Sema::DiagnoseUnexpandedParameterPack(const DeclarationNameInfo &NameInfo,
@@ -284,8 +326,7 @@ bool Sema::DiagnoseUnexpandedParameterPack(const DeclarationNameInfo &NameInfo,
   CollectUnexpandedParameterPacksVisitor(Unexpanded)
     .TraverseType(NameInfo.getName().getCXXNameType());
   assert(!Unexpanded.empty() && "Unable to find unexpanded parameter packs");
-  DiagnoseUnexpandedParameterPacks(NameInfo.getLoc(), UPPC, Unexpanded);
-  return true;
+  return DiagnoseUnexpandedParameterPacks(NameInfo.getLoc(), UPPC, Unexpanded);
 }
 
 bool Sema::DiagnoseUnexpandedParameterPack(SourceLocation Loc,
@@ -299,8 +340,7 @@ bool Sema::DiagnoseUnexpandedParameterPack(SourceLocation Loc,
   CollectUnexpandedParameterPacksVisitor(Unexpanded)
     .TraverseTemplateName(Template);
   assert(!Unexpanded.empty() && "Unable to find unexpanded parameter packs");
-  DiagnoseUnexpandedParameterPacks(Loc, UPPC, Unexpanded);
-  return true;
+  return DiagnoseUnexpandedParameterPacks(Loc, UPPC, Unexpanded);
 }
 
 bool Sema::DiagnoseUnexpandedParameterPack(TemplateArgumentLoc Arg,
@@ -313,8 +353,7 @@ bool Sema::DiagnoseUnexpandedParameterPack(TemplateArgumentLoc Arg,
   CollectUnexpandedParameterPacksVisitor(Unexpanded)
     .TraverseTemplateArgumentLoc(Arg);
   assert(!Unexpanded.empty() && "Unable to find unexpanded parameter packs");
-  DiagnoseUnexpandedParameterPacks(Arg.getLocation(), UPPC, Unexpanded);
-  return true;  
+  return DiagnoseUnexpandedParameterPacks(Arg.getLocation(), UPPC, Unexpanded);
 }
 
 void Sema::collectUnexpandedParameterPacks(TemplateArgument Arg,
index fff3b3f4bfd62aa4b896d831d772dea4065a852a..0dd9d9c1912bd3a0292c4e5080e311504352220c 100644 (file)
@@ -571,6 +571,9 @@ public:
   StmtResult TransformCompoundStmt(CompoundStmt *S, bool IsStmtExpr);
   ExprResult TransformCXXNamedCastExpr(CXXNamedCastExpr *E);
 
+  /// \brief Transform the captures and body of a lambda expression.
+  ExprResult TransformLambdaScope(LambdaExpr *E, CXXMethodDecl *CallOperator);
+
 #define STMT(Node, Parent)                        \
   StmtResult Transform##Node(Node *S);
 #define EXPR(Node, Parent)                        \
@@ -7894,14 +7897,13 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
     return ExprError();
 
   // Transform lambda parameters.
-  bool Invalid = false;
   llvm::SmallVector<QualType, 4> ParamTypes;
   llvm::SmallVector<ParmVarDecl *, 4> Params;
   if (getDerived().TransformFunctionTypeParams(E->getLocStart(),
         E->getCallOperator()->param_begin(),
         E->getCallOperator()->param_size(),
         0, ParamTypes, &Params))
-    Invalid = true;  
+    return ExprError();
 
   // Build the call operator.
   CXXMethodDecl *CallOperator
@@ -7910,11 +7912,14 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
                                       E->getCallOperator()->getLocEnd(),
                                       Params);
   getDerived().transformAttrs(E->getCallOperator(), CallOperator);
-  
-  // FIXME: Instantiation-specific.
-  CallOperator->setInstantiationOfMemberFunction(E->getCallOperator(), 
-                                                 TSK_ImplicitInstantiation);
 
+  return getDerived().TransformLambdaScope(E, CallOperator);
+}
+
+template<typename Derived>
+ExprResult
+TreeTransform<Derived>::TransformLambdaScope(LambdaExpr *E,
+                                             CXXMethodDecl *CallOperator) {
   // Introduce the context of the call operator.
   Sema::ContextRAII SavedContext(getSema(), CallOperator);
 
@@ -7927,6 +7932,7 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
                                  E->isMutable());
   
   // Transform captures.
+  bool Invalid = false;
   bool FinishedExplicitCaptures = false;
   for (LambdaExpr::capture_iterator C = E->capture_begin(), 
                                  CEnd = E->capture_end();
index 6a6e0d9c909ea2ec8af2b335b7b4ed98f8c4529d..0db2bf5646ff4568e3e8f71f9b068f763e27e699 100644 (file)
@@ -89,6 +89,8 @@ namespace overloading {
 
 namespace PR13117 {
   struct A {
+    template<typename ... Args> static void f(Args...);
+
     template<typename ... Args> static void f1()
     {
       (void)^(Args args) { // expected-error{{block contains unexpanded parameter pack 'Args'}}
@@ -97,9 +99,24 @@ namespace PR13117 {
 
     template<typename ... Args> static void f2()
     {
-      (void)[](Args args) { // expected-error{{lambda contains unexpanded parameter pack 'Args'}}
+      // FIXME: Allow this.
+      f(
+        ^(Args args) // expected-error{{block contains unexpanded parameter pack 'Args'}}
+        { }
+        ... // expected-error{{pack expansion does not contain any unexpanded parameter packs}}
+      );
+    }
+
+    template<typename ... Args> static void f3()
+    {
+      (void)[](Args args) { // expected-error{{expression contains unexpanded parameter pack 'Args'}}
       };
     }
+
+    template<typename ... Args> static void f4()
+    {
+      f([](Args args) { } ...);
+    }
   };
 
   void g() {
index 174db257c891b821aa1deb3c84cedc00882e31dd..82fc04a48fb60a889aeafdadfbb3e217b96848a0 100644 (file)
@@ -9,8 +9,8 @@ void print(T first, Ts... rest) {
 }
 
 template<typename... Ts>
-void unsupported(Ts ...values) {
-  auto unsup = [values] {}; // expected-error{{unexpanded function parameter pack capture is unsupported}}
+void unexpanded_capture(Ts ...values) {
+  auto unexp = [values] {}; // expected-error{{initializer contains unexpanded parameter pack 'values'}}
 }
 
 template<typename... Ts>
index f5eee6a529ed57efbac47747cc307a5e323de9ad..198f8cf1fef7f25d37c60f89f11040f61a7013b6 100644 (file)
@@ -145,3 +145,79 @@ namespace ModifyingCapture {
     };
   }
 }
+
+namespace VariadicPackExpansion {
+  template<typename T, typename U> using Fst = T;
+  template<typename...Ts> bool g(Fst<bool, Ts> ...bools);
+  template<typename...Ts> bool f(Ts &&...ts) {
+    return g<Ts...>([&ts] {
+      if (!ts)
+        return false;
+      --ts;
+      return true;
+    } () ...);
+  }
+  void h() {
+    int a = 5, b = 2, c = 3;
+    while (f(a, b, c)) {
+    }
+  }
+
+  struct sink {
+    template<typename...Ts> sink(Ts &&...) {}
+  };
+
+  template<typename...Ts> void local_class() {
+    sink {
+      [] (Ts t) {
+        struct S : Ts {
+          void f(Ts t) {
+            Ts &that = *this;
+            that = t;
+          }
+          Ts g() { return *this; };
+        };
+        S s;
+        s.f(t);
+        return s;
+      } (Ts()).g() ...
+    };
+  };
+  struct X {}; struct Y {};
+  template void local_class<X, Y>();
+
+  template<typename...Ts> void nested(Ts ...ts) {
+    f(
+      // Each expansion of this lambda implicitly captures all of 'ts', because
+      // the inner lambda also expands 'ts'.
+      [&] {
+        return ts + [&] { return f(ts...); } ();
+      } () ...
+    );
+  }
+  template void nested(int, int, int);
+
+  template<typename...Ts> void nested2(Ts ...ts) { // expected-note 2{{here}}
+    // Capture all 'ts', use only one.
+    f([&ts...] { return ts; } ()...);
+    // Capture each 'ts', use it.
+    f([&ts] { return ts; } ()...);
+    // Capture all 'ts', use all of them.
+    f([&ts...] { return (int)f(ts...); } ());
+    // Capture each 'ts', use all of them. Ill-formed. In more detail:
+    //
+    // We instantiate two lambdas here; the first captures ts$0, the second
+    // captures ts$1. Both of them reference both ts parameters, so both are
+    // ill-formed because ts can't be implicitly captured.
+    //
+    // FIXME: This diagnostic does not explain what's happening. We should
+    // specify which 'ts' we're referring to in its diagnostic name. We should
+    // also say which slice of the pack expansion is being performed in the
+    // instantiation backtrace.
+    f([&ts] { return (int)f(ts...); } ()...); // \
+    // expected-error 2{{'ts' cannot be implicitly captured}} \
+    // expected-note 2{{lambda expression begins here}}
+  }
+  template void nested2(int); // ok
+  template void nested2(int, int); // expected-note {{in instantiation of}}
+}