(Please read the earlier email in this thread first.)
Attached is an updated patch adding a LambdaExpr AST node (and stubs for
all the attendant Visit/Traverse/Transform functions) and building the
CXXMethodDecl for the lambda type's function call operator.
- John
diff --git a/include/clang/AST/DeclBase.h b/include/clang/AST/DeclBase.h
index 8355e36..ed7ce88 100644
--- a/include/clang/AST/DeclBase.h
+++ b/include/clang/AST/DeclBase.h
@@ -39,6 +39,7 @@ class ObjCCategoryImplDecl;
class ObjCImplDecl;
class LinkageSpecDecl;
class BlockDecl;
+class LambdaDecl;
class DeclarationName;
class CompoundStmt;
class StoredDeclsMap;
diff --git a/include/clang/AST/DeclCXX.h b/include/clang/AST/DeclCXX.h
index 01ca2e3..9bb6028 100644
--- a/include/clang/AST/DeclCXX.h
+++ b/include/clang/AST/DeclCXX.h
@@ -16,6 +16,8 @@
#define LLVM_CLANG_AST_DECLCXX_H
#include "clang/AST/Expr.h"
+// FIXME: Including this only for CXXThisExpr. Is that bad?
+#include "clang/AST/ExprCXX.h"
#include "clang/AST/Decl.h"
#include "clang/AST/TypeLoc.h"
#include "clang/AST/UnresolvedSet.h"
@@ -2566,6 +2568,58 @@ public:
friend class ASTDeclReader;
};
+/// LambdaDecl - Represents a C++0x lambda expression.
+class LambdaDecl : public Decl, public DeclContext {
+public:
+ class Capture {
+ enum {
+ CaptureThis,
+ CaptureByRef,
+ CaptureByCopy
+ } Kind;
+
+ Expr* Init;
+
+ public:
+ Capture(CXXThisExpr *Init)
+ : Kind(CaptureThis), Init(Init) {}
+
+ Capture(DeclRefExpr *Init, bool ByRef)
+ : Kind(ByRef ? CaptureByRef : CaptureByCopy), Init(Init) {}
+
+ bool isThisCapture() const { return Kind == CaptureThis; }
+ bool isReferenceCapture() const { return Kind == CaptureByRef; }
+ bool isCopyCapture() const { return Kind == CaptureByCopy; }
+
+ /// The initializing Expr for the captured entity. Will be either
+ /// CXXThisExpr or DeclRefExpr.
+ Expr* getInit() const { return Init; }
+
+ };
+
+ Capture *Explicits;
+ unsigned NumExplicits;
+
+ /// Declaration for the function object class implementing the lambda
+ /// expression.
+ CXXRecordDecl *Class;
+
+ /// Declaration for the function call operator method within the above class.
+ /// We cache it here to avoid lookup.
+ CXXMethodDecl *Method;
+
+protected:
+ LambdaDecl(DeclContext *DC, SourceLocation L)
+ : Decl(Lambda, DC, L), DeclContext(Lambda),
+ Explicits(0), NumExplicits(0), Class(0) {}
+
+public:
+ static LambdaDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation L) {
+ return new (C) LambdaDecl(DC, L);
+ }
+
+};
+
/// Insertion operator for diagnostics. This allows sending AccessSpecifier's
/// into a diagnostic with <<.
const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
diff --git a/include/clang/AST/ExprCXX.h b/include/clang/AST/ExprCXX.h
index 1911704..fee9089 100644
--- a/include/clang/AST/ExprCXX.h
+++ b/include/clang/AST/ExprCXX.h
@@ -27,6 +27,7 @@ class CXXDestructorDecl;
class CXXMethodDecl;
class CXXTemporary;
class TemplateArgumentListInfo;
+class LambdaDecl;
//===--------------------------------------------------------------------===//
// C++ Expressions.
@@ -3123,6 +3124,38 @@ public:
// Iterators
child_range children() { return child_range(&Temporary, &Temporary + 1); }
};
+
+/// LambdaExpr - Adaptor class for mixing a LambdaDecl with expressions.
+class LambdaExpr : public Expr {
+ LambdaDecl *Lambda;
+
+public:
+ LambdaExpr(LambdaDecl *L, QualType T)
+ : Expr(LambdaExprClass, T, VK_RValue, OK_Ordinary,
+ // FIXME: Support templates and parameter packs later.
+ /*TypeDependent=*/false,
+ /*ValueDependent=*/false,
+ /*InstantiationDependent=*/false,
+ /*ContainsUnexpandedParameterPack=*/false),
+ Lambda(L) {}
+
+ explicit LambdaExpr(EmptyShell Empty) : Expr(LambdaExprClass, Empty) {}
+
+ const LambdaDecl *getLambdaDecl() const { return Lambda; }
+ LambdaDecl *getLambdaDecl() { return Lambda; }
+ void setLambdaDecl(LambdaDecl *L) { Lambda = L; }
+
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == LambdaExprClass;
+ }
+ static bool classof(const LambdaExpr *) { return true; }
+
+ // Required to pass implementation check.
+ SourceRange getSourceRange() const {
+ return SourceRange(/*FIXME: What goes here?*/);
+ }
+ child_range children() { return child_range(); }
+};
} // end namespace clang
diff --git a/include/clang/AST/RecursiveASTVisitor.h
b/include/clang/AST/RecursiveASTVisitor.h
index 85c5c08..49a45ac 100644
--- a/include/clang/AST/RecursiveASTVisitor.h
+++ b/include/clang/AST/RecursiveASTVisitor.h
@@ -1114,6 +1114,8 @@ DEF_TRAVERSE_DECL(FriendTemplateDecl, {
}
})
+DEF_TRAVERSE_DECL(LambdaDecl, { })
+
DEF_TRAVERSE_DECL(LinkageSpecDecl, { })
DEF_TRAVERSE_DECL(ObjCClassDecl, {
@@ -1927,6 +1929,10 @@ DEF_TRAVERSE_STMT(DesignatedInitExpr, { })
DEF_TRAVERSE_STMT(ExtVectorElementExpr, { })
DEF_TRAVERSE_STMT(GNUNullExpr, { })
DEF_TRAVERSE_STMT(ImplicitValueInitExpr, { })
+DEF_TRAVERSE_STMT(LambdaExpr, {
+ TRY_TO(TraverseDecl(S->getLambdaDecl()));
+ return true; // no child statements to loop through.
+})
DEF_TRAVERSE_STMT(ObjCEncodeExpr, { })
DEF_TRAVERSE_STMT(ObjCIsaExpr, { })
DEF_TRAVERSE_STMT(ObjCIvarRefExpr, { })
diff --git a/include/clang/Basic/DeclNodes.td b/include/clang/Basic/DeclNodes.td
index ddd0827..3c3f590 100644
--- a/include/clang/Basic/DeclNodes.td
+++ b/include/clang/Basic/DeclNodes.td
@@ -74,3 +74,4 @@ def Friend : Decl;
def FriendTemplate : Decl;
def StaticAssert : Decl;
def Block : Decl, DeclContext;
+def Lambda : Decl, DeclContext;
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td
b/include/clang/Basic/DiagnosticSemaKinds.td
index 81fb8b6..a598f6b 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -1151,6 +1151,19 @@ def err_for_range_begin_end_types_differ : Error<
def note_for_range_type : Note<"range has type %0">;
def note_for_range_begin_end : Note<
"selected '%select{begin|end}0' %select{function|template }1%2 with iterator
type %3">;
+
+// C++0x lambda expressions
+def err_capture_more_than_once : Error<
+ "%0 can appear only once in a capture list">;
+// FIXME: Is this note overkill? It will almost always appear on the same line
+// as the error.
+def note_previously_captured_here : Note<"previously captured here">;
+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 '='">;
// 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 1258d59..9c744ef 100644
--- a/include/clang/Sema/Sema.h
+++ b/include/clang/Sema/Sema.h
@@ -4940,6 +4940,18 @@ public:
DeclContext *FindInstantiatedContext(SourceLocation Loc, DeclContext *DC,
const MultiLevelTemplateArgumentList &TemplateArgs);
+
//===--------------------------------------------------------------------===//
+ // C++ Lambda Expressions (C++0x [expr.prim.lambda])
+
+ // FIXME: Change to DeclResult later? 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. Should we condense these into one action, or
should
+ // we try semantic checking as early as possible?
+ LambdaDecl *ActOnLambdaIntroducer(const LambdaIntroducer &Intro);
+ void ActOnLambdaDeclarator(LambdaDecl *Lambda, Declarator &D);
+ void ActOnLambdaBody(LambdaDecl *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 9492654..2280d84 100644
--- a/include/clang/Serialization/ASTBitCodes.h
+++ b/include/clang/Serialization/ASTBitCodes.h
@@ -742,6 +742,8 @@ namespace clang {
DECL_FILE_SCOPE_ASM,
/// \brief A BlockDecl record.
DECL_BLOCK,
+ /// \brief A LambdaDecl record.
+ DECL_LAMBDA,
/// \brief A record that stores the set of declarations that are
/// lexically stored within a given DeclContext.
///
@@ -1040,6 +1042,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..a9f9684 100644
--- a/lib/AST/StmtPrinter.cpp
+++ b/lib/AST/StmtPrinter.cpp
@@ -1503,6 +1503,9 @@ StmtPrinter::VisitObjCBridgedCastExpr(ObjCBridgedCastExpr
*E) {
PrintExpr(E->getSubExpr());
}
+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..4f19e87 100644
--- a/lib/AST/StmtProfile.cpp
+++ b/lib/AST/StmtProfile.cpp
@@ -449,6 +449,11 @@ void StmtProfiler::VisitBlockExpr(const BlockExpr *S) {
VisitDecl(S->getBlockDecl());
}
+void StmtProfiler::VisitLambdaExpr(const LambdaExpr *S) {
+ VisitExpr(S);
+ VisitDecl(S->getLambdaDecl());
+}
+
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..81d5c73 100644
--- a/lib/Parse/ParseExprCXX.cpp
+++ b/lib/Parse/ParseExprCXX.cpp
@@ -672,8 +672,23 @@ bool Parser::TryParseLambdaIntroducer(LambdaIntroducer
&Intro) {
/// expression.
ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
LambdaIntroducer &Intro) {
+ LambdaDecl *Lambda = Actions.ActOnLambdaIntroducer(Intro);
+ if (!Lambda)
+ return ExprError();
+
// Parse lambda-declarator[opt].
DeclSpec DS(AttrFactory);
+ {
+ // FIXME: Should we default the TST to auto like below, or create
+ // Declarator::LambdaContext and add extra handling to a bunch of different
+ // functions?
+ const char *PrevSpec = 0;
+ unsigned DiagID = 0;
+ bool HasPrevSpec = DS.SetTypeSpecType(TST_auto, /*Loc=*/SourceLocation(),
PrevSpec, DiagID);
+ assert(!HasPrevSpec && !PrevSpec && "unexpected default type specifier!");
+ }
+ // FIXME: If no declarator is specified, it is as if it were "()". Should we
+ // default the declarator, or add extra handling to Sema?
Declarator D(DS, Declarator::PrototypeContext);
if (Tok.is(tok::l_paren)) {
@@ -747,6 +762,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 +775,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..103fc24 100644
--- a/lib/Sema/SemaExprCXX.cpp
+++ b/lib/Sema/SemaExprCXX.cpp
@@ -4655,3 +4655,358 @@ 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.".
+LambdaDecl *Sema::ActOnLambdaIntroducer(const LambdaIntroducer &Intro) {
+ // Diagnose the explicit capture list.
+ SourceLocation CapturesThis;
+ // FIXME: Are typedefs encouraged? What is the naming convention?
+ llvm::DenseMap<const IdentifierInfo*, SourceLocation> CapturesSoFar;
+
+ // Check captures before we allocate a LambdaDecl.
+ // FIXME: If we hit an error, should we continue as if it didn't exist, or
+ // immediately return failure? For now, return failure.
+ 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'";
+ Diag(CapturesThis, diag::note_previously_captured_here);
+ return NULL;
+ }
+
+ if (Intro.Default == LCD_ByCopy) {
+ Diag(C->Loc, diag::err_this_capture_with_copy_default);
+ return NULL;
+ }
+
+ CapturesThis = 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);
+ return NULL;
+ } else if (C->Kind == LCK_ByCopy && Intro.Default == LCD_ByCopy) {
+ Diag(C->Loc, diag::err_copy_capture_with_copy_default);
+ return NULL;
+ }
+
+ 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;
+ Diag(Appearance->second, diag::note_previously_captured_here);
+ return NULL;
+ }
+ }
+
+ // Avoid new Capture[] because we don't want to provide a default
constructor.
+ // FIXME: Do we need to align?
+ LambdaDecl::Capture *Explicits
+ = static_cast<LambdaDecl::Capture*>(
+ Context.Allocate(Intro.Captures.size() * sizeof(LambdaDecl::Capture)));
+
+ // FIXME: Try to merge with the above loop somehow?
+ LambdaDecl::Capture *Explicit = Explicits;
+ for (llvm::SmallVector<LambdaCapture, 4>::const_iterator
+ C = Intro.Captures.begin(), E = Intro.Captures.end(); C != E; ++C) {
+ if (C->Kind == LCK_This) {
+ CXXThisExpr *This =
static_cast<CXXThisExpr*>(ActOnCXXThis(C->Loc).take());
+ new (Explicit) LambdaDecl::Capture(This);
+ ++Explicit;
+ continue;
+ }
+
+ UnqualifiedId Name;
+ CXXScopeSpec ScopeSpec;
+ Name.setIdentifier(C->Id, C->Loc);
+ // FIXME: Can we do better than ActOnIdExpression?
+ DeclRefExpr *Var
+ = static_cast<DeclRefExpr*>(
+ ActOnIdExpression(getCurScope(),
+ ScopeSpec, Name,
+ /*HasTrailingLParen=*/false,
+ /*IsAddressOfOperand=*/false).take());
+
+ // FIXME: Check that we have a local variable with automatic storage
+ // duration.
+
+ new (Explicit) LambdaDecl::Capture(Var, C->Kind == LCK_ByRef);
+ ++Explicit;
+ }
+
+ // 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,
+ /*StartLoc=*/SourceLocation(),
+ /*IdLoc=*/SourceLocation(),
+ /*Id=*/0);
+ Class->startDefinition();
+
+ LambdaDecl *Lambda = LambdaDecl::Create(Context, DC,
+ Intro.Range.getBegin());
+ Lambda->Explicits = Explicits;
+ Lambda->NumExplicits = Intro.Captures.size();
+ Lambda->Class = Class;
+
+ return Lambda;
+}
+
+void Sema::ActOnLambdaDeclarator(LambdaDecl *Lambda, Declarator &D) {
+ CXXRecordDecl *Class = Lambda->Class;
+
+ 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.getNumTypeObjects() == 1 && "unexpected nested declarator!");
+ // FIXME: The scope is unused?
+ DeclaratorChunk &Chunk = D.getTypeObject(0);
+ assert(Chunk.Kind == DeclaratorChunk::Function &&
+ "unexpected non-function declarator chunk!");
+ if (!Chunk.Fun.TrailingReturnType) {
+ Chunk.Fun.TrailingReturnType = Context.VoidTy.getAsOpaquePtr();
+ }
+ MethodTyInfo = GetTypeForDeclarator(D, getCurScope());
+ MethodTy = MethodTyInfo->getType();
+ }
+
+ assert(MethodTy->isFunctionType() && "bad lambda method type!");
+ DeclarationName MethodName
+ = Context.DeclarationNames.getCXXOperatorName(OO_Call);
+ CXXMethodDecl *Method
+ = CXXMethodDecl::Create(Context,
+ Class,
+ /*StartLoc=*/SourceLocation(),
+ DeclarationNameInfo(MethodName,
+ /*NameLoc=*/SourceLocation()),
+ MethodTy,
+ MethodTyInfo,
+ /*isStatic=*/false,
+ SC_None,
+ /*isInline=*/true,
+ /*EndLocation=*/SourceLocation());
+
+ // 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?
+ FunctionProtoTypeLoc MethodTypeLoc;
+ {
+ TypeLoc TL = MethodTyInfo->getTypeLoc();
+ if (isa<FunctionProtoTypeLoc>(TL))
+ MethodTypeLoc = cast<FunctionProtoTypeLoc>(TL);
+ }
+ 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->Method = Method;
+}
+
+void Sema::ActOnLambdaBody(LambdaDecl *Lambda, Stmt *Body) {
+ CXXRecordDecl *Class = Lambda->Class;
+ CanQualType ClassType
+ = Context.getCanonicalType(Context.getTypeDeclType(Class));
+
+ CXXMethodDecl *Method = Lambda->Method;
+ 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);
+
+ // FIXME: When we support implicit captures later, this number will need to
be
+ // updated.
+ unsigned NumCaptures = Lambda->NumExplicits;
+
+ 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 (LambdaDecl::Capture *C = Lambda->Explicits,
+ *E = Lambda->Explicits + Lambda->NumExplicits; C != E; ++C) {
+
+ Expr *Init = C->getInit();
+
+ IdentifierInfo *Id;
+ if (C->isThisCapture()) {
+ Id = PP.getIdentifierInfo("__this");
+ } else {
+ Id = cast<DeclRefExpr>(Init)->getDecl()->getIdentifier();
+ }
+
+ 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,
+ /*StartLoc=*/SourceLocation(),
+ /*Mutable=*/false,
+ /*BitWidth=*/0,
+ /*HasInit=*/false,
+ /*IdLoc=*/SourceLocation(),
+ AS_private,
+ /*PrevDecl=*/0);
+
+ Class->addDecl(Field);
+
+ // FIXME: Compare with Sema::CheckParameter.
+ ParmVarDecl *CtorParam = ParmVarDecl::Create(Context,
+ Ctor,
+ /*StartLoc=*/SourceLocation(),
+ /*IdLoc=*/SourceLocation(),
+ Id,
+
Context.getAdjustedParameterType(CaptureType),
+ /*TInfo=*/0,
+ SC_None,
+ SC_None,
+ /*DefArg=*/0);
+
+ CtorParamTys.push_back(CaptureType);
+ CtorParams.push_back(CtorParam);
+
+ DeclRefExpr *CtorInitArg
+ = DeclRefExpr::Create(Context,
+ /*QualifierLoc=*/NestedNameSpecifierLoc(),
+ CtorParam,
+ /*NameLoc=*/SourceLocation(),
+ CaptureType.getNonReferenceType(),
+ VK_LValue);
+ // FIXME: Compare with Sema::BuildMemberInitializer.
+ *CtorInit = new (Context) CXXCtorInitializer(Context,
+ Field,
+
/*MemberLoc=*/SourceLocation(),
+ /*L=*/SourceLocation(),
+ CtorInitArg,
+ /*R=*/SourceLocation());
+ ++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);
+
+ CXXConstructExpr *CtorCall = CXXConstructExpr::Create(Context,
+ CtorType,
+
/*Loc=*/SourceLocation(),
+ Ctor,
+ /*Elidable=*/false,
+ CtorArgs.data(),
+ CtorArgs.size());
+
+}
+
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/ASTReaderDecl.cpp
b/lib/Serialization/ASTReaderDecl.cpp
index 707ee8a..4beaa78 100644
--- a/lib/Serialization/ASTReaderDecl.cpp
+++ b/lib/Serialization/ASTReaderDecl.cpp
@@ -154,6 +154,7 @@ namespace clang {
void VisitFriendTemplateDecl(FriendTemplateDecl *D);
void VisitStaticAssertDecl(StaticAssertDecl *D);
void VisitBlockDecl(BlockDecl *BD);
+ void VisitLambdaDecl(LambdaDecl *D);
std::pair<uint64_t, uint64_t> VisitDeclContext(DeclContext *DC);
template <typename T> void VisitRedeclarable(Redeclarable<T> *D);
@@ -748,6 +749,9 @@ void ASTDeclReader::VisitFileScopeAsmDecl(FileScopeAsmDecl
*AD) {
AD->setRParenLoc(ReadSourceLocation(Record, Idx));
}
+void ASTDeclReader::VisitLambdaDecl(LambdaDecl *D) {
+}
+
void ASTDeclReader::VisitBlockDecl(BlockDecl *BD) {
VisitDecl(BD);
BD->setBody(cast_or_null<CompoundStmt>(Reader.ReadStmt(F)));
diff --git a/lib/Serialization/ASTReaderStmt.cpp
b/lib/Serialization/ASTReaderStmt.cpp
index cfe46d7..b532f50 100644
--- a/lib/Serialization/ASTReaderStmt.cpp
+++ b/lib/Serialization/ASTReaderStmt.cpp
@@ -741,6 +741,11 @@ void
ASTStmtReader::VisitShuffleVectorExpr(ShuffleVectorExpr *E) {
E->setRParenLoc(ReadSourceLocation(Record, Idx));
}
+void ASTStmtReader::VisitLambdaExpr(LambdaExpr *E) {
+ VisitExpr(E);
+ //E->setLambdaDecl(ReadDeclAs<LambdaDecl>(Record, Idx));
+}
+
void ASTStmtReader::VisitBlockExpr(BlockExpr *E) {
VisitExpr(E);
E->setBlockDecl(ReadDeclAs<BlockDecl>(Record, Idx));
diff --git a/lib/Serialization/ASTWriterDecl.cpp
b/lib/Serialization/ASTWriterDecl.cpp
index 45f8a32..1e464cf 100644
--- a/lib/Serialization/ASTWriterDecl.cpp
+++ b/lib/Serialization/ASTWriterDecl.cpp
@@ -96,6 +96,7 @@ namespace clang {
void VisitFriendTemplateDecl(FriendTemplateDecl *D);
void VisitStaticAssertDecl(StaticAssertDecl *D);
void VisitBlockDecl(BlockDecl *D);
+ void VisitLambdaDecl(LambdaDecl *D);
void VisitDeclContext(DeclContext *DC, uint64_t LexicalOffset,
uint64_t VisibleOffset);
@@ -735,6 +736,9 @@ void ASTDeclWriter::VisitFileScopeAsmDecl(FileScopeAsmDecl
*D) {
Code = serialization::DECL_FILE_SCOPE_ASM;
}
+void ASTDeclWriter::VisitLambdaDecl(LambdaDecl *D) {
+}
+
void ASTDeclWriter::VisitBlockDecl(BlockDecl *D) {
VisitDecl(D);
Writer.AddStmt(D->getBody());
diff --git a/lib/Serialization/ASTWriterStmt.cpp
b/lib/Serialization/ASTWriterStmt.cpp
index f0636a1..3e6ae92 100644
--- a/lib/Serialization/ASTWriterStmt.cpp
+++ b/lib/Serialization/ASTWriterStmt.cpp
@@ -701,6 +701,12 @@ void
ASTStmtWriter::VisitShuffleVectorExpr(ShuffleVectorExpr *E) {
Code = serialization::EXPR_SHUFFLE_VECTOR;
}
+void ASTStmtWriter::VisitLambdaExpr(LambdaExpr *E) {
+ VisitExpr(E);
+ //Writer.AddDeclRef(E->getLambdaDecl(), Record);
+ Code = serialization::EXPR_LAMBDA;
+}
+
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..c9427aa
--- /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}}
expected-note {{previously captured here}}
+ [this, this] () {}; // expected-error {{'this' can appear only once}}
expected-note {{previously captured here}}
+ [=, 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