[cfe-commits] r150497 - in /cfe/trunk: include/clang/Basic/DiagnosticSemaKinds.td include/clang/Sema/DeclSpec.h include/clang/Sema/ScopeInfo.h include/clang/Sema/Sema.h lib/Parse/ParseExprCXX.cpp lib/Sema/SemaExpr.cpp lib/Sema/SemaLambda.cpp lib/Sema/TreeTransform.h test/CXX/expr/expr.prim/expr.prim.lambda/p23.cpp

Douglas Gregor dgregor at apple.com
Tue Feb 14 11:27:52 PST 2012


Author: dgregor
Date: Tue Feb 14 13:27:52 2012
New Revision: 150497

URL: http://llvm.org/viewvc/llvm-project?rev=150497&view=rev
Log:
Implement support for lambda capture pack expansions, e.g.,

  [&values...] { print(values...); }



Added:
    cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/p23.cpp
Modified:
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/include/clang/Sema/DeclSpec.h
    cfe/trunk/include/clang/Sema/ScopeInfo.h
    cfe/trunk/include/clang/Sema/Sema.h
    cfe/trunk/lib/Parse/ParseExprCXX.cpp
    cfe/trunk/lib/Sema/SemaExpr.cpp
    cfe/trunk/lib/Sema/SemaLambda.cpp
    cfe/trunk/lib/Sema/TreeTransform.h

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=150497&r1=150496&r2=150497&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Tue Feb 14 13:27:52 2012
@@ -4032,7 +4032,9 @@
   "cannot deduce lambda return type from initializer list">;
 def err_lambda_capture_default_arg : Error<
   "lambda expression in default argument cannot capture any entity">;
-
+def err_lambda_unexpanded_pack : Error<
+  "unexpanded function parameter pack capture is unsupported">;
+  
 def err_operator_arrow_circular : Error<
   "circular pointer delegation detected">;
 def err_pseudo_dtor_base_not_scalar : Error<

Modified: cfe/trunk/include/clang/Sema/DeclSpec.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/DeclSpec.h?rev=150497&r1=150496&r2=150497&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/DeclSpec.h (original)
+++ cfe/trunk/include/clang/Sema/DeclSpec.h Tue Feb 14 13:27:52 2012
@@ -1923,10 +1923,12 @@
   LambdaCaptureKind Kind;
   SourceLocation Loc;
   IdentifierInfo* Id;
-
+  SourceLocation EllipsisLoc;
+  
   LambdaCapture(LambdaCaptureKind Kind, SourceLocation Loc,
-                IdentifierInfo* Id = 0)
-    : Kind(Kind), Loc(Loc), Id(Id)
+                IdentifierInfo* Id = 0,
+                SourceLocation EllipsisLoc = SourceLocation())
+    : Kind(Kind), Loc(Loc), Id(Id), EllipsisLoc(EllipsisLoc)
   {}
 };
 
@@ -1943,8 +1945,9 @@
   /// addCapture - Append a capture in a lambda introducer.
   void addCapture(LambdaCaptureKind Kind,
                   SourceLocation Loc,
-                  IdentifierInfo* Id = 0) {
-    Captures.push_back(LambdaCapture(Kind, Loc, Id));
+                  IdentifierInfo* Id = 0, 
+                  SourceLocation EllipsisLoc = SourceLocation()) {
+    Captures.push_back(LambdaCapture(Kind, Loc, Id, EllipsisLoc));
   }
 
 };

Modified: cfe/trunk/include/clang/Sema/ScopeInfo.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/ScopeInfo.h?rev=150497&r1=150496&r2=150497&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/ScopeInfo.h (original)
+++ cfe/trunk/include/clang/Sema/ScopeInfo.h Tue Feb 14 13:27:52 2012
@@ -151,16 +151,19 @@
     /// \brief The source location at which the first capture occurred..
     SourceLocation Loc;
     
