Attached is an updated patch addressing suggestions.
I tried to start working on handling non-trivial lambda bodies, but ran
into trouble with Scope/DeclContext nesting. How should I handle the
semantic and lexical contexts for the lambda's closure type and its
members (constructor, fields, function call operator)? When should
DeclContext::addDecl be used, if at all?
- John
diff --git include/clang/AST/ExprCXX.h include/clang/AST/ExprCXX.h
index 1911704..821f312 100644
--- include/clang/AST/ExprCXX.h
+++ include/clang/AST/ExprCXX.h
@@ -3123,7 +3123,113 @@ 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:
+ class Capture {
+ enum Kind {
+ CaptureThis,
+ CaptureByCopy,
+ CaptureByRef
+ };
+
+ llvm::PointerIntPair<Expr*, 2, Kind> InitAndKind;
+
+ public:
+ Capture(CXXThisExpr *Init)
+ : InitAndKind(Init, CaptureThis) {}
+
+ Capture(DeclRefExpr *Init, bool ByRef)
+ : InitAndKind(Init, ByRef ? CaptureByRef : CaptureByCopy) {}
+
+ 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());
+ }
+
+ SourceLocation getLoc() const { return getInit()->getExprLoc(); }
+
+ };
+
+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;
+
+protected:
+ LambdaExpr(CXXRecordDecl *ClosureType, QualType T,
+ Capture *Explicits, unsigned NumExplicits)
+ : Expr(LambdaExprClass, T, VK_RValue, OK_Ordinary,
+ // FIXME: Support templates and parameter packs later.
+ /*TypeDependent=*/false,
+ /*ValueDependent=*/false,
+ /*InstantiationDependent=*/false,
+ /*ContainsUnexpandedParameterPack=*/false),
+ Explicits(Explicits), NumExplicits(NumExplicits),
+ ClosureType(ClosureType) {}
+
+ explicit LambdaExpr(EmptyShell Empty) : Expr(LambdaExprClass, Empty) {}
+
+public:
+ static LambdaExpr *Create(ASTContext &C, CXXRecordDecl *ClosureType,
+ const Capture *E, unsigned N);
+
+ unsigned getNumExplicits() const { return NumExplicits; }
+
+ typedef const Capture *capture_iterator;
+ typedef const Capture *capture_const_iterator;
+
+ capture_iterator explicits_begin() { return Explicits; }
+ capture_iterator explicits_end() { return Explicits + NumExplicits; }
+ capture_const_iterator explicits_begin() const { return Explicits; }
+ capture_const_iterator explicits_end() const {
+ return Explicits + NumExplicits;
+ }
+
+ CXXRecordDecl *getClosureType() const { return ClosureType; }
+
+ 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 include/clang/AST/RecursiveASTVisitor.h
include/clang/AST/RecursiveASTVisitor.h
index 473ba66..55375ec 100644
--- include/clang/AST/RecursiveASTVisitor.h
+++ include/clang/AST/RecursiveASTVisitor.h
@@ -1901,6 +1901,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 include/clang/Basic/DiagnosticSemaKinds.td
include/clang/Basic/DiagnosticSemaKinds.td
index a90849c..9c848c8 100644
--- include/clang/Basic/DiagnosticSemaKinds.td
+++ include/clang/Basic/DiagnosticSemaKinds.td
@@ -1182,6 +1182,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 include/clang/Basic/StmtNodes.td include/clang/Basic/StmtNodes.td
index 73996e4..a67dfa2 100644
--- include/clang/Basic/StmtNodes.td
+++ 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 include/clang/Sema/Sema.h include/clang/Sema/Sema.h
index 423f29f..abeb3c6 100644
--- include/clang/Sema/Sema.h
+++ 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;
@@ -4999,6 +5000,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, LambdaExpr *Lambda, Declarator &D);
+ void ActOnLambdaBody(Scope *S, LambdaExpr *Lambda, Stmt *Body);
+
+
//===--------------------------------------------------------------------===//
// Objective-C declarations.
Decl *ActOnStartClassInterface(SourceLocation AtInterfaceLoc,
IdentifierInfo *ClassName,
diff --git include/clang/Serialization/ASTBitCodes.h
include/clang/Serialization/ASTBitCodes.h
index 4c8eb28..3b5ec1f 100644
--- include/clang/Serialization/ASTBitCodes.h
+++ include/clang/Serialization/ASTBitCodes.h
@@ -1060,6 +1060,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 lib/AST/ExprCXX.cpp lib/AST/ExprCXX.cpp
index f92afff..35f2516 100644
--- lib/AST/ExprCXX.cpp
+++ lib/AST/ExprCXX.cpp
@@ -1012,4 +1012,18 @@ TemplateArgument
SubstNonTypeTemplateParmPackExpr::getArgumentPack() const {
return TemplateArgument(Arguments, NumArguments);
}
+LambdaExpr *LambdaExpr::Create(ASTContext &C, CXXRecordDecl *ClosureType,
+ const Capture *E, unsigned N) {
+ // Avoid new Capture[] because we don't want to provide a default
constructor.
+ size_t Size = N * sizeof(Capture);
+ void *buffer = C.Allocate(Size, llvm::AlignOf<Capture>::Alignment);
+ memcpy(buffer, E, Size);
+
+ return new (C) LambdaExpr(ClosureType, C.getRecordType(ClosureType),
+ static_cast<Capture*>(buffer), N);
+}
+
+SourceRange LambdaExpr::getSourceRange() const {
+ return ClosureType ? ClosureType->getSourceRange() : SourceRange();
+}
diff --git lib/AST/StmtPrinter.cpp lib/AST/StmtPrinter.cpp
index 79f14bc..24db42f 100644
--- lib/AST/StmtPrinter.cpp
+++ lib/AST/StmtPrinter.cpp
@@ -1503,6 +1503,11 @@
StmtPrinter::VisitObjCBridgedCastExpr(ObjCBridgedCastExpr *E) {
PrintExpr(E->getSubExpr());
}
+// FIXME: Implement.
+void StmtPrinter::VisitLambdaExpr(LambdaExpr *Node) {
+ llvm_unreachable("unimplemented");
+}
+
void StmtPrinter::VisitBlockExpr(BlockExpr *Node) {
BlockDecl *BD = Node->getBlockDecl();
OS << "^";
diff --git lib/AST/StmtProfile.cpp lib/AST/StmtProfile.cpp
index 12321ef..6580e9b 100644
--- lib/AST/StmtProfile.cpp
+++ 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 lib/Parse/ParseExprCXX.cpp lib/Parse/ParseExprCXX.cpp
index 1faeebc..d05c038 100644
--- lib/Parse/ParseExprCXX.cpp
+++ lib/Parse/ParseExprCXX.cpp
@@ -584,7 +584,7 @@ ExprResult Parser::TryParseLambdaExpression() {
return ParseLambdaExpressionAfterIntroducer(Intro);
}
-/// ParseLambdaExpression - Parse a lambda introducer.
+/// ParseLambdaIntroducer - Parse a lambda introducer.
///
/// Returns a DiagnosticID if it hit something unexpected.
llvm::Optional<unsigned> Parser::ParseLambdaIntroducer(LambdaIntroducer
&Intro) {
@@ -652,7 +652,7 @@ llvm::Optional<unsigned>
Parser::ParseLambdaIntroducer(LambdaIntroducer &Intro)
return DiagResult();
}
-/// TryParseLambdaExpression - Tentatively parse a lambda introducer.
+/// TryParseLambdaIntroducer - Tentatively parse a lambda introducer.
///
/// Returns true if it hit something unexpected.
bool Parser::TryParseLambdaIntroducer(LambdaIntroducer &Intro) {
@@ -673,8 +673,20 @@ bool Parser::TryParseLambdaIntroducer(LambdaIntroducer
&Intro) {
/// expression.
ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
LambdaIntroducer &Intro) {
+ ExprResult MaybeLambda = Actions.ActOnLambdaIntroducer(getCurScope(), Intro);
+ if (!MaybeLambda.isUsable())
+ return ExprError();
+
+ 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)) {
@@ -748,6 +760,8 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
Attr, DeclEndLoc);
}
+ Actions.ActOnLambdaDeclarator(getCurScope(), Lambda, D);
+
// Parse compound-statement.
if (Tok.is(tok::l_brace)) {
// FIXME: Rename BlockScope -> ClosureScope if we decide to continue using
@@ -759,6 +773,9 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
StmtResult Stmt(ParseCompoundStatementBody());
BodyScope.Exit();
+
+ if (!Stmt.isInvalid())
+ Actions.ActOnLambdaBody(getCurScope(), Lambda, Stmt.take());
} else {
Diag(Tok, diag::err_expected_lambda_body);
}
diff --git lib/Sema/SemaExprCXX.cpp lib/Sema/SemaExprCXX.cpp
index 428e728..337633e 100644
--- lib/Sema/SemaExprCXX.cpp
+++ lib/Sema/SemaExprCXX.cpp
@@ -4655,3 +4655,381 @@ 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);
+ 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 == LCK_ByRef));
+ }
+
+ // 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();
+ // FIXME: This is how we track the end of the lambda. It is set repeatedly as
+ // we move along. Is it ok?
+ // 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(Intro.Range.getEnd());
+
+ LambdaExpr *Lambda = LambdaExpr::Create(Context, Class,
+ Explicits.data(), Explicits.size());
+
+ return ExprResult(Lambda);
+}
+
+void Sema::ActOnLambdaDeclarator(Scope *S, LambdaExpr *Lambda, Declarator &D) {
+ CXXRecordDecl *Class = Lambda->getClosureType();
+ Class->setRBraceLoc(D.getSourceRange().getEnd());
+
+ 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, S);
+ // 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());
+ Method->setAccess(AS_public);
+ Method->setLexicalDeclContext(CurContext);
+ // FIXME: How to add Method as a member of Class? Cannot use
+ // DeclContext::addDecl. Apparently, that is only for lexical contexts. How
+ // should we handle DeclContexts for Class, Method, Field, and Ctor?
+
+ 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(S, Method, Previous,
+ /*IsExplicitSpecialization=*/false,
+ Redeclaration);
+ assert(!Method->isInvalidDecl() && "bad lambda constructor");
+
+ Lambda->setFunction(Method);
+}
+
+void Sema::ActOnLambdaBody(Scope *S, LambdaExpr *Lambda, Stmt *Body) {
+ CXXRecordDecl *Class = Lambda->getClosureType();
+ Class->setRBraceLoc(Body->getLocEnd());
+
+ CanQualType ClassType
+ = Context.getCanonicalType(Context.getRecordType(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;
+ for (LambdaExpr::capture_const_iterator C = Lambda->explicits_begin(),
+ E = Lambda->explicits_end(); 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);
+
+ 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(S, Ctor, Previous,
+ /*IsExplicitSpecialization=*/false,
+ Redeclaration);
+ 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()),
+ /*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 lib/Sema/TreeTransform.h lib/Sema/TreeTransform.h
index 12eba29..5336bca 100644
--- lib/Sema/TreeTransform.h
+++ lib/Sema/TreeTransform.h
@@ -7932,6 +7932,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 lib/Serialization/ASTReaderStmt.cpp
lib/Serialization/ASTReaderStmt.cpp
index a402ad0..d969809 100644
--- lib/Serialization/ASTReaderStmt.cpp
+++ lib/Serialization/ASTReaderStmt.cpp
@@ -741,6 +741,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 lib/Serialization/ASTWriterStmt.cpp
lib/Serialization/ASTWriterStmt.cpp
index 8f68b12..3f8a54f 100644
--- lib/Serialization/ASTWriterStmt.cpp
+++ lib/Serialization/ASTWriterStmt.cpp
@@ -701,6 +701,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 test/Parser/objcxx0x-lambda-expressions.mm
test/Parser/objcxx0x-lambda-expressions.mm
index d100e2e..8d2d9f6 100644
--- test/Parser/objcxx0x-lambda-expressions.mm
+++ 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 test/SemaCXX/lambda-expressions.cpp
test/SemaCXX/lambda-expressions.cpp
new file mode 100644
index 0000000..306af7b
--- /dev/null
+++ test/SemaCXX/lambda-expressions.cpp
@@ -0,0 +1,21 @@
+// 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; // expected-error {{should not return a value}}
+ };
+ }
+};
+
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits