From: Richard Smith Date: Thu, 16 May 2013 06:20:58 +0000 (+0000) Subject: First pass of semantic analysis for init-captures: check the initializer, build X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=0d8e9646bc000bab521ce52ed294209a92298cef;p=clang First pass of semantic analysis for init-captures: check the initializer, build a FieldDecl from it, and propagate both into the closure type and the LambdaExpr. You can't do much useful with them yet -- you can't use them within the body of the lambda, because we don't have a representation for "the this of the lambda, not the this of the enclosing context". We also don't have support or a representation for a nested capture of an init-capture yet, which was intended to work despite not being allowed by the current standard wording. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@181985 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/AST/DeclCXX.h b/include/clang/AST/DeclCXX.h index c483dde1f5..9722ad8427 100644 --- a/include/clang/AST/DeclCXX.h +++ b/include/clang/AST/DeclCXX.h @@ -988,6 +988,8 @@ public: /// /// \param ThisCapture Will be set to the field declaration for the /// 'this' capture. + /// + /// \note No entries will be added for init-captures. void getCaptureFields(llvm::DenseMap &Captures, FieldDecl *&ThisCapture) const; diff --git a/include/clang/AST/ExprCXX.h b/include/clang/AST/ExprCXX.h index a4f296c988..a2259903ef 100644 --- a/include/clang/AST/ExprCXX.h +++ b/include/clang/AST/ExprCXX.h @@ -1256,7 +1256,7 @@ class LambdaExpr : public Expr { /// capture was implicit. Capture_Implicit = 0x01, - /// \brief Flag used by the Capture class to indciate that the + /// \brief Flag used by the Capture class to indicate that the /// given capture was by-copy. Capture_ByCopy = 0x02 }; @@ -1299,7 +1299,7 @@ class LambdaExpr : public Expr { public: /// \brief Describes the capture of either a variable or 'this'. class Capture { - llvm::PointerIntPair VarAndBits; + llvm::PointerIntPair DeclAndBits; SourceLocation Loc; SourceLocation EllipsisLoc; @@ -1315,7 +1315,8 @@ public: /// /// \param Implicit Whether the capture was implicit or explicit. /// - /// \param Var The local variable being captured, or null if capturing this. + /// \param Var The local variable being captured, or null if capturing this + /// or if this is an init-capture. /// /// \param EllipsisLoc The location of the ellipsis (...) for a /// capture that is a pack expansion, or an invalid source @@ -1324,29 +1325,43 @@ public: LambdaCaptureKind Kind, VarDecl *Var = 0, SourceLocation EllipsisLoc = SourceLocation()); + /// \brief Create a new init-capture. + Capture(FieldDecl *Field); + /// \brief Determine the kind of capture. LambdaCaptureKind getCaptureKind() const; /// \brief Determine whether this capture handles the C++ 'this' /// pointer. - bool capturesThis() const { return VarAndBits.getPointer() == 0; } + bool capturesThis() const { return DeclAndBits.getPointer() == 0; } /// \brief Determine whether this capture handles a variable. - bool capturesVariable() const { return VarAndBits.getPointer() != 0; } + bool capturesVariable() const { + return dyn_cast_or_null(DeclAndBits.getPointer()); + } + + /// \brief Determines whether this is an init-capture. + bool isInitCapture() const { return getCaptureKind() == LCK_Init; } /// \brief Retrieve the declaration of the local variable being /// captured. /// - /// This operation is only valid if this capture does not capture - /// 'this'. - VarDecl *getCapturedVar() const { - assert(!capturesThis() && "No variable available for 'this' capture"); - return VarAndBits.getPointer(); + /// This operation is only valid if this capture is a variable capture + /// (other than a capture of 'this'). + VarDecl *getCapturedVar() const { + assert(capturesVariable() && "No variable available for 'this' capture"); + return cast(DeclAndBits.getPointer()); + } + + /// \brief Retrieve the field for an init-capture. + FieldDecl *getInitCaptureField() const { + assert(getCaptureKind() == LCK_Init && "no field for non-init-capture"); + return cast(DeclAndBits.getPointer()); } /// \brief Determine whether this was an implicit capture (not /// written between the square brackets introducing the lambda). - bool isImplicit() const { return VarAndBits.getInt() & Capture_Implicit; } + bool isImplicit() const { return DeclAndBits.getInt() & Capture_Implicit; } /// \brief Determine whether this was an explicit capture, written /// between the square brackets introducing the lambda. @@ -1483,6 +1498,16 @@ public: return capture_init_begin() + NumCaptures; } + /// \brief Retrieve the initializer for an init-capture. + Expr *getInitCaptureInit(capture_iterator Capture) { + assert(Capture >= explicit_capture_begin() && + Capture <= explicit_capture_end() && Capture->isInitCapture()); + return capture_init_begin()[Capture - capture_begin()]; + } + const Expr *getInitCaptureInit(capture_iterator Capture) const { + return const_cast(this)->getInitCaptureInit(Capture); + } + /// \brief Retrieve the set of index variables used in the capture /// initializer of an array captured by copy. /// diff --git a/include/clang/AST/RecursiveASTVisitor.h b/include/clang/AST/RecursiveASTVisitor.h index b5a4b5e36d..2c534ac6bc 100644 --- a/include/clang/AST/RecursiveASTVisitor.h +++ b/include/clang/AST/RecursiveASTVisitor.h @@ -243,7 +243,7 @@ public: /// \brief Recursively visit a lambda capture. /// /// \returns false if the visitation was terminated early, true otherwise. - bool TraverseLambdaCapture(LambdaExpr::Capture C); + bool TraverseLambdaCapture(LambdaExpr *LE, const LambdaExpr::Capture *C); // ---- Methods on Stmts ---- @@ -802,7 +802,10 @@ bool RecursiveASTVisitor::TraverseConstructorInitializer( } template -bool RecursiveASTVisitor::TraverseLambdaCapture(LambdaExpr::Capture C){ +bool RecursiveASTVisitor::TraverseLambdaCapture( + LambdaExpr *LE, const LambdaExpr::Capture *C) { + if (C->isInitCapture()) + TRY_TO(TraverseStmt(LE->getInitCaptureInit(C))); return true; } @@ -2120,7 +2123,7 @@ bool RecursiveASTVisitor::TraverseLambdaExpr(LambdaExpr *S) { for (LambdaExpr::capture_iterator C = S->explicit_capture_begin(), CEnd = S->explicit_capture_end(); C != CEnd; ++C) { - TRY_TO(TraverseLambdaCapture(*C)); + TRY_TO(TraverseLambdaCapture(S, C)); } if (S->hasExplicitParameters() || S->hasExplicitResultType()) { diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 55f237736c..c8ea19336b 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -4895,8 +4895,16 @@ let CategoryName = "Lambda Issue" in { def note_lambda_to_block_conv : Note< "implicit capture of lambda object due to conversion to block pointer " "here">; - def err_lambda_init_capture_unsupported : Error< - "sorry, initialized lambda-captures are not supported yet">; + + // C++1y lambda init-captures. + def err_init_capture_no_expression : Error< + "initializer missing for lambda capture %0">; + def err_init_capture_multiple_expressions : Error< + "initializer for lambda capture %0 contains multiple expressions">; + def err_init_capture_deduction_failure : Error< + "cannot deduce type for lambda capture %0 from initializer of type %1">; + def err_init_capture_deduction_failure_from_init_list : Error< + "cannot deduce type for lambda capture %0 from initializer list">; } def err_return_in_captured_stmt : Error< diff --git a/include/clang/Basic/Lambda.h b/include/clang/Basic/Lambda.h index b1ad6acda3..48f5229dc6 100644 --- a/include/clang/Basic/Lambda.h +++ b/include/clang/Basic/Lambda.h @@ -31,7 +31,8 @@ enum LambdaCaptureDefault { enum LambdaCaptureKind { LCK_This, LCK_ByCopy, - LCK_ByRef + LCK_ByRef, + LCK_Init }; } // end namespace clang diff --git a/include/clang/Sema/ScopeInfo.h b/include/clang/Sema/ScopeInfo.h index b232b59d3c..7fe2ac8370 100644 --- a/include/clang/Sema/ScopeInfo.h +++ b/include/clang/Sema/ScopeInfo.h @@ -27,6 +27,7 @@ class Decl; class BlockDecl; class CapturedDecl; class CXXMethodDecl; +class FieldDecl; class ObjCPropertyDecl; class IdentifierInfo; class ImplicitParamDecl; @@ -330,60 +331,93 @@ public: ImplicitCaptureStyle ImpCaptureStyle; class Capture { - // There are two categories of capture: capturing 'this', and capturing - // local variables. There are three ways to capture a local variable: - // capture by copy in the C++11 sense, capture by reference - // in the C++11 sense, and __block capture. Lambdas explicitly specify - // capture by copy or capture by reference. For blocks, __block capture - // applies to variables with that annotation, variables of reference type - // are captured by reference, and other variables are captured by copy. + // There are three categories of capture: capturing 'this', capturing + // local variables, and C++1y initialized captures (which can have an + // arbitrary initializer, and don't really capture in the traditional + // sense at all). + // + // There are three ways to capture a local variable: + // - capture by copy in the C++11 sense, + // - capture by reference in the C++11 sense, and + // - __block capture. + // Lambdas explicitly specify capture by copy or capture by reference. + // For blocks, __block capture applies to variables with that annotation, + // variables of reference type are captured by reference, and other + // variables are captured by copy. enum CaptureKind { - Cap_This, Cap_ByCopy, Cap_ByRef, Cap_Block + Cap_ByCopy, Cap_ByRef, Cap_Block, Cap_ThisOrInit }; - // The variable being captured (if we are not capturing 'this'), - // and misc bits descibing the capture. - llvm::PointerIntPair VarAndKind; + // The variable being captured (if we are not capturing 'this', and whether + // this is a nested capture; the expression is only required if we are + // capturing ByVal and the variable's type has a non-trivial copy + // constructor, or for an initialized capture. + typedef llvm::PointerIntPair VarAndNested; - // Expression to initialize a field of the given type, and whether this - // is a nested capture; the expression is only required if we are - // capturing ByVal and the variable's type has a non-trivial - // copy constructor. - llvm::PointerIntPair CopyExprAndNested; + // The variable being captured, or the implicitly-generated field for + // an init-capture. + llvm::PointerUnion VarOrField; - /// \brief The source location at which the first capture occurred.. + // Expression to initialize a field of the given type, and the kind of + // capture (if this is a capture and not an init-capture). + llvm::PointerIntPair InitExprAndCaptureKind; + + /// \brief The source location at which the first capture occurred. SourceLocation Loc; - + /// \brief The location of the ellipsis that expands a parameter pack. SourceLocation EllipsisLoc; - + /// \brief The type as it was captured, which is in effect the type of the /// non-static data member that would hold the capture. QualType CaptureType; - + public: - Capture(VarDecl *Var, bool block, bool byRef, bool isNested, - SourceLocation Loc, SourceLocation EllipsisLoc, + Capture(VarDecl *Var, bool Block, bool ByRef, bool IsNested, + SourceLocation Loc, SourceLocation EllipsisLoc, QualType CaptureType, Expr *Cpy) - : VarAndKind(Var, block ? Cap_Block : byRef ? Cap_ByRef : Cap_ByCopy), - CopyExprAndNested(Cpy, isNested), Loc(Loc), EllipsisLoc(EllipsisLoc), - CaptureType(CaptureType){} + : VarOrField(VarAndNested(Var, IsNested)), + InitExprAndCaptureKind(Cpy, Block ? Cap_Block : + ByRef ? Cap_ByRef : Cap_ByCopy), + Loc(Loc), EllipsisLoc(EllipsisLoc), CaptureType(CaptureType) {} enum IsThisCapture { ThisCapture }; - Capture(IsThisCapture, bool isNested, SourceLocation Loc, + Capture(IsThisCapture, bool IsNested, SourceLocation Loc, QualType CaptureType, Expr *Cpy) - : VarAndKind(0, Cap_This), CopyExprAndNested(Cpy, isNested), Loc(Loc), - EllipsisLoc(), CaptureType(CaptureType) { } + : VarOrField(VarAndNested(0, IsNested)), + InitExprAndCaptureKind(Cpy, Cap_ThisOrInit), + Loc(Loc), EllipsisLoc(), CaptureType(CaptureType) {} - bool isThisCapture() const { return VarAndKind.getInt() == Cap_This; } - bool isVariableCapture() const { return !isThisCapture(); } - bool isCopyCapture() const { return VarAndKind.getInt() == Cap_ByCopy; } - bool isReferenceCapture() const { return VarAndKind.getInt() == Cap_ByRef; } - bool isBlockCapture() const { return VarAndKind.getInt() == Cap_Block; } - bool isNested() { return CopyExprAndNested.getInt(); } + Capture(FieldDecl *Field, Expr *Init) + : VarOrField(Field), InitExprAndCaptureKind(Init, Cap_ThisOrInit), + Loc(), EllipsisLoc(), CaptureType() {} + + bool isThisCapture() const { + return InitExprAndCaptureKind.getInt() == Cap_ThisOrInit && + VarOrField.is(); + } + bool isVariableCapture() const { + return InitExprAndCaptureKind.getInt() != Cap_ThisOrInit; + } + bool isInitCapture() const { + return VarOrField.is(); + } + bool isCopyCapture() const { + return InitExprAndCaptureKind.getInt() == Cap_ByCopy; + } + bool isReferenceCapture() const { + return InitExprAndCaptureKind.getInt() == Cap_ByRef; + } + bool isBlockCapture() const { + return InitExprAndCaptureKind.getInt() == Cap_Block; + } + bool isNested() { return VarOrField.dyn_cast().getInt(); } VarDecl *getVariable() const { - return VarAndKind.getPointer(); + return VarOrField.dyn_cast().getPointer(); + } + FieldDecl *getInitCaptureField() const { + return VarOrField.dyn_cast(); } /// \brief Retrieve the location at which this variable was captured. @@ -398,8 +432,8 @@ public: /// that would store this capture. QualType getCaptureType() const { return CaptureType; } - Expr *getCopyExpr() const { - return CopyExprAndNested.getPointer(); + Expr *getInitExpr() const { + return InitExprAndCaptureKind.getPointer(); } }; @@ -437,6 +471,10 @@ public: void addThisCapture(bool isNested, SourceLocation Loc, QualType CaptureType, Expr *Cpy); + void addInitCapture(FieldDecl *Field, Expr *Init) { + Captures.push_back(Capture(Field, Init)); + } + /// \brief Determine whether the C++ 'this' is captured. bool isCXXThisCaptured() const { return CXXThisCaptureIndex != 0; } diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index 61b91c5962..a2e47e5a5a 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -4313,6 +4313,11 @@ public: bool ExplicitResultType, bool Mutable); + /// \brief Check and build an init-capture with the specified name and + /// initializer. + FieldDecl *checkInitCapture(SourceLocation Loc, bool ByRef, + IdentifierInfo *Id, Expr *Init); + /// \brief Note that we have finished the explicit captures for the /// given lambda. void finishLambdaExplicitCaptures(sema::LambdaScopeInfo *LSI); diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp index 064649904d..df8a52675b 100644 --- a/lib/AST/DeclCXX.cpp +++ b/lib/AST/DeclCXX.cpp @@ -940,12 +940,10 @@ void CXXRecordDecl::getCaptureFields( RecordDecl::field_iterator Field = field_begin(); for (LambdaExpr::Capture *C = Lambda.Captures, *CEnd = C + Lambda.NumCaptures; C != CEnd; ++C, ++Field) { - if (C->capturesThis()) { + if (C->capturesThis()) ThisCapture = *Field; - continue; - } - - Captures[C->getCapturedVar()] = *Field; + else if (C->capturesVariable()) + Captures[C->getCapturedVar()] = *Field; } } diff --git a/lib/AST/ExprCXX.cpp b/lib/AST/ExprCXX.cpp index 402d7b532b..59e780ae0a 100644 --- a/lib/AST/ExprCXX.cpp +++ b/lib/AST/ExprCXX.cpp @@ -811,7 +811,7 @@ CXXConstructExpr::CXXConstructExpr(ASTContext &C, StmtClass SC, QualType T, LambdaExpr::Capture::Capture(SourceLocation Loc, bool Implicit, LambdaCaptureKind Kind, VarDecl *Var, SourceLocation EllipsisLoc) - : VarAndBits(Var, 0), Loc(Loc), EllipsisLoc(EllipsisLoc) + : DeclAndBits(Var, 0), Loc(Loc), EllipsisLoc(EllipsisLoc) { unsigned Bits = 0; if (Implicit) @@ -828,15 +828,27 @@ LambdaExpr::Capture::Capture(SourceLocation Loc, bool Implicit, case LCK_ByRef: assert(Var && "capture must have a variable!"); break; + + case LCK_Init: + llvm_unreachable("don't use this constructor for an init-capture"); } - VarAndBits.setInt(Bits); + DeclAndBits.setInt(Bits); } +LambdaExpr::Capture::Capture(FieldDecl *Field) + : DeclAndBits(Field, + Field->getType()->isReferenceType() ? 0 : Capture_ByCopy), + Loc(Field->getLocation()), EllipsisLoc() {} + LambdaCaptureKind LambdaExpr::Capture::getCaptureKind() const { - if (capturesThis()) + Decl *D = DeclAndBits.getPointer(); + if (!D) return LCK_This; - return (VarAndBits.getInt() & Capture_ByCopy)? LCK_ByCopy : LCK_ByRef; + if (isa(D)) + return LCK_Init; + + return (DeclAndBits.getInt() & Capture_ByCopy) ? LCK_ByCopy : LCK_ByRef; } LambdaExpr::LambdaExpr(QualType T, diff --git a/lib/AST/Stmt.cpp b/lib/AST/Stmt.cpp index 5b29c073f9..7e85880b5f 100644 --- a/lib/AST/Stmt.cpp +++ b/lib/AST/Stmt.cpp @@ -1128,7 +1128,7 @@ Stmt::child_range CapturedStmt::children() { bool CapturedStmt::capturesVariable(const VarDecl *Var) const { for (const_capture_iterator I = capture_begin(), E = capture_end(); I != E; ++I) { - if (I->capturesThis()) + if (!I->capturesVariable()) continue; // This does not handle variable redeclarations. This should be diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp index 9203dc1584..2edb078442 100644 --- a/lib/AST/StmtPrinter.cpp +++ b/lib/AST/StmtPrinter.cpp @@ -1387,6 +1387,13 @@ void StmtPrinter::VisitLambdaExpr(LambdaExpr *Node) { OS << '='; OS << C->getCapturedVar()->getName(); break; + + case LCK_Init: + if (C->getInitCaptureField()->getType()->isReferenceType()) + OS << '&'; + OS << C->getInitCaptureField()->getName(); + PrintExpr(Node->getInitCaptureInit(C)); + break; } } OS << ']'; diff --git a/lib/AST/StmtProfile.cpp b/lib/AST/StmtProfile.cpp index 8ade242d56..4a3448c1e5 100644 --- a/lib/AST/StmtProfile.cpp +++ b/lib/AST/StmtProfile.cpp @@ -822,9 +822,17 @@ StmtProfiler::VisitLambdaExpr(const LambdaExpr *S) { CEnd = S->explicit_capture_end(); C != CEnd; ++C) { ID.AddInteger(C->getCaptureKind()); - if (C->capturesVariable()) { + switch (C->getCaptureKind()) { + case LCK_This: + break; + case LCK_ByRef: + case LCK_ByCopy: VisitDecl(C->getCapturedVar()); ID.AddBoolean(C->isPackExpansion()); + break; + case LCK_Init: + VisitDecl(C->getInitCaptureField()); + break; } } // Note: If we actually needed to be able to match lambda diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp index 86e2e187d3..8bc9a796fe 100644 --- a/lib/Parse/ParseExprCXX.cpp +++ b/lib/Parse/ParseExprCXX.cpp @@ -766,9 +766,6 @@ Optional Parser::ParseLambdaIntroducer(LambdaIntroducer &Intro) { if (Tok.is(tok::identifier)) { Id = Tok.getIdentifierInfo(); Loc = ConsumeToken(); - - if (Tok.is(tok::ellipsis)) - EllipsisLoc = ConsumeToken(); } else if (Tok.is(tok::kw_this)) { // FIXME: If we want to suggest a fixit here, will need to return more // than just DiagnosticID. Perhaps full DiagnosticBuilder that can be @@ -798,7 +795,8 @@ Optional Parser::ParseLambdaIntroducer(LambdaIntroducer &Intro) { ConsumeToken(); Init = ParseInitializer(); - } + } else if (Tok.is(tok::ellipsis)) + EllipsisLoc = ConsumeToken(); } Intro.addCapture(Kind, Loc, Id, EllipsisLoc, Init); diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index fa2bfd260b..8c612b42ca 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -9932,7 +9932,7 @@ ExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc, if (Cap.isThisCapture()) continue; BlockDecl::Capture NewCap(Cap.getVariable(), Cap.isBlockCapture(), - Cap.isNested(), Cap.getCopyExpr()); + Cap.isNested(), Cap.getInitExpr()); Captures.push_back(NewCap); } BSI->TheDecl->setCaptures(Context, Captures.begin(), Captures.end(), @@ -11144,17 +11144,18 @@ bool Sema::tryCaptureVariable(VarDecl *Var, SourceLocation Loc, cast(FunctionScopes[FunctionScopesIndex]); // Check whether we've already captured it. - if (CSI->CaptureMap.count(Var)) { + if (CSI->isCaptured(Var)) { + const CapturingScopeInfo::Capture &Cap = CSI->getCapture(Var); + // If we found a capture, any subcaptures are nested. Nested = true; // Retrieve the capture type for this variable. - CaptureType = CSI->getCapture(Var).getCaptureType(); + CaptureType = Cap.getCaptureType(); // Compute the type of an expression that refers to this variable. DeclRefType = CaptureType.getNonReferenceType(); - const CapturingScopeInfo::Capture &Cap = CSI->getCapture(Var); if (Cap.isCopyCapture() && !(isa(CSI) && cast(CSI)->Mutable)) DeclRefType.addConst(); diff --git a/lib/Sema/SemaLambda.cpp b/lib/Sema/SemaLambda.cpp index 4e11bb4c05..d647be3761 100644 --- a/lib/Sema/SemaLambda.cpp +++ b/lib/Sema/SemaLambda.cpp @@ -18,6 +18,7 @@ #include "clang/Sema/Scope.h" #include "clang/Sema/ScopeInfo.h" #include "clang/Sema/SemaInternal.h" +#include "TypeLocBuilder.h" using namespace clang; using namespace sema; @@ -429,6 +430,88 @@ void Sema::deduceClosureReturnType(CapturingScopeInfo &CSI) { } } +FieldDecl *Sema::checkInitCapture(SourceLocation Loc, bool ByRef, + IdentifierInfo *Id, Expr *InitExpr) { + LambdaScopeInfo *LSI = getCurLambda(); + + // C++1y [expr.prim.lambda]p11: + // The type of [the] member corresponds to the type of a hypothetical + // variable declaration of the form "auto init-capture;" + QualType DeductType = Context.getAutoDeductType(); + TypeLocBuilder TLB; + TLB.pushTypeSpec(DeductType).setNameLoc(Loc); + if (ByRef) { + DeductType = BuildReferenceType(DeductType, true, Loc, Id); + assert(!DeductType.isNull() && "can't build reference to auto"); + TLB.push(DeductType).setSigilLoc(Loc); + } + + InitializationKind InitKind = InitializationKind::CreateDefault(Loc); + Expr *Init = InitExpr; + if (ParenListExpr *Parens = dyn_cast(Init)) { + if (Parens->getNumExprs() == 1) { + Init = Parens->getExpr(0); + InitKind = InitializationKind::CreateDirect( + Loc, Parens->getLParenLoc(), Parens->getRParenLoc()); + } else { + // C++1y [dcl.spec.auto]p3: + // In an initializer of the form ( expression-list ), the + // expression-list shall be a single assignment-expression. + if (Parens->getNumExprs() == 0) + Diag(Parens->getLocStart(), diag::err_init_capture_no_expression) + << Id; + else if (Parens->getNumExprs() > 1) + Diag(Parens->getExpr(1)->getLocStart(), + diag::err_init_capture_multiple_expressions) + << Id; + return 0; + } + } else if (isa(Init)) + // We do not need to distinguish between direct-list-initialization + // and copy-list-initialization here, because we will always deduce + // std::initializer_list, and direct- and copy-list-initialization + // always behave the same for such a type. + // FIXME: We should model whether an '=' was present. + InitKind = InitializationKind::CreateDirectList(Loc); + else + InitKind = InitializationKind::CreateCopy(Loc, Loc); + QualType DeducedType; + if (DeduceAutoType(TLB.getTemporaryTypeLoc(DeductType), + Init, DeducedType) == DAR_Failed) { + if (isa(Init)) + Diag(Loc, diag::err_init_capture_deduction_failure_from_init_list) + << Id << Init->getSourceRange(); + else + Diag(Loc, diag::err_init_capture_deduction_failure) + << Id << Init->getType() << Init->getSourceRange(); + } + if (DeducedType.isNull()) + return 0; + + // [...] a non-static data member named by the identifier is declared in + // the closure type. This member is not a bit-field and not mutable. + // Core issue: the member is (probably...) public. + FieldDecl *NewFD = CheckFieldDecl( + Id, DeducedType, TLB.getTypeSourceInfo(Context, DeductType), LSI->Lambda, + Loc, /*Mutable*/ false, /*BitWidth*/ 0, ICIS_NoInit, + Loc, AS_public, /*PrevDecl*/ 0, /*Declarator*/ 0); + LSI->Lambda->addDecl(NewFD); + + if (CurContext->isDependentContext()) { + LSI->addInitCapture(NewFD, InitExpr); + } else { + InitializedEntity Entity = InitializedEntity::InitializeMember(NewFD); + InitializationSequence InitSeq(*this, Entity, InitKind, Init); + if (!InitSeq.Diagnose(*this, Entity, InitKind, Init)) { + ExprResult InitResult = InitSeq.Perform(*this, Entity, InitKind, Init); + if (!InitResult.isInvalid()) + LSI->addInitCapture(NewFD, InitResult.take()); + } + } + + return NewFD; +} + void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro, Declarator &ParamInfo, Scope *CurScope) { @@ -514,7 +597,10 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro, = enterLambdaScope(Method, Intro.Range, Intro.Default, ExplicitParams, ExplicitResultType, !Method->isConst()); - + + // Distinct capture names, for diagnostics. + llvm::SmallSet CaptureNames; + // Handle explicit captures. SourceLocation PrevCaptureLoc = Intro.Default == LCD_None? Intro.Range.getBegin() : Intro.DefaultLoc; @@ -559,16 +645,32 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro, continue; } - // FIXME: C++1y [expr.prim.lambda]p11 + assert(C->Id && "missing identifier for capture"); + if (C->Init.isInvalid()) continue; if (C->Init.isUsable()) { - Diag(C->Loc, diag::err_lambda_init_capture_unsupported); + // C++11 [expr.prim.lambda]p8: + // An identifier or this shall not appear more than once in a + // lambda-capture. + if (!CaptureNames.insert(C->Id)) + Diag(C->Loc, diag::err_capture_more_than_once) << C->Id; + + if (C->Init.get()->containsUnexpandedParameterPack()) + ContainsUnexpandedParameterPack = true; + + FieldDecl *NewFD = checkInitCapture(C->Loc, C->Kind == LCK_ByRef, + C->Id, C->Init.take()); + // C++1y [expr.prim.lambda]p11: + // Within the lambda-expression's lambda-declarator and + // compound-statement, the identifier in the init-capture + // hides any declaration of the same name in scopes enclosing + // the lambda-expression. + if (NewFD) + PushOnScopeChains(NewFD, CurScope, false); continue; } - assert(C->Id && "missing identifier for capture"); - // C++11 [expr.prim.lambda]p8: // If a lambda-capture includes a capture-default that is &, the // identifiers in the lambda-capture shall not be preceded by &. @@ -586,6 +688,9 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro, continue; } + // C++11 [expr.prim.lambda]p10: + // The identifiers in a capture-list are looked up using the usual + // rules for unqualified name lookup (3.4.1) DeclarationNameInfo Name(C->Id, C->Loc); LookupResult R(*this, Name, LookupOrdinaryName); LookupName(R, CurScope); @@ -599,14 +704,27 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro, continue; } + VarDecl *Var = R.getAsSingle(); + + // C++11 [expr.prim.lambda]p8: + // An identifier or this shall not appear more than once in a + // lambda-capture. + if (!CaptureNames.insert(C->Id)) { + if (Var && LSI->isCaptured(Var)) { + Diag(C->Loc, diag::err_capture_more_than_once) + << C->Id << SourceRange(LSI->getCapture(Var).getLocation()) + << FixItHint::CreateRemoval( + SourceRange(PP.getLocForEndOfToken(PrevCaptureLoc), C->Loc)); + } else + // Previous capture was an init-capture: no fixit. + Diag(C->Loc, diag::err_capture_more_than_once) << C->Id; + continue; + } + // C++11 [expr.prim.lambda]p10: - // The identifiers in a capture-list are looked up using the usual rules - // for unqualified name lookup (3.4.1); each such lookup shall find a - // variable with automatic storage duration declared in the reaching - // scope of the local lambda expression. - // + // [...] each such lookup shall find a variable with automatic storage + // duration declared in the reaching scope of the local lambda expression. // Note that the 'reaching scope' check happens in tryCaptureVariable(). - VarDecl *Var = R.getAsSingle(); if (!Var) { Diag(C->Loc, diag::err_capture_does_not_name_variable) << C->Id; continue; @@ -622,18 +740,6 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro, continue; } - // C++11 [expr.prim.lambda]p8: - // An identifier or this shall not appear more than once in a - // lambda-capture. - if (LSI->isCaptured(Var)) { - Diag(C->Loc, diag::err_capture_more_than_once) - << C->Id - << SourceRange(LSI->getCapture(Var).getLocation()) - << FixItHint::CreateRemoval( - SourceRange(PP.getLocForEndOfToken(PrevCaptureLoc), C->Loc)); - continue; - } - // C++11 [expr.prim.lambda]p23: // A capture followed by an ellipsis is a pack expansion (14.5.3). SourceLocation EllipsisLoc; @@ -853,11 +959,17 @@ ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body, continue; } + if (From.isInitCapture()) { + Captures.push_back(LambdaExpr::Capture(From.getInitCaptureField())); + CaptureInits.push_back(From.getInitExpr()); + continue; + } + VarDecl *Var = From.getVariable(); LambdaCaptureKind Kind = From.isCopyCapture()? LCK_ByCopy : LCK_ByRef; Captures.push_back(LambdaExpr::Capture(From.getLocation(), IsImplicit, Kind, Var, From.getEllipsisLoc())); - CaptureInits.push_back(From.getCopyExpr()); + CaptureInits.push_back(From.getInitExpr()); } switch (LSI->ImpCaptureStyle) { diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp index 6d568c4d0b..3cd1a11ba5 100644 --- a/lib/Sema/SemaStmt.cpp +++ b/lib/Sema/SemaStmt.cpp @@ -3063,7 +3063,7 @@ static void buildCapturedStmtCaptureList( if (Cap->isThisCapture()) { Captures.push_back(CapturedStmt::Capture(Cap->getLocation(), CapturedStmt::VCK_This)); - CaptureInits.push_back(Cap->getCopyExpr()); + CaptureInits.push_back(Cap->getInitExpr()); continue; } @@ -3073,7 +3073,7 @@ static void buildCapturedStmtCaptureList( Captures.push_back(CapturedStmt::Capture(Cap->getLocation(), CapturedStmt::VCK_ByRef, Cap->getVariable())); - CaptureInits.push_back(Cap->getCopyExpr()); + CaptureInits.push_back(Cap->getInitExpr()); } } diff --git a/lib/Sema/SemaTemplateVariadic.cpp b/lib/Sema/SemaTemplateVariadic.cpp index db885aeec7..3b8228016c 100644 --- a/lib/Sema/SemaTemplateVariadic.cpp +++ b/lib/Sema/SemaTemplateVariadic.cpp @@ -179,10 +179,14 @@ namespace { // If any capture names a function parameter pack, that pack is expanded // when the lambda is expanded. for (LambdaExpr::capture_iterator I = Lambda->capture_begin(), - E = Lambda->capture_end(); I != E; ++I) - if (VarDecl *VD = I->getCapturedVar()) + E = Lambda->capture_end(); + I != E; ++I) { + if (I->capturesVariable()) { + VarDecl *VD = I->getCapturedVar(); if (VD->isParameterPack()) Unexpanded.push_back(std::make_pair(VD, I->getLocation())); + } + } inherited::TraverseLambdaExpr(Lambda); diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index 253135ff70..95ea9bc4ec 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -8074,6 +8074,22 @@ template ExprResult TreeTransform::TransformLambdaScope(LambdaExpr *E, CXXMethodDecl *CallOperator) { + bool Invalid = false; + + // Transform any init-capture expressions before entering the scope of the + // lambda. + llvm::SmallVector InitCaptureExprs; + InitCaptureExprs.resize(E->explicit_capture_end() - + E->explicit_capture_begin()); + for (LambdaExpr::capture_iterator C = E->capture_begin(), + CEnd = E->capture_end(); + C != CEnd; ++C) { + if (!C->isInitCapture()) + continue; + InitCaptureExprs[C - E->capture_begin()] = + getDerived().TransformExpr(E->getInitCaptureInit(C)); + } + // Introduce the context of the call operator. Sema::ContextRAII SavedContext(getSema(), CallOperator); @@ -8086,7 +8102,6 @@ TreeTransform::TransformLambdaScope(LambdaExpr *E, E->isMutable()); // Transform captures. - bool Invalid = false; bool FinishedExplicitCaptures = false; for (LambdaExpr::capture_iterator C = E->capture_begin(), CEnd = E->capture_end(); @@ -8104,6 +8119,26 @@ TreeTransform::TransformLambdaScope(LambdaExpr *E, continue; } + // Rebuild init-captures, including the implied field declaration. + if (C->isInitCapture()) { + ExprResult Init = InitCaptureExprs[C - E->capture_begin()]; + if (Init.isInvalid()) { + Invalid = true; + continue; + } + FieldDecl *OldFD = C->getInitCaptureField(); + FieldDecl *NewFD = getSema().checkInitCapture( + C->getLocation(), OldFD->getType()->isReferenceType(), + OldFD->getIdentifier(), Init.take()); + if (!NewFD) + Invalid = true; + else + getDerived().transformedLocalDecl(OldFD, NewFD); + continue; + } + + assert(C->capturesVariable() && "unexpected kind of lambda capture"); + // Determine the capture kind for Sema. Sema::TryCaptureKind Kind = C->isImplicit()? Sema::TryCapture_Implicit @@ -8120,8 +8155,10 @@ TreeTransform::TransformLambdaScope(LambdaExpr *E, C->getLocation(), Unexpanded, ShouldExpand, RetainExpansion, - NumExpansions)) - return ExprError(); + NumExpansions)) { + Invalid = true; + continue; + } if (ShouldExpand) { // The transform has determined that we should perform an expansion; diff --git a/lib/Serialization/ASTReaderDecl.cpp b/lib/Serialization/ASTReaderDecl.cpp index b117b733a4..11c82daaf5 100644 --- a/lib/Serialization/ASTReaderDecl.cpp +++ b/lib/Serialization/ASTReaderDecl.cpp @@ -1160,9 +1160,22 @@ void ASTDeclReader::ReadCXXDefinitionData( SourceLocation Loc = ReadSourceLocation(Record, Idx); bool IsImplicit = Record[Idx++]; LambdaCaptureKind Kind = static_cast(Record[Idx++]); - VarDecl *Var = ReadDeclAs(Record, Idx); - SourceLocation EllipsisLoc = ReadSourceLocation(Record, Idx); - *ToCapture++ = Capture(Loc, IsImplicit, Kind, Var, EllipsisLoc); + switch (Kind) { + case LCK_This: + *ToCapture++ = Capture(Loc, IsImplicit, Kind, 0, SourceLocation()); + break; + case LCK_ByCopy: + case LCK_ByRef: { + VarDecl *Var = ReadDeclAs(Record, Idx); + SourceLocation EllipsisLoc = ReadSourceLocation(Record, Idx); + *ToCapture++ = Capture(Loc, IsImplicit, Kind, Var, EllipsisLoc); + break; + } + case LCK_Init: + FieldDecl *Field = ReadDeclAs(Record, Idx); + *ToCapture++ = Capture(Field); + break; + } } } } diff --git a/lib/Serialization/ASTWriter.cpp b/lib/Serialization/ASTWriter.cpp index dd5818f843..ba6243a51a 100644 --- a/lib/Serialization/ASTWriter.cpp +++ b/lib/Serialization/ASTWriter.cpp @@ -5047,12 +5047,25 @@ void ASTWriter::AddCXXDefinitionData(const CXXRecordDecl *D, RecordDataImpl &Rec LambdaExpr::Capture &Capture = Lambda.Captures[I]; AddSourceLocation(Capture.getLocation(), Record); Record.push_back(Capture.isImplicit()); - Record.push_back(Capture.getCaptureKind()); // FIXME: stable! - VarDecl *Var = Capture.capturesVariable()? Capture.getCapturedVar() : 0; - AddDeclRef(Var, Record); - AddSourceLocation(Capture.isPackExpansion()? Capture.getEllipsisLoc() - : SourceLocation(), - Record); + Record.push_back(Capture.getCaptureKind()); + switch (Capture.getCaptureKind()) { + case LCK_This: + break; + case LCK_ByCopy: + case LCK_ByRef: { + VarDecl *Var = + Capture.capturesVariable() ? Capture.getCapturedVar() : 0; + AddDeclRef(Var, Record); + AddSourceLocation(Capture.isPackExpansion() ? Capture.getEllipsisLoc() + : SourceLocation(), + Record); + break; + } + case LCK_Init: + FieldDecl *Field = Capture.getInitCaptureField(); + AddDeclRef(Field, Record); + break; + } } } } diff --git a/test/CXX/expr/expr.prim/expr.prim.lambda/p11-1y.cpp b/test/CXX/expr/expr.prim/expr.prim.lambda/p11-1y.cpp new file mode 100644 index 0000000000..0eec331b28 --- /dev/null +++ b/test/CXX/expr/expr.prim/expr.prim.lambda/p11-1y.cpp @@ -0,0 +1,84 @@ +// RUN: %clang_cc1 -std=c++1y %s -verify + +// For every init-capture a non-static data member named by the identifier of +// the init-capture is declared in the closure type. +const char *has_member_x = [x("hello")] {}.x; +// This member is not a bit-field... +auto capturing_lambda = [n(0)] {}; +int decltype(capturing_lambda)::*mem_ptr = &decltype(capturing_lambda)::n; +// ... and not mutable. +const auto capturing_lambda_copy = capturing_lambda; +int &n = capturing_lambda_copy.n; // expected-error {{drops qualifiers}} + +// The type of that member [...is that of a...] variable declaration of the form +// "auto init-capture ;"... +auto with_float = [f(1.0f)] {}; +float &f = with_float.f; +// ... except that the variable name is replaced by a unique identifier. +auto with_float_2 = [&f(f)] {}; // ok, refers to outer f +float &f2 = with_float_2.f; + +// Within the lambda-expression's lambda-declarator (FIXME) and +// compound-statement, the identifier in the init-capture hides any declaration +// of the same name in scopes enclosing the lambda-expression. +void hiding() { + char c; + (void) [c("foo")] { + static_assert(sizeof(c) == sizeof(const char*), ""); + }; + (void) [c("bar")] () -> decltype(c) { + // FIXME: the 'c' in the return type should be the init-capture, not the + // outer c. + return "baz"; // expected-error {{cannot initialize}} + }; +} + +struct ExplicitCopy { + ExplicitCopy(); // expected-note 2{{not viable}} + explicit ExplicitCopy(const ExplicitCopy&); +}; +auto init_kind_1 = [ec(ExplicitCopy())] {}; +auto init_kind_2 = [ec = ExplicitCopy()] {}; // expected-error {{no matching constructor}} + +template void init_kind_template() { + auto init_kind_1 = [ec(T())] {}; + auto init_kind_2 = [ec = T()] {}; // expected-error {{no matching constructor}} +} +template void init_kind_template(); +template void init_kind_template(); // expected-note {{instantiation of}} + +void void_fn(); +int overload_fn(); +int overload_fn(int); + +auto bad_init_1 = [a()] {}; // expected-error {{expected expression}} +auto bad_init_2 = [a(1, 2)] {}; // expected-error {{initializer for lambda capture 'a' contains multiple expressions}} +auto bad_init_3 = [&a(void_fn())] {}; // expected-error {{cannot form a reference to 'void'}} +auto bad_init_4 = [a(void_fn())] {}; // expected-error {{field has incomplete type 'void'}} +auto bad_init_5 = [a(overload_fn)] {}; // expected-error {{cannot deduce type for lambda capture 'a' from initializer of type ' void pack_1(T...t) { [a(t...)] {}; } // expected-error {{initializer missing for lambda capture 'a'}} +template void pack_1<>(); // expected-note {{instantiation of}} + +auto multi_return(int a, int b) { + return [n(a + 2*b), m(a - 2*b)] {}; +} +auto use_multi_return() { + auto nm = multi_return(5, 9); + return nm.n + nm.m; +} + +auto a = [a(4), b = 5, &c = static_cast(0)] { + static_assert(sizeof(a) == sizeof(int), ""); + static_assert(sizeof(b) == sizeof(int), ""); + using T = decltype(c); + using T = const int &; +}; +auto b = [a{0}] {}; // expected-error {{include }} + +struct S { S(); S(S&&); }; +template struct remove_reference { typedef T type; }; +template struct remove_reference { typedef T type; }; +template decltype(auto) move(T &&t) { return static_cast::type&&>(t); } +auto s = [s(move(S()))] {}; diff --git a/test/CXX/expr/expr.prim/expr.prim.lambda/p23.cpp b/test/CXX/expr/expr.prim/expr.prim.lambda/p23.cpp index 82fc04a48f..174ae6d5b0 100644 --- a/test/CXX/expr/expr.prim/expr.prim.lambda/p23.cpp +++ b/test/CXX/expr/expr.prim/expr.prim.lambda/p23.cpp @@ -1,4 +1,5 @@ // RUN: %clang_cc1 -fsyntax-only -std=c++11 %s -verify +// RUN: %clang_cc1 -fsyntax-only -std=c++1y %s -verify void print(); @@ -56,3 +57,25 @@ void variadic_lambda(Args... args) { } template void variadic_lambda(int*, float*, double*); + +template +void init_capture_pack_err(Args ...args) { + [as(args)...] {} (); // expected-error {{expected ','}} + [as...(args)]{} (); // expected-error {{expected ','}} +} + +template +void init_capture_pack_multi(Args ...args) { + [as(args...)] {} (); // expected-error {{initializer missing}} expected-error {{multiple}} +} +template void init_capture_pack_multi(); // expected-note {{instantiation}} +template void init_capture_pack_multi(int); +template void init_capture_pack_multi(int, int); // expected-note {{instantiation}} + +template +void init_capture_pack_outer(Args ...args) { + print([as(args)] { return sizeof(as); } () ...); +} +template void init_capture_pack_outer(); +template void init_capture_pack_outer(int); +template void init_capture_pack_outer(int, int); diff --git a/test/CXX/expr/expr.prim/expr.prim.lambda/p8.cpp b/test/CXX/expr/expr.prim/expr.prim.lambda/p8.cpp index d1384f19dd..408fb75f80 100644 --- a/test/CXX/expr/expr.prim/expr.prim.lambda/p8.cpp +++ b/test/CXX/expr/expr.prim/expr.prim.lambda/p8.cpp @@ -26,4 +26,7 @@ void S2::f(int i) { (void)[=, this]{ }; // expected-error{{'this' cannot be explicitly captured}} (void)[=]{ this->g(i); }; (void)[i, i]{ }; // expected-error{{'i' can appear only once in a capture list}} + (void)[i(0), i(1)]{ }; // expected-error{{'i' can appear only once in a capture list}} + (void)[i, i(1)]{ }; // expected-error{{'i' can appear only once in a capture list}} + (void)[i(0), i]{ }; // expected-error{{'i' can appear only once in a capture list}} } diff --git a/test/PCH/cxx11-lambdas.mm b/test/PCH/cxx11-lambdas.mm index c00ec63807..807bf23067 100644 --- a/test/PCH/cxx11-lambdas.mm +++ b/test/PCH/cxx11-lambdas.mm @@ -33,6 +33,11 @@ inline int to_block_pointer(int n) { return block(17); } +template +int init_capture(T t) { + return [&, x(t)] { return sizeof(x); }; +} + #else // CHECK-PRINT: T add_slowly @@ -45,4 +50,8 @@ int add(int x, int y) { // CHECK-PRINT: inline int add_int_slowly_twice // CHECK-PRINT: lambda = [&] (int z) + +// CHECK-PRINT: init_capture +// CHECK-PRINT: [&, x( t )] + #endif diff --git a/test/Parser/cxx0x-lambda-expressions.cpp b/test/Parser/cxx0x-lambda-expressions.cpp index d7dc7d3a47..76c1e0e7ce 100644 --- a/test/Parser/cxx0x-lambda-expressions.cpp +++ b/test/Parser/cxx0x-lambda-expressions.cpp @@ -54,16 +54,16 @@ class C { void init_capture() { // FIXME: These diagnostics should all disappear once semantic analysis // for init-captures is complete. - [n(0)] () -> int { return ++n; }; // expected-error {{not supported}} expected-error {{undeclared}} - [n{0}] { return; }; // expected-error {{not supported}} - [n = 0] { return ++n; }; // expected-error {{not supported}} expected-error {{undeclared}} - [n = {0}] { return; }; // expected-error {{not supported}} - [a([&b = z]{})](){}; // expected-error 2{{not supported}} + [n(0)] () -> int { return ++n; }; // expected-error {{non-static data member}} + [n{0}] { return; }; // expected-error {{}} + [n = 0] { return ++n; }; // expected-error {{non-static data member}} + [n = {0}] { return; }; // expected-error {{}} + [a([&b = z]{})](){}; - int x = 4; // expected-note {{here}} - auto y = [&r = x, x = x + 1]() -> int { // expected-error 2{{not supported}} expected-note {{here}} - r += 2; // expected-error {{undeclared}} - return x + 2; // expected-error {{implicitly captured}} + int x = 4; + auto y = [&r = x, x = x + 1]() -> int { + r += 2; // expected-error {{non-static data member}} + return x + 2; // expected-error {{non-static data member}} } (); } }; diff --git a/test/Parser/objcxx0x-lambda-expressions.mm b/test/Parser/objcxx0x-lambda-expressions.mm index 94e47ccd3e..b2a75f2edb 100644 --- a/test/Parser/objcxx0x-lambda-expressions.mm +++ b/test/Parser/objcxx0x-lambda-expressions.mm @@ -18,10 +18,10 @@ class C { [=,&foo] () {}; [this] () {}; - [foo(bar)] () {}; // expected-error {{not supported}} - [foo = bar] () {}; // expected-error {{not supported}} - [foo{bar}] () {}; // expected-error {{not supported}} - [foo = {bar}] () {}; // expected-error {{not supported}} + [foo(bar)] () {}; + [foo = bar] () {}; + [foo{bar}] () {}; // expected-error {{}} + [foo = {bar}] () {}; // expected-error {{}} [foo(bar) baz] () {}; // expected-error {{called object type 'int' is not a function}} diff --git a/tools/libclang/CIndex.cpp b/tools/libclang/CIndex.cpp index 71827f8a23..db7faabbee 100644 --- a/tools/libclang/CIndex.cpp +++ b/tools/libclang/CIndex.cpp @@ -2366,9 +2366,10 @@ bool CursorVisitor::RunVisitorWorkList(VisitorWorkList &WL) { for (LambdaExpr::capture_iterator C = E->explicit_capture_begin(), CEnd = E->explicit_capture_end(); C != CEnd; ++C) { - if (C->capturesThis()) + // FIXME: Lambda init-captures. + if (!C->capturesVariable()) continue; - + if (Visit(MakeCursorVariableRef(C->getCapturedVar(), C->getLocation(), TU))) diff --git a/tools/libclang/IndexBody.cpp b/tools/libclang/IndexBody.cpp index 02ab885e62..e08a3461e8 100644 --- a/tools/libclang/IndexBody.cpp +++ b/tools/libclang/IndexBody.cpp @@ -153,9 +153,11 @@ public: if (C.capturesThis()) return true; - if (IndexCtx.shouldIndexFunctionLocalSymbols()) + if (C.capturesVariable() && IndexCtx.shouldIndexFunctionLocalSymbols()) IndexCtx.handleReference(C.getCapturedVar(), C.getLocation(), Parent, ParentDC); + + // FIXME: Lambda init-captures. return true; }