diff --git a/include/clang/AST/ExprCXX.h b/include/clang/AST/ExprCXX.h
index 3cc09cd..5063d30 100644
--- a/include/clang/AST/ExprCXX.h
+++ b/include/clang/AST/ExprCXX.h
@@ -3142,7 +3142,111 @@ public:
   // Iterators
   child_range children() { return child_range(&Temporary, &Temporary + 1); }
 };
-  
+
+/// LambdaExpr - Represents a C++0x lambda expression, e.g.,
+/// @c [&sum] (int x) -> void { sum += x; }
+/// Holds related declarations, including the captures and closure type.
+class LambdaExpr : public Expr {
+public:
+  /// \brief Describes the capture of either a variable or 'this'.
+  class Capture {
+    llvm::PointerIntPair<Expr*, 2, LambdaCaptureKind> InitAndKind;
+
+  public:
+    Capture(Expr *Init, LambdaCaptureKind Kind)
+      : InitAndKind(Init, Kind) {}
+
+    Capture(CXXThisExpr *Init)
+      : InitAndKind(Init, LCK_This) {}
+
+    bool isThisCapture() const { return InitAndKind.getInt() == LCK_This; }
+    bool isVariableCapture() const { return !isThisCapture(); }
+    bool isCopyCapture() const { return InitAndKind.getInt() == LCK_ByCopy; }
+    bool isReferenceCapture() const { return InitAndKind.getInt() == LCK_ByRef; }
+
+    /// The initializing Expr for the captured entity. Will be either
+    /// CXXThisExpr or DeclRefExpr.
+    Expr *getInitializer() const { return InitAndKind.getPointer(); }
+
+    /// Convenience function for variable captures.
+    VarDecl *getVariable() const {
+      assert(isVariableCapture() && "expected variable capture");
+      DeclRefExpr *VarRef = cast<DeclRefExpr>(getInitializer());
+      return cast<VarDecl>(VarRef->getDecl());
+    }
+
+    SourceLocation getLoc() const { return getInitializer()->getExprLoc(); }
+
+  };
+
+private:
+  /// \brief The capture mode for implicit captures.
+  LambdaCaptureDefault Default;
+
+  /// \brief The number of explicit captures.
+  /// The explicit captures are stored in source order in an array past the
+  /// end of the LambdaExpr.
+  unsigned NumExplicits;
+
+  /// 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;
+
+  /// Convenience functions to access the array of explicit captures.
+  Capture *getExplicits() { return reinterpret_cast<Capture *>(this + 1); }
+  const Capture *getExplicits() const {
+    return reinterpret_cast<const Capture *>(this + 1);
+  }
+
+protected:
+  LambdaExpr(QualType T, LambdaCaptureDefault Default,
+             ArrayRef<Capture> Explicits);
+  explicit LambdaExpr(EmptyShell Empty) : Expr(LambdaExprClass, Empty) {}
+
+public:
+  static LambdaExpr *Create(ASTContext &C, CXXRecordDecl *ClosureType,
+                            LambdaCaptureDefault Default,
+                            ArrayRef<Capture> Explicits);
+
+  LambdaCaptureDefault getDefault() const { return Default; }
+  unsigned getNumExplicits() const { return NumExplicits; }
+
+  typedef const Capture *capture_iterator;
+  typedef const Capture *capture_const_iterator;
+
+  capture_iterator explicits_begin() { return getExplicits(); }
+  capture_iterator explicits_end() { return getExplicits() + NumExplicits; }
+  capture_const_iterator explicits_begin() const { return getExplicits(); }
+  capture_const_iterator explicits_end() const {
+    return getExplicits() + NumExplicits;
+  }
+
+  /// \brief Retrieve the declaration of the generated closure type.
+  CXXRecordDecl *getClosureType() const {
+    return getType()->getAsCXXRecordDecl();
+  }
+
+  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;
+
+  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 0ec09c9..e14518f 100644
--- a/include/clang/AST/RecursiveASTVisitor.h
+++ b/include/clang/AST/RecursiveASTVisitor.h
@@ -1909,6 +1909,12 @@ DEF_TRAVERSE_STMT(CXXConstructExpr, { })
 DEF_TRAVERSE_STMT(CallExpr, { })
 DEF_TRAVERSE_STMT(CXXMemberCallExpr, { })
 
+// FIXME: Implement.
+// Traverse captures, parameters, return type, body, etc.
+DEF_TRAVERSE_STMT(LambdaExpr, {
+  llvm_unreachable("unimplemented");
+})
+
 // These exprs (most of them), do not need any action except iterating
 // over the children.
 DEF_TRAVERSE_STMT(AddrLabelExpr, { })
diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h
index 5a1200c..59bc161 100644
--- a/include/clang/AST/Type.h
+++ b/include/clang/AST/Type.h
@@ -109,6 +109,7 @@ namespace clang {
 /// * Objective C: the GC attributes (none, weak, or strong)
 class Qualifiers {
 public:
+  // FIXME: Why not just move this enum to Basic?
   enum TQ { // NOTE: These flags must be kept in sync with DeclSpec::TQ.
     Const    = 0x1,
     Restrict = 0x2,
diff --git a/include/clang/AST/TypeLoc.h b/include/clang/AST/TypeLoc.h
index 20acada..8e6e730 100644
--- a/include/clang/AST/TypeLoc.h
+++ b/include/clang/AST/TypeLoc.h
@@ -1077,6 +1077,10 @@ public:
     getLocalData()->TrailingReturn = Trailing;
   }
 
+  ArrayRef<ParmVarDecl *> getParams() const {
+    return ArrayRef<ParmVarDecl *>(getParmArray(), getNumArgs());
+  }
+
   // ParmVarDecls* are stored after Info, one for each argument.
   ParmVarDecl **getParmArray() const {
     return (ParmVarDecl**) getExtraLocalData();
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index 1fb8fb8..4425737 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -1274,6 +1274,20 @@ def note_non_literal_nontrivial_dtor : Note<
 def note_non_literal_mutable_field : Note<
   "%0 is not literal because it has a mutable data member">;
  
+// C++11 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<
   "Objective-C declarations may only appear in global scope">;
diff --git a/include/clang/Basic/Specifiers.h b/include/clang/Basic/Specifiers.h
index 2a95d61..dfff637 100644
--- a/include/clang/Basic/Specifiers.h
+++ b/include/clang/Basic/Specifiers.h
@@ -162,6 +162,21 @@ namespace clang {
   inline bool isLegalForVariable(StorageClass SC) {
     return true;
   }
+
+  /// The default, if any, capture method for a lambda expression.
+  enum LambdaCaptureDefault {
+    LCD_None,
+    LCD_ByCopy,
+    LCD_ByRef
+  };
+
+  /// The different capture forms in a lambda introducer: 'this' or a copied
+  /// or referenced variable.
+  enum LambdaCaptureKind {
+    LCK_This,
+    LCK_ByCopy,
+    LCK_ByRef
+  };
 } // end namespace clang
 
 #endif // LLVM_CLANG_BASIC_SPECIFIERS_H
diff --git a/include/clang/Basic/StmtNodes.td b/include/clang/Basic/StmtNodes.td
index 7b3d776..6b67f6f 100644
--- a/include/clang/Basic/StmtNodes.td
+++ b/include/clang/Basic/StmtNodes.td
@@ -126,6 +126,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/DeclSpec.h b/include/clang/Sema/DeclSpec.h
index 3260a70..9f21c8a 100644
--- a/include/clang/Sema/DeclSpec.h
+++ b/include/clang/Sema/DeclSpec.h
@@ -1855,23 +1855,7 @@ private:
   SourceLocation LastLocation;
 };
 
-/// LambdaCaptureDefault - The default, if any, capture method for a
-/// lambda expression.
-enum LambdaCaptureDefault {
-  LCD_None,
-  LCD_ByCopy,
-  LCD_ByRef
-};
-
-/// LambdaCaptureKind - The different capture forms in a lambda
-/// introducer: 'this' or a copied or referenced variable.
-enum LambdaCaptureKind {
-  LCK_This,
-  LCK_ByCopy,
-  LCK_ByRef
-};
-
-/// LambdaCapture - An individual capture in a lambda introducer.
+/// An individual capture in a lambda introducer.
 struct LambdaCapture {
   LambdaCaptureKind Kind;
   SourceLocation Loc;
@@ -1884,7 +1868,7 @@ struct LambdaCapture {
   {}
 };
 
-/// LambdaIntroducer - Represents a complete lambda introducer.
+/// Represents a complete lambda introducer.
 struct LambdaIntroducer {
   SourceRange Range;
   LambdaCaptureDefault Default;
@@ -1893,7 +1877,7 @@ struct LambdaIntroducer {
   LambdaIntroducer()
     : Default(LCD_None) {}
 
-  /// addCapture - Append a capture in a lambda introducer.
+  /// Append a capture in a lambda introducer.
   void addCapture(LambdaCaptureKind Kind,
                   SourceLocation Loc,
                   IdentifierInfo* Id = 0) {
diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h
index 22d5db2..524a5d1 100644
--- a/include/clang/Sema/Sema.h
+++ b/include/clang/Sema/Sema.h
@@ -100,6 +100,7 @@ namespace clang {
   class InitializedEntity;
   class IntegerLiteral;
   class LabelStmt;
+  class LambdaExpr;
   class LangOptions;
   class LocalInstantiationScope;
   class LookupResult;
@@ -5077,6 +5078,14 @@ public:
   DeclContext *FindInstantiatedContext(SourceLocation Loc, DeclContext *DC,
                           const MultiLevelTemplateArgumentList &TemplateArgs);
 
+  //===--------------------------------------------------------------------===//
+  // C++ Lambda Expressions (C++0x [expr.prim.lambda])
+
+  ExprResult ActOnLambdaIntroducer(Scope *S, const LambdaIntroducer &Intro);
+  void ActOnLambdaDeclarator(Scope *S, Expr *Lambda, Declarator &D);
+  void ActOnLambdaBody(Scope *S, Expr *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 dc4d05c..5ea717d 100644
--- a/include/clang/Serialization/ASTBitCodes.h
+++ b/include/clang/Serialization/ASTBitCodes.h
@@ -1081,6 +1081,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/Expr.cpp b/lib/AST/Expr.cpp
index b0bcfe0..f8f69d7 100644
--- a/lib/AST/Expr.cpp
+++ b/lib/AST/Expr.cpp
@@ -1616,6 +1616,7 @@ bool Expr::isUnusedResultAWarning(SourceLocation &Loc, SourceRange &R1,
 
   case CXXTemporaryObjectExprClass:
   case CXXConstructExprClass:
+  case LambdaExprClass:
     return false;
 
   case ObjCMessageExprClass: {
diff --git a/lib/AST/ExprCXX.cpp b/lib/AST/ExprCXX.cpp
index ad5ec8b..5e84187 100644
--- a/lib/AST/ExprCXX.cpp
+++ b/lib/AST/ExprCXX.cpp
@@ -1020,4 +1020,39 @@ TemplateArgument SubstNonTypeTemplateParmPackExpr::getArgumentPack() const {
   return TemplateArgument(Arguments, NumArguments);
 }
 
+LambdaExpr::LambdaExpr(QualType T, LambdaCaptureDefault Default,
+                       ArrayRef<Capture> Explicits)
+  : Expr(LambdaExprClass, T, VK_RValue, OK_Ordinary,
+         // If T is dependent, then the lambda must be inside a template, in
+         // which case the type of the lambda will be different for each
+         // instantiation of the template.
+         /*TypeDependent=*/T->isDependentType(),
+         /*ValueDependent=*/T->isDependentType(),
+         /*InstantiationDependent=*/T->isDependentType(),
+         /*ContainsUnexpandedParameterPack=*/false),
+    Default(Default),
+    NumExplicits(Explicits.size())
+{
+  // Space for explicit captures has been allocated past the end of the
+  // LambdaExpr.
+  memcpy(reinterpret_cast<Capture *>(this + 1),
+         Explicits.data(), sizeof(Capture) * NumExplicits);
+}
+
+LambdaExpr *LambdaExpr::Create(ASTContext &C, CXXRecordDecl *ClosureType,
+                               LambdaCaptureDefault Default,
+                               ArrayRef<Capture> Explicits) {
+  // Allocate space for explicit captures past the end of the LambdaExpr.
+  void *Mem = C.Allocate(sizeof(LambdaExpr) +
+                          sizeof(Capture) * Explicits.size(),
+                          llvm::alignOf<Capture>());
+
+  // FIXME: Here, Doug used getTypeDeclType instead of getRecordType. I believe
+  // getRecordType skips a level of delegation. Is that right?
+  return new (Mem) LambdaExpr(C.getRecordType(ClosureType), Default, Explicits);
+}
+
+SourceRange LambdaExpr::getSourceRange() const {
+  return getClosureType()->getSourceRange();
+}
 
diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp
index daaa354..c041925 100644
--- a/lib/AST/StmtPrinter.cpp
+++ b/lib/AST/StmtPrinter.cpp
@@ -1557,6 +1557,59 @@ StmtPrinter::VisitObjCBridgedCastExpr(ObjCBridgedCastExpr *E) {
   PrintExpr(E->getSubExpr());
 }
 
+void StmtPrinter::VisitLambdaExpr(LambdaExpr *Lambda) {
+  OS << "[";
+  bool first = true;
+  if (Lambda->getDefault() == LCD_ByCopy) {
+    OS << "=";
+    first = false;
+  } else if (Lambda->getDefault() == LCD_ByRef) {
+    OS << "&";
+    first = false;
+  }
+  for (LambdaExpr::capture_const_iterator C = Lambda->explicits_begin(),
+       E = Lambda->explicits_end(); C != E; ++C) {
+    if (!first)
+      OS << ", ";
+    else
+      first = false;
+
+    if (C->isThisCapture()) {
+      OS << "this";
+    } else {
+      if (C->isReferenceCapture()) OS << "&";
+      OS << cast<DeclRefExpr>(C->getInitializer())->getDecl()
+                                                  ->getIdentifier()->getName();
+    }
+  }
+  OS << "] (";
+  CXXMethodDecl *Method = Lambda->getFunction();
+  // Which is preferred: indexing or iteration?
+  //for (unsigned i = 0, e = Method->getNumParams(); i != e; ++i) {
+    //if (i != 0)
+  for (CXXMethodDecl::param_const_iterator P = Method->param_begin(),
+       E = Method->param_end(); P != E; ++P) {
+    if (P != Method->param_begin()) OS << ", ";
+    std::string ParamStr = (*P)->getNameAsString();
+    (*P)->getType().getAsStringInternal(ParamStr, Policy);
+    OS << ParamStr;
+    //OS << (*P)->getType().getAsString(Policy) << (*P)->getNameAsString();
+  }
+  OS << ")";
+
+  if (!(Method->getTypeQualifiers() & Qualifiers::Const))
+    OS << " mutable";
+
+  OS << " -> "
+     << cast<FunctionType>(Method->getType())->getResultType()
+                                              .getAsString(Policy)
+     << " ";
+
+  if (Method->hasBody())
+    PrintRawCompoundStmt(cast<CompoundStmt>(Method->getBody()));
+
+}
+
 void StmtPrinter::VisitBlockExpr(BlockExpr *Node) {
   BlockDecl *BD = Node->getBlockDecl();
   OS << "^";
diff --git a/lib/AST/StmtProfile.cpp b/lib/AST/StmtProfile.cpp
index 214378a..7d407ae 100644
--- a/lib/AST/StmtProfile.cpp
+++ b/lib/AST/StmtProfile.cpp
@@ -449,6 +449,11 @@ void StmtProfiler::VisitBlockExpr(const BlockExpr *S) {
   VisitDecl(S->getBlockDecl());
 }
 
+// FIXME: Implement.
+void StmtProfiler::VisitLambdaExpr(const LambdaExpr *S) {
+  llvm_unreachable("unimplemented");
+}
+
 void StmtProfiler::VisitBlockDeclRefExpr(const BlockDeclRefExpr *S) {
   VisitExpr(S);
   VisitDecl(S->getDecl());
diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp
index 33348a9..5781ce0 100644
--- a/lib/Parse/ParseExprCXX.cpp
+++ b/lib/Parse/ParseExprCXX.cpp
@@ -509,7 +509,7 @@ ExprResult Parser::ParseCXXIdExpression(bool isAddressOfOperand) {
   
 }
 
-/// ParseLambdaExpression - Parse a C++0x lambda expression.
+/// \brief Parse a C++11 lambda expression.
 ///
 ///       lambda-expression:
 ///         lambda-introducer lambda-declarator[opt] compound-statement
@@ -553,9 +553,10 @@ ExprResult Parser::ParseLambdaExpression() {
   return ParseLambdaExpressionAfterIntroducer(Intro);
 }
 
-/// TryParseLambdaExpression - Use lookahead and potentially tentative
-/// parsing to determine if we are looking at a C++0x lambda expression, and parse
-/// it if we are.
+/// \brief Tentatively parse a lambda expression.
+/// 
+/// Use lookahead and potentially tentative parsing to determine if we
+/// are looking at a C++11 lambda expression, and parse it if we are.
 ///
 /// If we are not looking at a lambda expression, returns ExprError().
 ExprResult Parser::TryParseLambdaExpression() {
@@ -587,7 +588,7 @@ ExprResult Parser::TryParseLambdaExpression() {
   return ParseLambdaExpressionAfterIntroducer(Intro);
 }
 
-/// ParseLambdaExpression - Parse a lambda introducer.
+/// \brief Parse a lambda introducer.
 ///
 /// Returns a DiagnosticID if it hit something unexpected.
 llvm::Optional<unsigned> Parser::ParseLambdaIntroducer(LambdaIntroducer &Intro) {
@@ -658,7 +659,7 @@ llvm::Optional<unsigned> Parser::ParseLambdaIntroducer(LambdaIntroducer &Intro)
   return DiagResult();
 }
 
-/// TryParseLambdaExpression - Tentatively parse a lambda introducer.
+/// \brief Tentatively parse a lambda introducer.
 ///
 /// Returns true if it hit something unexpected.
 bool Parser::TryParseLambdaIntroducer(LambdaIntroducer &Intro) {
@@ -675,15 +676,26 @@ bool Parser::TryParseLambdaIntroducer(LambdaIntroducer &Intro) {
   return false;
 }
 
-/// ParseLambdaExpressionAfterIntroducer - Parse the rest of a lambda
-/// expression.
+/// \brief Parse the rest of a lambda expression.
 ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
                      LambdaIntroducer &Intro) {
   Diag(Intro.Range.getBegin(), diag::warn_cxx98_compat_lambda);
 
+  ExprResult MaybeLambda = Actions.ActOnLambdaIntroducer(getCurScope(), Intro);
+  if (!MaybeLambda.isUsable())
+    return ExprError();
+
+  Expr *Lambda = MaybeLambda.take();
+
   // Parse lambda-declarator[opt].
   DeclSpec DS(AttrFactory);
-  Declarator D(DS, Declarator::PrototypeContext);
+  {
+    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::MemberContext);
 
   if (Tok.is(tok::l_paren)) {
     ParseScope PrototypeScope(this,
@@ -760,22 +772,27 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
                   Attr, DeclEndLoc);
   }
 
+  Actions.ActOnLambdaDeclarator(getCurScope(), Lambda, D);
+
   // Parse compound-statement.
+  Stmt *Body = 0;
   if (Tok.is(tok::l_brace)) {
     // FIXME: Rename BlockScope -> ClosureScope if we decide to continue using
     // it.
     ParseScope BodyScope(this, Scope::BlockScope | Scope::FnScope |
                                Scope::BreakScope | Scope::ContinueScope |
                                Scope::DeclScope);
-
-    StmtResult Stmt(ParseCompoundStatementBody());
-
+    StmtResult MaybeBody(ParseCompoundStatementBody());
     BodyScope.Exit();
+    if (!MaybeBody.isInvalid())
+      Body = MaybeBody.take();
   } else {
     Diag(Tok, diag::err_expected_lambda_body);
   }
 
-  return ExprEmpty();
+  Actions.ActOnLambdaBody(getCurScope(), Lambda, Body);
+
+  return Lambda;
 }
 
 /// ParseCXXCasts - This handles the various ways to cast expressions to another
diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp
index 3300444..b2bb6aa 100644
--- a/lib/Sema/SemaExprCXX.cpp
+++ b/lib/Sema/SemaExprCXX.cpp
@@ -4676,3 +4676,415 @@ 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(Scope *S, 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;
+        continue;
+      }
+
+      if (Intro.Default == LCD_ByCopy) {
+        Diag(C->Loc, diag::err_this_capture_with_copy_default);
+        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));
+      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);
+      continue;
+    } else if (C->Kind == LCK_ByCopy && Intro.Default == LCD_ByCopy) {
+      Diag(C->Loc, diag::err_copy_capture_with_copy_default);
+      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) {
+      Diag(C->Loc, diag::err_capture_more_than_once) << C->Id
+        << Appearance->second;
+      continue;
+    }
+
+    UnqualifiedId Name;
+    CXXScopeSpec ScopeSpec;
+    Name.setIdentifier(C->Id, C->Loc);
+    // FIXME: Handle error here, such as invalid result or Expr other than
+    // DeclRefExpr.
+    DeclRefExpr *VarRef
+      = static_cast<DeclRefExpr*>(
+          ActOnIdExpression(S, 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())) {
+      if (!Var->hasLocalStorage() || Var->getStorageClass() == SC_Register)
+        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));
+  }
+
+  // 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);
+  // FIXME: Necessary?
+  //Class->setLexicalDeclContext(CurContext);
+  Class->startDefinition();
+
+  LambdaExpr *Lambda = LambdaExpr::Create(Context, Class, Intro.Default,
+                                          Explicits);
+
+  return ExprResult(Lambda);
+}
+
+void Sema::ActOnLambdaDeclarator(Scope *S, Expr *L, Declarator &D) {
+  assert(isa<LambdaExpr>(L) && "expected lambda expression");
+  LambdaExpr *Lambda = cast<LambdaExpr>(L);
+  CXXRecordDecl *Class = Lambda->getClosureType();
+
+  QualType MethodTy;
+  TypeSourceInfo *MethodTyInfo;
+  if (D.getNumTypeObjects() == 0) {
+    FunctionProtoType::ExtProtoInfo EPI;
+    EPI.TypeQuals |= DeclSpec::TQ_const;
+    MethodTy = Context.getFunctionType(Context.VoidTy,
+                                       /*Args=*/0, /*NumArgs=*/0, EPI);
+    MethodTyInfo = Context.getTrivialTypeSourceInfo(MethodTy);
+  } else {
+    assert(D.isFunctionDeclarator() && "non-function lambda-declarator");
+    DeclaratorChunk::FunctionTypeInfo &FTI = D.getFunctionTypeInfo();
+    if (!FTI.TrailingReturnType) {
+      FTI.TrailingReturnType = Context.VoidTy.getAsOpaquePtr();
+    }
+    // FIXME: Are we handling the mutable specifier correctly?
+    if (!FTI.hasMutableQualifier()) {
+      FTI.TypeQuals |= DeclSpec::TQ_const;
+    }
+    // FIXME: The scope is unused?
+    MethodTyInfo = GetTypeForDeclarator(D, S);
+    // FIXME: Handle error here, such as illegal return type.  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());
+  // Other functions depend on Method having a valid location. Since the
+  // Declarator may be empty, we will use the start of the lambda as the
+  // location for Method.
+  Method->setLocation(Lambda->getExprLoc());
+  assert(!Method->getLocation().isInvalid() &&
+         "lambda function needs valid location");
+  Method->setAccess(AS_public);
+  Method->setLexicalDeclContext(CurContext);
+
+  assert(isa<FunctionProtoTypeLoc>(MethodTyInfo->getTypeLoc()) &&
+         "no function type from lambda-declarator");
+  FunctionProtoTypeLoc MethodTypeLoc
+    = cast<FunctionProtoTypeLoc>(MethodTyInfo->getTypeLoc());
+  Method->setParams(MethodTypeLoc.getParams());
+
+  // FIXME: Remove this check later.
+  LookupResult Previous(*this,
+                        MethodName,
+                        SourceLocation(),
+                        LookupOrdinaryName,
+                        ForRedeclaration);
+  CheckFunctionDeclaration(S, Method, Previous,
+                           /*IsExplicitSpecialization=*/false);
+  assert(!Method->isInvalidDecl() && "bad lambda constructor");
+
+  Lambda->setFunction(Method);
+
+  ActOnStartOfFunctionDef(S, Method);
+}
+
+void Sema::ActOnLambdaBody(Scope *S, Expr *L, Stmt *Body) {
+  assert(isa<LambdaExpr>(L) && "expected lambda expression");
+  LambdaExpr *Lambda = cast<LambdaExpr>(L);
+  CXXRecordDecl *Class = Lambda->getClosureType();
+
+  CanQualType ClassType
+    = Context.getCanonicalType(Context.getRecordType(Class));
+
+  CXXMethodDecl *Method = Lambda->getFunction();
+  // FIXME: Body can be null. Create an empty body in that case? Any errors with
+  // the body should already have been diagnosed.
+  // FIXME: Returning a value from a lambda with void return type triggers a
+  // diagnostic here. In diagnostics on the Method, we probably want it to use a
+  // name like "lambda expression" instead of "operator ()". How do we handle
+  // that? Would be nice if we didn't have to introduce an isLambda flag to
+  // CXXMethodDecl (or other AST nodes).
+  ActOnFinishFunctionBody(Method, Body, /*IsInstantiation=*/false);
+  // Mark the end of the lambda.
+  // FIXME: We've got Decl::getSourceRange (that splits into Decl::getLocStart
+  // and Decl::getLocEnd), Decl::getLocation, and Decl::getBodyRBrace;
+  // DeclaratorDecl::getInnerLocStart and DeclaratorDecl::getOuterLocStart;
+  // TagDecl::getRBraceLoc. Some of these do not have corresponding setters,
+  // some do---even in other subclasses, e.g., FunctionDecl::setRangeEnd.
+  // How are they related? I have a feeling some redundancy exists.
+  Class->setRBraceLoc(Method->getLocEnd());
+  Method->setLexicalDeclContext(Class);
+  Class->addDecl(Method);
+
+  DeclarationName CtorName
+    = Context.DeclarationNames.getCXXConstructorName(ClassType);
+  // Other functions may depend on Ctor having a valid location. Since the Ctor
+  // does not appear directly in the source, it will share the location of the
+  // LambdaExpr.
+  SourceLocation CtorLoc = Lambda->getExprLoc();
+  CXXConstructorDecl *Ctor
+    = CXXConstructorDecl::Create(Context,
+                                 Class,
+                                 CtorLoc,
+                                 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;
+  for (LambdaExpr::capture_const_iterator C = Lambda->explicits_begin(),
+       E = Lambda->explicits_end(); C != E; ++C) {
+
+    Expr *Init = C->getInitializer();
+
+    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.
+    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);
+
+    {
+      // Have to use Expr* instead of DeclRefExpr* because we cannot convert
+      // from DeclRefExpr** to Expr** in the call to BuildMemberInitializer.
+      Expr *CtorInitArg
+        = DeclRefExpr::Create(Context,
+                              /*QualifierLoc=*/NestedNameSpecifierLoc(),
+                              CtorParam,
+                              CaptureLoc,
+                              CaptureType.getNonReferenceType(),
+                              VK_LValue);
+
+      MemInitResult Res = BuildMemberInitializer(Field,
+                                                 MultiInitializer(
+                                                   /*LParenLoc=*/SourceLocation(),
+                                                   &CtorInitArg,
+                                                   /*NumInits=*/1u,
+                                                   /*RParenLoc=*/SourceLocation()),
+                                                 CaptureLoc);
+
+      // FIXME: Handle error here, such as no copy constructor available.
+      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);
+  if (CheckParmsForFunctionDef(CtorParams.data(),
+                               CtorParams.data() + CtorParams.size(),
+                               /*CheckParameterNames=*/true)) {
+    // FIXME: Is there an error that could appear here that we did not catch
+    // earlier?
+    llvm_unreachable("unexpected problem with lambda constructor parameters");
+  }
+  Ctor->setParams(CtorParams);
+  // FIXME: Compare with Sema::ActOnMemInitializers.
+  // FIXME: Compare with Sema::SetCtorInitializers.
+  // Doug says the checks in the above comments are probably unnecessary. Will
+  // wait to remove the comments until closer to finish.
+  Ctor->setNumCtorInitializers(NumCaptures);
+  Ctor->setCtorInitializers(CtorInits);
+  Ctor->setBody(new (Context) CompoundStmt(Context, /*StmtStart=*/0,
+                                           /*NumStmts=*/0,
+                                           CtorLoc,
+                                           CtorLoc));
+
+  // FIXME: Remove this check later?
+  {
+    LookupResult Previous(*this,
+                          CtorName,
+                          SourceLocation(),
+                          LookupOrdinaryName,
+                          ForRedeclaration);
+    CheckFunctionDeclaration(S, Ctor, Previous,
+                             /*IsExplicitSpecialization=*/false);
+    assert(!Ctor->isInvalidDecl() && "bad lambda constructor");
+  }
+
+  Class->addDecl(Ctor);
+
+  Class->completeDefinition();
+  // FIXME: Remove this check later.
+  CheckCompletedCXXClass(Class);
+
+  {
+    ExprResult Res = BuildCXXConstructExpr(Lambda->getLocStart(),
+                                           CtorType,
+                                           Ctor,
+                                           /*Elidable=*/false,
+                                           MultiExprArg(CtorArgs.data(),
+                                                        CtorArgs.size()),
+                                           /*HadMultipleCandidates=*/false,
+                                           /*RequiresZeroInit=*/false,
+                                           CXXConstructExpr::CK_Complete,
+                                           /*ParenRange=*/SourceRange());
+
+    // If there was an error, then we probably have a bug.
+    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 bb49eee..a09a1fc 100644
--- a/lib/Sema/TreeTransform.h
+++ b/lib/Sema/TreeTransform.h
@@ -7995,6 +7995,14 @@ TreeTransform<Derived>::TransformShuffleVectorExpr(ShuffleVectorExpr *E) {
                                                E->getRParenLoc());
 }
 
+// FIXME: Implement.
+template<typename Derived>
+ExprResult
+TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
+  llvm_unreachable("unimplemented");
+  return ExprEmpty();
+}
+
 template<typename Derived>
 ExprResult
 TreeTransform<Derived>::TransformBlockExpr(BlockExpr *E) {
diff --git a/lib/Serialization/ASTReaderStmt.cpp b/lib/Serialization/ASTReaderStmt.cpp
index ab07b85..48b7f33 100644
--- a/lib/Serialization/ASTReaderStmt.cpp
+++ b/lib/Serialization/ASTReaderStmt.cpp
@@ -742,6 +742,11 @@ void ASTStmtReader::VisitShuffleVectorExpr(ShuffleVectorExpr *E) {
   E->setRParenLoc(ReadSourceLocation(Record, Idx));
 }
 
+// FIXME: Implement.
+void ASTStmtReader::VisitLambdaExpr(LambdaExpr *E) {
+  llvm_unreachable("unimplemented");
+}
+
 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 7e2d45c..14bfe43 100644
--- a/lib/Serialization/ASTWriterStmt.cpp
+++ b/lib/Serialization/ASTWriterStmt.cpp
@@ -704,6 +704,11 @@ void ASTStmtWriter::VisitShuffleVectorExpr(ShuffleVectorExpr *E) {
   Code = serialization::EXPR_SHUFFLE_VECTOR;
 }
 
+// FIXME: Implement.
+void ASTStmtWriter::VisitLambdaExpr(LambdaExpr *E) {
+  llvm_unreachable("unimplemented");
+}
+
 void ASTStmtWriter::VisitBlockExpr(BlockExpr *E) {
   VisitExpr(E);
   Writer.AddDeclRef(E->getBlockDecl(), Record);
diff --git a/test/Parser/cxx0x-lambda-expressions.cpp b/test/Parser/cxx0x-lambda-expressions.cpp
index b4fe4cc..ce7453e 100644
--- a/test/Parser/cxx0x-lambda-expressions.cpp
+++ b/test/Parser/cxx0x-lambda-expressions.cpp
@@ -15,7 +15,7 @@ class C {
     [] {};
     [=] (int i) {};
     [&] (int) mutable -> void {};
-    [foo,bar] () { return 3; };
+    [foo,bar] () -> int { return 3; };
     [=,&foo] () {};
     [&,foo] () {};
     [this] () {};
diff --git a/test/Parser/objcxx0x-lambda-expressions.mm b/test/Parser/objcxx0x-lambda-expressions.mm
index 9374649..9d6e5b3 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) {};
@@ -17,7 +17,7 @@ class C {
     // FIXME: this error occurs because we do not yet handle lambda scopes
     // properly. I did not anticipate it because I thought it was a semantic (not
     // syntactic) check.
-    [foo,bar] () { return 3; }; // expected-error {{void function 'f' should not return a value}}
+    [foo,bar] () -> int { return 3; };
     [=,&foo] () {};
     [this] () {};
   }
diff --git a/test/SemaCXX/lambda-expressions.cpp b/test/SemaCXX/lambda-expressions.cpp
new file mode 100644
index 0000000..c37db3d
--- /dev/null
+++ b/test/SemaCXX/lambda-expressions.cpp
@@ -0,0 +1,19 @@
+// 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] () {};
+    [] () -> bool { return true; };
+    [] () { return true; }; // expected-error {{should not return a value}}
+  }
+};
+