+    /// \brief The location of the ellipsis that expands a parameter pack.
+    SourceLocation EllipsisLoc;
+    
   public:
     Capture(VarDecl *Var, bool block, bool byRef, bool isNested, 
-            SourceLocation Loc, Expr *Cpy)
+            SourceLocation Loc, SourceLocation EllipsisLoc, Expr *Cpy)
       : VarAndKind(Var, block ? Cap_Block : byRef ? Cap_ByRef : Cap_ByCopy),
-        CopyExprAndNested(Cpy, isNested) {}
+        CopyExprAndNested(Cpy, isNested), Loc(Loc), EllipsisLoc(EllipsisLoc) {}
 
     enum IsThisCapture { ThisCapture };
     Capture(IsThisCapture, bool isNested, SourceLocation Loc, Expr *Cpy)
-      : VarAndKind(0, Cap_This), CopyExprAndNested(Cpy, isNested), Loc(Loc) {
-    }
+      : VarAndKind(0, Cap_This), CopyExprAndNested(Cpy, isNested), Loc(Loc),
+        EllipsisLoc() { }
 
     bool isThisCapture() const { return VarAndKind.getInt() == Cap_This; }
     bool isVariableCapture() const { return !isThisCapture(); }
@@ -176,6 +179,10 @@
     /// \brief Retrieve the location at which this variable was captured.
     SourceLocation getLocation() const { return Loc; }
     
+    /// \brief Retrieve the source location of the ellipsis, whose presence
+    /// indicates that the capture is a pack expansion.
+    SourceLocation getEllipsisLoc() const { return EllipsisLoc; }
+    
     Expr *getCopyExpr() const {
       return CopyExprAndNested.getPointer();
     }
@@ -205,8 +212,9 @@
   QualType ReturnType;
 
   void AddCapture(VarDecl *Var, bool isBlock, bool isByref, bool isNested,
-                  SourceLocation Loc, Expr *Cpy) {
-    Captures.push_back(Capture(Var, isBlock, isByref, isNested, Loc, Cpy));
+                  SourceLocation Loc, SourceLocation EllipsisLoc, Expr *Cpy) {
+    Captures.push_back(Capture(Var, isBlock, isByref, isNested, Loc, 
+                               EllipsisLoc, Cpy));
     CaptureMap[Var] = Captures.size();
   }
 

Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=150497&r1=150496&r2=150497&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Tue Feb 14 13:27:52 2012
@@ -2298,7 +2298,8 @@
     TryCapture_Implicit, TryCapture_ExplicitByVal, TryCapture_ExplicitByRef
   };
   void TryCaptureVar(VarDecl *var, SourceLocation loc,
-                     TryCaptureKind Kind = TryCapture_Implicit);
+                     TryCaptureKind Kind = TryCapture_Implicit,
+                     SourceLocation EllipsisLoc = SourceLocation());
 
   void MarkDeclarationsReferencedInType(SourceLocation Loc, QualType T);
   void MarkDeclarationsReferencedInExpr(Expr *E);

Modified: cfe/trunk/lib/Parse/ParseExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseExprCXX.cpp?rev=150497&r1=150496&r2=150497&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseExprCXX.cpp (original)
+++ cfe/trunk/lib/Parse/ParseExprCXX.cpp Tue Feb 14 13:27:52 2012
@@ -651,7 +651,8 @@
     LambdaCaptureKind Kind = LCK_ByCopy;
     SourceLocation Loc;
     IdentifierInfo* Id = 0;
-
+    SourceLocation EllipsisLoc;
+    
     if (Tok.is(tok::kw_this)) {
       Kind = LCK_This;
       Loc = ConsumeToken();
@@ -664,6 +665,9 @@
       if (Tok.is(tok::identifier)) {
         Id = Tok.getIdentifierInfo();
         Loc = ConsumeToken();
+        
+        if (Tok.is(tok::ellipsis))
+          EllipsisLoc = ConsumeToken();
       } else if (Tok.is(tok::kw_this)) {
         // FIXME: If we want to suggest a fixit here, will need to return more
         // than just DiagnosticID. Perhaps full DiagnosticBuilder that can be
@@ -674,7 +678,7 @@
       }
     }
 
