PR12057: Allow variadic template pack expansions to cross lambda boundaries.
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
diff --git a/lib/Sema/SemaTemplateVariadic.cpp b/lib/Sema/SemaTemplateVariadic.cpp
index 0d0f992..aece90b 100644
--- a/lib/Sema/SemaTemplateVariadic.cpp
+++ b/lib/Sema/SemaTemplateVariadic.cpp
@@ -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 @@
 
     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 @@
     /// \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 @@
     /// \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 @@
     /// \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 @@
       
       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 @@
 
   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 @@
   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 @@
   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 @@
   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 @@
   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 @@
   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 @@
   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,