Attached is an updated patch.

- There is a LambdaExpr AST node, and no LambdaDecl.

- Documentation may be sparse in some areas. Please let me know where it is insufficient.

- In the fix-its for explicit captures that conflict with the default, the suggestion is to remove the explicit capture, not the default. My expectation is that this more closely aligns with programmer intent.

- I have not yet implemented any traverse/visit/transform functions yet. I want to wait until the AST node is a little more settled before I start that. It seems that some of these functions will have duplicate functionality. Is that true, and is there any opportunity for reuse?

Doug wrote:
The ParmVarDecls will be the same in both places. I suggest grabbing them from 
the Declarator, since that's easiest.

I do not believe it is easier to get ParmVarDecls from a Declarator than from a FunctionProtoTypeLoc. It seems like GetTypeForDeclarator does all the heavy lifting for me. Am I missing something?

Doug wrote:
The way we typically address this chicken-and-egg problem is to actually build 
the ParmVarDecls for the constructor before building the constructor itself. 
The ParmVarDecls are given the translation unit as their DeclContext, and then 
later (after the constructor is built) we update their DeclContext to point to 
the constructor. This allows us to build the full type of the constructor 
before building the constructor itself.

I favored building the type after because it is a little easier. There do not seem to be any problems so far. Should I still build the type first?


Thank you,
John
diff --git a/include/clang/AST/ExprCXX.h b/include/clang/AST/ExprCXX.h
index 1911704..0c27843 100644
--- a/include/clang/AST/ExprCXX.h
+++ b/include/clang/AST/ExprCXX.h
@@ -3123,7 +3123,135 @@ public:
   // Iterators
   child_range children() { return child_range(&Temporary, &Temporary + 1); }
 };
-  
+
+/// LambdaExpr - Represents a C++0x lambda expression, e.g.,
+/// @c [&sum] (x) -> void { sum += x; }
+/// Holds related declarations, including the captures and closure type.
+class LambdaExpr : public Expr {
+public:
+  class Capture {
+    enum Kind {
+      CaptureThis,
+      CaptureByCopy,
+      CaptureByRef
+    };
+
+    llvm::PointerIntPair<Expr*, 2, Kind> InitAndKind;
+    SourceLocation Loc;
+
+  public:
+    Capture(CXXThisExpr *Init, SourceLocation Loc)
+      : InitAndKind(Init, CaptureThis), Loc(Loc) {}
+
+    Capture(DeclRefExpr *Init, bool ByRef, SourceLocation Loc)
+      : InitAndKind(Init, ByRef ? CaptureByRef : CaptureByCopy), Loc(Loc) {}
+
+    bool isThisCapture() const { return InitAndKind.getInt() == CaptureThis; }
+    bool isCopyCapture() const { return InitAndKind.getInt() == CaptureByCopy; 
}
+    bool isReferenceCapture() const {
+      return InitAndKind.getInt() == CaptureByRef;
+    }
+
+    /// The initializing Expr for the captured entity. Will be either
+    /// CXXThisExpr or DeclRefExpr.
+    Expr *getInit() const { return InitAndKind.getPointer(); }
+
+    /// Convenience function for variable captures.
+    VarDecl *getVar() const {
+      DeclRefExpr *VarRef = cast<DeclRefExpr>(getInit());
+      return cast<VarDecl>(VarRef->getDecl());
+    }
+
+    // FIXME: Use Expr::getExprLoc instead and save the space for Loc?
+    SourceLocation getLoc() const { return Loc; }
+
+  };
+
+private:
+  /// Array of explicit captures in source order.
+  Capture *Explicits;
+  unsigned NumExplicits;
+
+  /// Declaration for the closure type.
+  CXXRecordDecl *ClosureType;
+
+  /// Declaration for the function call operator of the closure type.
+  /// We cache it here to avoid lookup.
+  CXXMethodDecl *Function;
+
+  /// The temporary object resulting from evaluating the lambda expression,
+  /// represented by a call to the constructor of the closure type.
+  CXXConstructExpr *ClosureObject;
+
+  // FIXME: We can keep this range information separately, or we can go digging
+  // in the ClosureType and Function for the beginning and end every time it is
+  // requested.
+  SourceRange Range;
+  // FIXME: Do we want to keep the location of the end of the introducer?
+
+protected:
+  LambdaExpr(CXXRecordDecl *ClosureType, QualType T,
+             SourceLocation L)
+    : Expr(LambdaExprClass, T, VK_RValue, OK_Ordinary,
+           // FIXME: Support templates and parameter packs later.
+           /*TypeDependent=*/false,
+           /*ValueDependent=*/false,
+           /*InstantiationDependent=*/false,
+           /*ContainsUnexpandedParameterPack=*/false),
+      Explicits(0), NumExplicits(0),
+      ClosureType(ClosureType),
+      Range(L) {}
+
+  explicit LambdaExpr(EmptyShell Empty) : Expr(LambdaExprClass, Empty) {}
+
+public:
+  static LambdaExpr *Create(ASTContext &C, CXXRecordDecl *ClosureType,
+                            const Capture *Explicits, unsigned NumExplicits,
+                            SourceLocation L) {
+    // FIXME: Set the Expr type later. Is that ok? At this point, the type is
+    // incomplete.
+    LambdaExpr *Res = new (C) LambdaExpr(ClosureType, QualType(), L);
+    Res->setExplicits(C, Explicits, NumExplicits);
+    return Res;
+  }
+
+  Capture *getExplicits() const { return Explicits; }
+  unsigned getNumExplicits() const { return NumExplicits; }
+  // FIXME: Should we have this setter?
+  void setExplicits(ASTContext &C, const Capture *E, unsigned N) {
+    size_t Size = N * sizeof(Capture);
+    // Avoid new Capture[] because we don't want to provide a default 
constructor.
+    void *buffer = C.Allocate(Size, llvm::AlignOf<Capture>::Alignment);
+    memcpy(buffer, E, Size);
+    Explicits = static_cast<Capture*>(buffer);
+    NumExplicits = N;
+  }
+
+  CXXRecordDecl *getClosureType() const { return ClosureType; }
+  // FIXME: Should we have this setter?
+  //void setClosureType(CXXRecordDecl *D) { ClosureType = D; }
+
+  CXXMethodDecl *getFunction() const { return Function; }
+  void setFunction(CXXMethodDecl *D) { Function = D; }
+
+  CXXConstructExpr *getClosureObject() const { return ClosureObject; }
+  void setClosureObject(CXXConstructExpr *E) { ClosureObject = E; }
+
+  SourceRange getSourceRange() const { return Range; }
+  // Decl has a virtual getSourceRange and a non-virtual getLocation, leading 
to
+  // duplicate information that needs to be kept in sync.
+  void setLocBegin(SourceLocation L) { Range.setBegin(L); }
+  void setLocEnd(SourceLocation L) { Range.setEnd(L); }
+
+  static bool classof(const Stmt *T) {
+    return T->getStmtClass() == LambdaExprClass;
+  }
+  static bool classof(const LambdaExpr *) { return true; }
+
+  // Required to pass implementation check.
+  child_range children() { return child_range(); }
+};
+
 }  // end namespace clang
 
 #endif