-    Intro.addCapture(Kind, Loc, Id);
+    Intro.addCapture(Kind, Loc, Id, EllipsisLoc);
   }
 
   T.consumeClose();

Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=150497&r1=150496&r2=150497&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Tue Feb 14 13:27:52 2012
@@ -9831,7 +9831,7 @@
 // Check if the variable needs to be captured; if so, try to perform
 // the capture.
 void Sema::TryCaptureVar(VarDecl *var, SourceLocation loc,
-                         TryCaptureKind Kind) {
+                         TryCaptureKind Kind, SourceLocation EllipsisLoc) {
   QualType type;
   unsigned functionScopesIndex;
   bool Nested;
@@ -9909,7 +9909,8 @@
       }
     }
 
-    CSI->AddCapture(var, hasBlocksAttr, byRef, Nested, loc, copyExpr);
+    CSI->AddCapture(var, hasBlocksAttr, byRef, Nested, loc, EllipsisLoc, 
+                    copyExpr);
 
     Nested = true;
     if (shouldAddConstForScope(CSI, var))

Modified: cfe/trunk/lib/Sema/SemaLambda.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaLambda.cpp?rev=150497&r1=150496&r2=150497&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaLambda.cpp (original)
+++ cfe/trunk/lib/Sema/SemaLambda.cpp Tue Feb 14 13:27:52 2012
@@ -291,9 +291,26 @@
       continue;
     }
 
+    // C++11 [expr.prim.lambda]p23:
+    //   A capture followed by an ellipsis is a pack expansion (14.5.3).
+    SourceLocation EllipsisLoc;
+    if (C->EllipsisLoc.isValid()) {
+      if (Var->isParameterPack()) {
+        EllipsisLoc = C->EllipsisLoc;
+      } else {
+        Diag(C->EllipsisLoc, diag::err_pack_expansion_without_parameter_packs)
+          << SourceRange(C->Loc);
+        
+        // Just ignore the ellipsis.
+      }
+    } else if (Var->isParameterPack()) {
+      Diag(C->Loc, diag::err_lambda_unexpanded_pack);
+      continue;
+    }
+    
     TryCaptureKind Kind = C->Kind == LCK_ByRef ? TryCapture_ExplicitByRef :
                                                  TryCapture_ExplicitByVal;
-    TryCaptureVar(Var, C->Loc, Kind);
+    TryCaptureVar(Var, C->Loc, Kind, EllipsisLoc);
   }
   finishLambdaExplicitCaptures(LSI);
 
@@ -380,10 +397,9 @@
       }
 
       VarDecl *Var = From.getVariable();
-      // FIXME: Handle pack expansions.
       LambdaCaptureKind Kind = From.isCopyCapture()? LCK_ByCopy : LCK_ByRef;
       Captures.push_back(LambdaExpr::Capture(From.getLocation(), IsImplicit, 
-                                             Kind, Var));
+                                             Kind, Var, From.getEllipsisLoc()));
       CaptureInits.push_back(From.getCopyExpr());
     }
 

Modified: cfe/trunk/lib/Sema/TreeTransform.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/TreeTransform.h?rev=150497&r1=150496&r2=150497&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/TreeTransform.h (original)
+++ cfe/trunk/lib/Sema/TreeTransform.h Tue Feb 14 13:27:52 2012
@@ -7706,6 +7706,49 @@
       continue;
     }
     