diff --git a/include/clang/AST/RecursiveASTVisitor.h 
b/include/clang/AST/RecursiveASTVisitor.h
index 473ba66..1a6d56c 100644
--- a/include/clang/AST/RecursiveASTVisitor.h
+++ b/include/clang/AST/RecursiveASTVisitor.h
@@ -1901,6 +1901,10 @@ DEF_TRAVERSE_STMT(CXXConstructExpr, { })
 DEF_TRAVERSE_STMT(CallExpr, { })
 DEF_TRAVERSE_STMT(CXXMemberCallExpr, { })
 
+// FIXME: Implement. Is there an order or grouping to these functions?
+// Traverse captures, parameters, return type, body, etc.
+DEF_TRAVERSE_STMT(LambdaExpr, { })
+
 // These exprs (most of them), do not need any action except iterating
 // over the children.
 DEF_TRAVERSE_STMT(AddrLabelExpr, { })
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td 
b/include/clang/Basic/DiagnosticSemaKinds.td
index 89ffebb..d30c8cd 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -1176,6 +1176,20 @@ def err_constexpr_tag : Error<
 def err_constexpr_dtor : Error<"destructor cannot be marked constexpr">;
 def err_constexpr_no_declarators : Error<
   "constexpr can only be used in variable and function declarations">;
+
+// C++0x lambda expressions
+def err_capture_more_than_once : Error<
+  "%0 can appear only once in a capture list">;
+def err_reference_capture_with_reference_default : Error<
+  "'&' cannot precede a capture when the capture default is '&'">;
+def err_this_capture_with_copy_default : Error<
+  "'this' cannot appear in a capture list when the capture default is '='">;
+def err_copy_capture_with_copy_default : Error<
+  "'&' must precede a capture when the capture default is '='">;
+def err_capture_does_not_name_variable : Error<
+  "%0 in capture list does not name a variable">;
+def err_capture_non_automatic_variable : Error<
+  "%0 cannot be captured because it does not have automatic storage duration">;
   
 // Objective-C++
 def err_objc_decls_may_only_appear_in_global_scope : Error<