+    // Determine the capture kind for Sema.
+    Sema::TryCaptureKind Kind
+      = C->isImplicit()? Sema::TryCapture_Implicit
+                       : C->getCaptureKind() == LCK_ByCopy
+                           ? Sema::TryCapture_ExplicitByVal
+                           : Sema::TryCapture_ExplicitByRef;
+    SourceLocation EllipsisLoc;
+    if (C->isPackExpansion()) {
+      UnexpandedParameterPack Unexpanded(C->getCapturedVar(), C->getLocation());
+      bool ShouldExpand = false;
+      bool RetainExpansion = false;
+      llvm::Optional<unsigned> NumExpansions;
+      if (getDerived().TryExpandParameterPacks(C->getEllipsisLoc(), 
+                                               C->getLocation(), 
+                                               Unexpanded,
+                                               ShouldExpand, RetainExpansion,
+                                               NumExpansions))
+        return ExprError();
+      
+      if (ShouldExpand) {
+        // The transform has determined that we should perform an expansion;
+        // transform and capture each of the arguments.
+        // expansion of the pattern. Do so.
+        VarDecl *Pack = C->getCapturedVar();
+        for (unsigned I = 0; I != *NumExpansions; ++I) {
+          Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(getSema(), I);
+          VarDecl *CapturedVar
+            = cast_or_null<VarDecl>(getDerived().TransformDecl(C->getLocation(), 
+                                                               Pack));
+          if (!CapturedVar) {
+            Invalid = true;
+            continue;
+          }
+          
+          // Capture the transformed variable.
+          getSema().TryCaptureVar(CapturedVar, C->getLocation(), Kind);          
+        }          
+        continue;
+      }
+      
+      EllipsisLoc = C->getEllipsisLoc();
+    }
+    
     // Transform the captured variable.
     VarDecl *CapturedVar
       = cast_or_null<VarDecl>(getDerived().TransformDecl(C->getLocation(), 
@@ -7714,13 +7757,9 @@
       Invalid = true;
       continue;
     }
-    
+  
     // Capture the transformed variable.
-    getSema().TryCaptureVar(CapturedVar, C->getLocation(),
-                            C->isImplicit()? Sema::TryCapture_Implicit
-                                           : C->getCaptureKind() == LCK_ByCopy
-                                             ? Sema::TryCapture_ExplicitByVal
-                                             : Sema::TryCapture_ExplicitByRef);
+    getSema().TryCaptureVar(CapturedVar, C->getLocation(), Kind);
   }
   if (!FinishedExplicitCaptures)
     getSema().finishLambdaExplicitCaptures(LSI);

Added: cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/p23.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/p23.cpp?rev=150497&view=auto
==============================================================================
--- cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/p23.cpp (added)
+++ cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/p23.cpp Tue Feb 14 13:27:52 2012
@@ -0,0 +1,58 @@
+// RUN: %clang_cc1 -fsyntax-only -std=c++11 %s -verify
+
+void print();
+
+template<typename T, typename... Ts>
+void print(T first, Ts... rest) {
+  (void)first;
+  print(rest...);
+}
+
+template<typename... Ts>
+void unsupported(Ts ...values) {
+  auto unsup = [values] {}; // expected-error{{unexpanded function parameter pack capture is unsupported}}
+}
+
+template<typename... Ts>
+void implicit_capture(Ts ...values) {
+  auto implicit = [&] { print(values...); };
+  implicit();
+}
+
+template<typename... Ts>
+void do_print(Ts... values) {
+  auto bycopy = [values...]() { print(values...); };
+  bycopy();
+  auto byref = [&values...]() { print(values...); };
+  byref();
+
+  auto bycopy2 = [=]() { print(values...); };
+  bycopy2();
+  auto byref2 = [&]() { print(values...); };
+  byref2();
+}
+
+template void do_print(int, float, double);
+
+template<typename T, int... Values>
+void bogus_expansions(T x) {
+  auto l1 = [x...] {}; // expected-error{{pack expansion does not contain any unexpanded parameter packs}}
+  auto l2 = [Values...] {}; // expected-error{{'Values' in capture list does not name a variable}}
+}
+
+void g(int*, float*, double*);
+
+template<class... Args>
+void std_example(Args... args) {
+  auto lm = [&, args...] { return g(args...); };
+};
+
+template void std_example(int*, float*, double*);
+
+template<typename ...Args>
+void variadic_lambda(Args... args) {
+  auto lambda = [](Args... inner_args) { return g(inner_args...); };
+  lambda(args...);
+}
+
+template void variadic_lambda(int*, float*, double*);





More information about the cfe-commits mailing list