diff --git a/include/clang/Basic/StmtNodes.td b/include/clang/Basic/StmtNodes.td
index 73996e4..a67dfa2 100644
--- a/include/clang/Basic/StmtNodes.td
+++ b/include/clang/Basic/StmtNodes.td
@@ -123,6 +123,7 @@ def SizeOfPackExpr : DStmt<Expr>;
 def SubstNonTypeTemplateParmExpr : DStmt<Expr>;
 def SubstNonTypeTemplateParmPackExpr : DStmt<Expr>;
 def MaterializeTemporaryExpr : DStmt<Expr>;
+def LambdaExpr : DStmt<Expr>;
 
 // Obj-C Expressions.
 def ObjCStringLiteral : DStmt<Expr>;
diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h
index 07bbd18..b4d5122 100644
--- a/include/clang/Sema/Sema.h
+++ b/include/clang/Sema/Sema.h
@@ -98,6 +98,7 @@ namespace clang {
   class InitializedEntity;
   class IntegerLiteral;
   class LabelStmt;
+  class LambdaExpr;
   class LangOptions;
   class LocalInstantiationScope;
   class LookupResult;
@@ -4949,6 +4950,16 @@ public:
   DeclContext *FindInstantiatedContext(SourceLocation Loc, DeclContext *DC,
                           const MultiLevelTemplateArgumentList &TemplateArgs);
 
+  
//===--------------------------------------------------------------------===//
+  // C++ Lambda Expressions (C++0x [expr.prim.lambda])
+
+  // FIXME: Is there a better way to pass the Lambda from through each action?
+  // The introducer does not begin a function scope, so cannot mimic blocks.
+  ExprResult ActOnLambdaIntroducer(const LambdaIntroducer &Intro);
+  void ActOnLambdaDeclarator(LambdaExpr *Lambda, Declarator &D);
+  void ActOnLambdaBody(LambdaExpr *Lambda, Stmt *Body);
+
+  
//===--------------------------------------------------------------------===//
   // Objective-C declarations.
   Decl *ActOnStartClassInterface(SourceLocation AtInterfaceLoc,
                                  IdentifierInfo *ClassName,
diff --git a/include/clang/Serialization/ASTBitCodes.h 
b/include/clang/Serialization/ASTBitCodes.h
index 166a7b9..bb4d83f 100644
--- a/include/clang/Serialization/ASTBitCodes.h
+++ b/include/clang/Serialization/ASTBitCodes.h
@@ -1051,6 +1051,9 @@ namespace clang {
       EXPR_SUBST_NON_TYPE_TEMPLATE_PARM_PACK,// 
SubstNonTypeTemplateParmPackExpr
       EXPR_MATERIALIZE_TEMPORARY, // MaterializeTemporaryExpr
       
+      /// \brief LambdaExpr
+      EXPR_LAMBDA,
+
       // CUDA
       EXPR_CUDA_KERNEL_CALL,       // CUDAKernelCallExpr      
 
diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp
index 79f14bc..a97867d 100644
--- a/lib/AST/StmtPrinter.cpp
+++ b/lib/AST/StmtPrinter.cpp
@@ -1503,6 +1503,10 @@ 
StmtPrinter::VisitObjCBridgedCastExpr(ObjCBridgedCastExpr *E) {
   PrintExpr(E->getSubExpr());
 }
 
+// FIXME: Implement. Is there an order or grouping to these functions?
+void StmtPrinter::VisitLambdaExpr(LambdaExpr *Node) {
+}
+
 void StmtPrinter::VisitBlockExpr(BlockExpr *Node) {
   BlockDecl *BD = Node->getBlockDecl();
   OS << "^";
diff --git a/lib/AST/StmtProfile.cpp b/lib/AST/StmtProfile.cpp
index 12321ef..8579df6 100644
--- a/lib/AST/StmtProfile.cpp
+++ b/lib/AST/StmtProfile.cpp
@@ -449,6 +449,10 @@ void StmtProfiler::VisitBlockExpr(const BlockExpr *S) {
   VisitDecl(S->getBlockDecl());
 }
 
+// FIXME: Implement. Is there an order or grouping to these functions?
+void StmtProfiler::VisitLambdaExpr(const LambdaExpr *S) {
+}
+
 void StmtProfiler::VisitBlockDeclRefExpr(const BlockDeclRefExpr *S) {
   VisitExpr(S);
   VisitDecl(S->getDecl());
diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp
index 757d86e..4599471 100644
--- a/lib/Parse/ParseExprCXX.cpp
+++ b/lib/Parse/ParseExprCXX.cpp
@@ -672,8 +672,24 @@ bool Parser::TryParseLambdaIntroducer(LambdaIntroducer 
&Intro) {
 /// expression.
 ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
                      LambdaIntroducer &Intro) {
+  ExprResult MaybeLambda = Actions.ActOnLambdaIntroducer(Intro);
+  if (!MaybeLambda.isUsable())
+    return ExprError();
+
+  // FIXME: get vs. take vs. release vs. takeAs?
+  // FIXME: I presume we cannot use static_cast since we do not have base class
+  // information for LambdaExpr? Why can't we use llvm::cast? I have a feeling
+  // reinterpret_cast is wrong.
+  LambdaExpr *Lambda = reinterpret_cast<LambdaExpr*>(MaybeLambda.take());
+
   // Parse lambda-declarator[opt].
   DeclSpec DS(AttrFactory);
+  {
+    const char *PrevSpec = 0;
+    unsigned DiagID = 0;
+    bool HasPrevSpec = DS.SetTypeSpecType(TST_auto, /*Loc=*/SourceLocation(), 
PrevSpec, DiagID);
+    assert(!HasPrevSpec && !PrevSpec && "unexpected default type specifier!");
+  }
   Declarator D(DS, Declarator::PrototypeContext);
 
   if (Tok.is(tok::l_paren)) {
@@ -747,6 +763,8 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
                   Attr, DeclEndLoc);
   }
 
+  Actions.ActOnLambdaDeclarator(Lambda, D);
+
   // Parse compound-statement.
   if (Tok.is(tok::l_brace)) {
     // FIXME: Rename BlockScope -> ClosureScope if we decide to continue using
@@ -758,6 +776,9 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
     StmtResult Stmt(ParseCompoundStatementBody());
 
     BodyScope.Exit();
+
+    if (!Stmt.isInvalid())
+      Actions.ActOnLambdaBody(Lambda, Stmt.take());
   } else {
     Diag(Tok, diag::err_expected_lambda_body);
   }
diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp
index 4f49463..514df8f 100644
--- a/lib/Sema/SemaExprCXX.cpp
+++ b/lib/Sema/SemaExprCXX.cpp
@@ -4655,3 +4655,406 @@ bool Sema::CheckMicrosoftIfExistsSymbol(CXXScopeSpec 
&SS,
   LookupParsedName(R, getCurScope(), &SS);
   return !R.empty(); 
 }
+
+// FIXME: Several areas in the below ActOnLambda* functions may benefit from
+// calling existing Sema functions, or from factoring out some essential bits 
to
+// share. These are marked with FIXMEs that begin "Compare with ...".
+//
+// Additionally, there are a few checks sprinkled throughout these actions
+// merely to ensure their correct implementation. I did not think it worth
+// wrapping them in separate functions just so they can be asserted. They 
should
+// be removed after code review for performance reasons. They are marked with
+// FIXMEs stating "Remove this check later.".
+ExprResult Sema::ActOnLambdaIntroducer(const LambdaIntroducer &Intro) {
+  // Diagnose and build the explicit capture list. Erroneous captures are
+  // skipped as if they did not exist.
+  SourceLocation CapturesThis;
+  llvm::DenseMap<const IdentifierInfo*, SourceLocation> CapturesSoFar;
+  llvm::SmallVector<LambdaExpr::Capture, 4> Explicits;
+
+  for (llvm::SmallVector<LambdaCapture, 4>::const_iterator
+       C = Intro.Captures.begin(), E = Intro.Captures.end(); C != E; ++C) {
+    if (C->Kind == LCK_This) {
+      if (CapturesThis.isValid()) {
+        Diag(C->Loc, diag::err_capture_more_than_once) << "'this'"
+          << CapturesThis
+          << FixItHint::CreateRemoval(C->Loc);
+        continue;
+      }
+
+      if (Intro.Default == LCD_ByCopy) {
+        Diag(C->Loc, diag::err_this_capture_with_copy_default)
+          << FixItHint::CreateRemoval(C->Loc);
+        continue;
+      }
+
+      ExprResult ThisRes = ActOnCXXThis(C->Loc);
+      if (!ThisRes.isUsable()) {
+        // Already diagnosed the error.
+        continue;
+      }
+
+      CapturesThis = C->Loc;
+      CXXThisExpr *This = static_cast<CXXThisExpr*>(ThisRes.take());
+      Explicits.push_back(LambdaExpr::Capture(This, C->Loc));
+      continue;
+    }
+
+    assert(C->Id && "missing identifier for capture");
+
+    if (C->Kind == LCK_ByRef && Intro.Default == LCD_ByRef) {
+      Diag(C->Loc, diag::err_reference_capture_with_reference_default)
+        << FixItHint::CreateRemoval(C->Loc);
+      continue;
+    } else if (C->Kind == LCK_ByCopy && Intro.Default == LCD_ByCopy) {
+      Diag(C->Loc, diag::err_copy_capture_with_copy_default)
+        << FixItHint::CreateRemoval(C->Loc);
+      continue;
+    }
+
+    llvm::DenseMap<const IdentifierInfo*, SourceLocation>::iterator Appearance;
+    bool IsFirstAppearance;
+    llvm::tie(Appearance, IsFirstAppearance)
+      = CapturesSoFar.insert(std::make_pair(C->Id, C->Loc));
+
+    if (!IsFirstAppearance) {
+      // FIXME: These fix-its do not handle associated ampersands or commas.
+      Diag(C->Loc, diag::err_capture_more_than_once) << C->Id
+        << Appearance->second
+        << FixItHint::CreateRemoval(C->Loc);
+      continue;
+    }
+
+    UnqualifiedId Name;
+    CXXScopeSpec ScopeSpec;
+    Name.setIdentifier(C->Id, C->Loc);
+    // FIXME: Can we do better than ActOnIdExpression?
+    DeclRefExpr *VarRef
+      = static_cast<DeclRefExpr*>(
+          ActOnIdExpression(getCurScope(),
+                            ScopeSpec, Name,
+                            /*HasTrailingLParen=*/false,
+                            /*IsAddressOfOperand=*/false).take());
+
+    // Check that we have a local variable with automatic storage duration.
+    if (VarDecl *Var = dyn_cast<VarDecl>(VarRef->getDecl())) {
+      // FIXME: This accepts register variables. What is the correct test?
+      if (!Var->hasLocalStorage())
+        Diag(C->Loc, diag::err_capture_non_automatic_variable) << C->Id;
+    } else {
+      Diag(C->Loc, diag::err_capture_does_not_name_variable) << C->Id;
+    }
+
+    Explicits.push_back(
+      LambdaExpr::Capture(VarRef, C->Kind == LCK_ByRef, C->Loc));
+  }
+
+  // Find the nearest block, class, or namespace scope.
+  DeclContext *DC = CurContext;
+  while (!(DC->isFunctionOrMethod() || DC->isRecord() || DC->isNamespace()))
+    DC = DC->getParent();
+
+  CXXRecordDecl *Class = CXXRecordDecl::Create(Context,
+                                               TTK_Class,
+                                               DC,
+                                               Intro.Range.getBegin(),
+                                               /*IdLoc=*/SourceLocation(),
+                                               /*Id=*/0);
+  Class->startDefinition();
+
+  LambdaExpr *Lambda = LambdaExpr::Create(Context, Class,
+                                          Explicits.data(), Explicits.size(),
+                                          Intro.Range.getBegin());
+  // This gets set again as we move along.
+  Lambda->setLocEnd(Intro.Range.getEnd());
+
+  return ExprResult(Lambda);
+}
+
+void Sema::ActOnLambdaDeclarator(LambdaExpr *Lambda, Declarator &D) {
+  Lambda->setLocEnd(D.getSourceRange().getEnd());
+
+  CXXRecordDecl *Class = Lambda->getClosureType();
+
+  QualType MethodTy;
+  TypeSourceInfo *MethodTyInfo;
+  if (D.getNumTypeObjects() == 0) {
+    MethodTy = Context.getFunctionType(Context.VoidTy,
+                                       /*Args=*/0,
+                                       /*NumArgs=*/0,
+                                       FunctionProtoType::ExtProtoInfo());
+    MethodTyInfo = Context.getTrivialTypeSourceInfo(MethodTy);
+  } else {
+    assert(D.isFunctionDeclarator() && "non-function lambda-declarator!");
+    DeclaratorChunk::FunctionTypeInfo &Fun = D.getFunctionTypeInfo();
+    if (!Fun.TrailingReturnType) {
+      Fun.TrailingReturnType = Context.VoidTy.getAsOpaquePtr();
+    }
+    // FIXME: The scope is unused?
+    MethodTyInfo = GetTypeForDeclarator(D, getCurScope());
+    // FIXME: Unsure of how to deal with this error. Any problems building the
+    // DeclaratorChunk should have been dealt with earlier, correct? I expect
+    // that we would have a void() function type at worst.
+    // If we can fail here, then probably need to return true to indicate
+    // failure, and have the caller in Parser skip over the rest of the
+    // expression and return ExprError.
+    assert(MethodTyInfo && "no type from lambda-declarator!");
+    MethodTy = MethodTyInfo->getType();
+  }
+
+  assert(MethodTy->isFunctionType() &&
+         "no function type from lambda-declarator!");
+  DeclarationName MethodName
+    = Context.DeclarationNames.getCXXOperatorName(OO_Call);
+  CXXMethodDecl *Method
+    = CXXMethodDecl::Create(Context,
+                            Class,
+                            D.getSourceRange().getBegin(),
+                            DeclarationNameInfo(MethodName,
+                                                /*NameLoc=*/SourceLocation()),
+                            MethodTy,
+                            MethodTyInfo,
+                            /*isStatic=*/false,
+                            SC_None,
+                            /*isInline=*/true,
+                            /*isConstExpr=*/false,
+                            D.getSourceRange().getEnd());
+
+  // FIXME: It appears we can get the ParmVarDecls through either the
+  // Declarator, a la Sema::ActOnMethodDeclaration, or through the
+  // TypeSourceInfo, a la Sema::ActOnBlockArguments. Which is preferred? What 
do
+  // TypeSourceInfo and TypeLoc represent?
+  assert(isa<FunctionProtoTypeLoc>(MethodTyInfo->getTypeLoc()) &&
+         "no function type from lambda-declarator!");
+  FunctionProtoTypeLoc MethodTypeLoc
+    = cast<FunctionProtoTypeLoc>(MethodTyInfo->getTypeLoc());
+  Method->setParams(MethodTypeLoc.getParmArray(), MethodTypeLoc.getNumArgs());
+
+  // FIXME: Remove this check later.
+  bool Redeclaration = false;
+  LookupResult Previous(*this,
+                        MethodName,
+                        SourceLocation(),
+                        LookupOrdinaryName,
+                        ForRedeclaration);
+  CheckFunctionDeclaration(getCurScope(),
+                           Method,
+                           Previous,
+                           /*IsExplicitSpecialization=*/false,
+                           Redeclaration);
+  assert(!Method->isInvalidDecl() && "bad lambda constructor");
+
+  Class->addDecl(Method);
+
+  Lambda->setFunction(Method);
+}
+
+void Sema::ActOnLambdaBody(LambdaExpr *Lambda, Stmt *Body) {
+  Lambda->setLocEnd(Body->getLocEnd());
+
+  CXXRecordDecl *Class = Lambda->getClosureType();
+  CanQualType ClassType
+    = Context.getCanonicalType(Context.getTypeDeclType(Class));
+
+  CXXMethodDecl *Method = Lambda->getFunction();
+  Method->setBody(Body);
+
+  DeclarationName CtorName
+    = Context.DeclarationNames.getCXXConstructorName(ClassType);
+  CXXConstructorDecl *Ctor
+    = CXXConstructorDecl::Create(Context,
+                                 Class,
+                                 /*StartLoc=*/SourceLocation(),
+                                 DeclarationNameInfo(CtorName,
+                                                  
/*NameLoc=*/SourceLocation()),
+                                 // Chicken and egg problem: we need the Ctor 
to
+                                 // build the CtorParams and the CtorParams to
+                                 // build the Ctor. Favor one call on the Ctor
+                                 // to set its type after construction instead
+                                 // of one call on each CtorParam to set their
+                                 // DeclContext.
+                                 QualType(),
+                                 /*TInfo=*/0,
+                                 /*isExplicit=*/true,
+                                 /*isInline=*/true,
+                                 /*isImplicitlyDeclared=*/true,
+                                 /*isConstExpr=*/false);
+
+  // FIXME: When we support implicit captures later, this number will need to 
be
+  // updated.
+  unsigned NumCaptures = Lambda->getNumExplicits();
+
+  llvm::SmallVector<QualType, 4> CtorParamTys;
+  CtorParamTys.reserve(NumCaptures);
+  llvm::SmallVector<ParmVarDecl*, 4> CtorParams;
+  CtorParams.reserve(NumCaptures);
+  CXXCtorInitializer **CtorInits
+    = new (Context) CXXCtorInitializer*[NumCaptures];
+  llvm::SmallVector<Expr*, 4> CtorArgs;
+  CtorArgs.reserve(NumCaptures);
+
+
+  CXXCtorInitializer **CtorInit = CtorInits;
+  // FIXME: Add some capture iterators to LambdaExpr.
+  for (LambdaExpr::Capture *C = Lambda->getExplicits(),
+       *E = Lambda->getExplicits() + Lambda->getNumExplicits(); C != E; ++C) {
+
+    Expr *Init = C->getInit();
+
+    IdentifierInfo *Id;
+    if (C->isThisCapture()) {
+      Id = PP.getIdentifierInfo("__this");
+    } else {
+      Id = cast<DeclRefExpr>(Init)->getDecl()->getIdentifier();
+    }
+
+    SourceLocation CaptureLoc = C->getLoc();
+    DeclarationName CaptureName
+      = Context.DeclarationNames.getIdentifier(Id);
+
+    // FIXME: Find the correct type. There are capture type transformations
+    // remaining to be implemented. What is the difference between CanQualType
+    // and QualType? How is template instantiation handled? If some of these
+    // have dependent type, how is that treated?
+    QualType CaptureType = Init->getType();
+    if (C->isReferenceCapture()) {
+      // FIXME: Compare with Sema::BuildReferenceType.
+      CaptureType = Context.getLValueReferenceType(CaptureType,
+                                                   /*SpelledAsLValue=*/true);
+    }
+
+    FieldDecl *Field = CheckFieldDecl(CaptureName,
+                                      CaptureType,
+                                      /*TInfo=*/0,
+                                      Class,
+                                      CaptureLoc,
+                                      /*Mutable=*/false,
+                                      /*BitWidth=*/0,
+                                      /*HasInit=*/false,
+                                      // FIXME: Pass IdLoc? We haven't for 
other
+                                      // declarations so far, but fields are 
the
+                                      // only ones we have names for in the
+                                      // source.
+                                      CaptureLoc,
+                                      AS_private,
+                                      /*PrevDecl=*/0);
+
+    Class->addDecl(Field);
+
+    // FIXME: Compare with Sema::CheckParameter.
+    ParmVarDecl *CtorParam = ParmVarDecl::Create(Context,
+                                                 Ctor,
+                                                 CaptureLoc,
+                                                 CaptureLoc,
+                                                 Id,
+                                  
Context.getAdjustedParameterType(CaptureType),
+                                                 /*TInfo=*/0,
+                                                 SC_None,
+                                                 SC_None,
+                                                 /*DefArg=*/0);
+
+    CtorParamTys.push_back(CaptureType);
+    CtorParams.push_back(CtorParam);
+
+    {
+      // FIXME: Have to use Expr* instead of DeclRefExpr* because we cannot
+      // convert from DeclRefExpr** to Expr**. Why?
+      Expr *CtorInitArg
+        = DeclRefExpr::Create(Context,
+                              /*QualifierLoc=*/NestedNameSpecifierLoc(),
+                              CtorParam,
+                              CaptureLoc,
+                              CaptureType.getNonReferenceType(),
+                              VK_LValue);
+
+      // FIXME: Compare with Sema::BuildMemberInitializer.
+      //*CtorInit = new (Context) CXXCtorInitializer(Context,
+                                                   //Field,
+                                                   //CaptureLoc,
+                                                   ///*L=*/SourceLocation(),
+                                                   //CtorInitArg,
+                                                   ///*R=*/SourceLocation());
+      MemInitResult Res = BuildMemberInitializer(Field,
+                                                 &CtorInitArg,
+                                                 /*NumArgs=*/1u,
+                                                 CaptureLoc,
+                                                 /*L=*/SourceLocation(),
+                                                 /*R=*/SourceLocation());
+
+      // FIXME: If there was an error, it is probably a bug, right?
+      assert(Res.isUsable() && "bad member initializer!");
+      *CtorInit = Res.take();
+      ++CtorInit;
+    }
+
+    CtorArgs.push_back(Init);
+  }
+
+  assert(CtorParamTys.size() == NumCaptures &&
+         "missed a constructor parameter type!");
+  assert(CtorParams.size() == NumCaptures && "missed a constructor 
parameter!");
+  assert(CtorArgs.size() == NumCaptures && "missed a constructor argument!");
+
+  // FIXME: Compare with Sema::BuildFunctionType.
+  QualType CtorType = Context.getFunctionType(Context.VoidTy,
+                                              CtorParamTys.data(),
+                                              CtorParamTys.size(),
+                                              
FunctionProtoType::ExtProtoInfo());
+
+  Ctor->setAccess(AS_public);
+  Ctor->setImplicit();
+  Ctor->setType(CtorType);
+  // FIXME: Compare with Sema::CheckParmsForFunctionDef.
+  Ctor->setParams(CtorParams.data(), CtorParams.size());
+  // FIXME: Compare with Sema::ActOnMemInitializers.
+  // FIXME: Compare with Sema::SetCtorInitializers.
+  Ctor->setNumCtorInitializers(NumCaptures);
+  Ctor->setCtorInitializers(CtorInits);
+
+  // FIXME: Remove this check later.
+  bool Redeclaration = false;
+  LookupResult Previous(*this,
+                        CtorName,
+                        SourceLocation(),
+                        LookupOrdinaryName,
+                        ForRedeclaration);
+  CheckFunctionDeclaration(getCurScope(),
+                           Ctor,
+                           Previous,
+                           /*IsExplicitSpecialization=*/false,
+                           Redeclaration);
+  assert(!Ctor->isInvalidDecl() && "bad lambda constructor");
+
+  Class->addDecl(Ctor);
+
+  Class->completeDefinition();
+  // FIXME: Remove this check later.
+  CheckCompletedCXXClass(Class);
+
+  {
+    // FIXME: Compare with Sema::BuildCXXConstructExpr.
+    //CXXConstructExpr *CtorCall = CXXConstructExpr::Create(Context,
+                                                          //CtorType,
+                                                        
//Lambda->getLocStart(),
+                                                          //Ctor,
+                                                          ///*Elidable=*/false,
+                                                          //CtorArgs.data(),
+                                                          //CtorArgs.size());
+    ExprResult Res = BuildCXXConstructExpr(Lambda->getLocStart(),
+                                           CtorType,
+                                           Ctor,
+                                           /*Elidable=*/false,
+                                           MultiExprArg(CtorArgs.data(),
+                                                        CtorArgs.size()),
+                                           /*RequiresZeroInit=*/false,
+                                           CXXConstructExpr::CK_Complete,
+                                           /*ParenRange=*/SourceRange());
+
+    // FIXME: If there was an error, it is probably a bug, right?
+    assert(Res.isUsable() && "bad lambda construction!");
+
+    CXXConstructExpr *CtorCall = Res.takeAs<CXXConstructExpr>();
+    Lambda->setClosureObject(CtorCall);
+  }
+}
+
diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h
index 12eba29..790e2cd 100644
--- a/lib/Sema/TreeTransform.h
+++ b/lib/Sema/TreeTransform.h
@@ -7934,6 +7934,12 @@ 
TreeTransform<Derived>::TransformShuffleVectorExpr(ShuffleVectorExpr *E) {
 
 template<typename Derived>
 ExprResult
+TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
+  return ExprEmpty();
+}
+
+template<typename Derived>
+ExprResult
 TreeTransform<Derived>::TransformBlockExpr(BlockExpr *E) {
   BlockDecl *oldBlock = E->getBlockDecl();
   
diff --git a/lib/Serialization/ASTReaderStmt.cpp 
b/lib/Serialization/ASTReaderStmt.cpp
index cfe46d7..e2e8c15 100644
--- a/lib/Serialization/ASTReaderStmt.cpp
+++ b/lib/Serialization/ASTReaderStmt.cpp
@@ -741,6 +741,10 @@ void 
ASTStmtReader::VisitShuffleVectorExpr(ShuffleVectorExpr *E) {
   E->setRParenLoc(ReadSourceLocation(Record, Idx));
 }
 
+// FIXME: Implement. Is there an order or grouping to these functions?
+void ASTStmtReader::VisitLambdaExpr(LambdaExpr *E) {
+}
+
 void ASTStmtReader::VisitBlockExpr(BlockExpr *E) {
   VisitExpr(E);
   E->setBlockDecl(ReadDeclAs<BlockDecl>(Record, Idx));
diff --git a/lib/Serialization/ASTWriterStmt.cpp 
b/lib/Serialization/ASTWriterStmt.cpp
index f0636a1..f362861 100644
--- a/lib/Serialization/ASTWriterStmt.cpp
+++ b/lib/Serialization/ASTWriterStmt.cpp
@@ -701,6 +701,10 @@ void 
ASTStmtWriter::VisitShuffleVectorExpr(ShuffleVectorExpr *E) {
   Code = serialization::EXPR_SHUFFLE_VECTOR;
 }
 
+// FIXME: Implement. Is there an order or grouping to these functions?
+void ASTStmtWriter::VisitLambdaExpr(LambdaExpr *E) {
+}
+
 void ASTStmtWriter::VisitBlockExpr(BlockExpr *E) {
   VisitExpr(E);
   Writer.AddDeclRef(E->getBlockDecl(), Record);
diff --git a/test/Parser/objcxx0x-lambda-expressions.mm 
b/test/Parser/objcxx0x-lambda-expressions.mm
index d100e2e..8d2d9f6 100644
--- a/test/Parser/objcxx0x-lambda-expressions.mm
+++ b/test/Parser/objcxx0x-lambda-expressions.mm
@@ -9,7 +9,7 @@ class C {
     [foo,+] {}; // expected-error {{expected expression}}
 
     []; // expected-error {{expected body of lambda expression}}
-    [=,foo+] {}; // expected-error {{expected ',' or ']' in lambda capture 
list}}
+    [=,&foo+] {}; // expected-error {{expected ',' or ']' in lambda capture 
list}}
     [&this] {}; // expected-error {{address expression must be an lvalue}}
     [] {};
     [=] (int i) {};
diff --git a/test/SemaCXX/lambda-expressions.cpp 
b/test/SemaCXX/lambda-expressions.cpp
new file mode 100644
index 0000000..60378ed
--- /dev/null
+++ b/test/SemaCXX/lambda-expressions.cpp
@@ -0,0 +1,17 @@
+// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
+
+class C {
+  void f() {
+    int foo;
+
+    [foo, foo] () {}; // expected-error {{'foo' can appear only once}}
+    [this, this] () {}; // expected-error {{'this' can appear only once}}
+    [=, foo] () {}; // expected-error {{'&' must precede a capture when}}
+    [=, &foo] () {};
+    [=, this] () {}; // expected-error {{'this' cannot appear}}
+    [&, foo] () {};
+    [&, &foo] () {}; // expected-error {{'&' cannot precede a capture when}}
+    [&, this] () {};
+  }
+};
+
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits

Reply via email to