Index: cfe/trunk/include/clang/AST/RecursiveASTVisitor.h =================================================================== --- cfe/trunk/include/clang/AST/RecursiveASTVisitor.h +++ cfe/trunk/include/clang/AST/RecursiveASTVisitor.h @@ -298,14 +298,6 @@ bool TraverseLambdaCapture(LambdaExpr *LE, const LambdaCapture *C, Expr *Init); - /// Recursively visit the body of a lambda expression. - /// - /// This provides a hook for visitors that need more context when visiting - /// \c LE->getBody(). - /// - /// \returns false if the visitation was terminated early, true otherwise. - bool TraverseLambdaBody(LambdaExpr *LE, DataRecursionQueue *Queue = nullptr); - /// Recursively visit the syntactic or semantic form of an /// initialization list. /// @@ -936,13 +928,6 @@ return true; } -template -bool RecursiveASTVisitor::TraverseLambdaBody( - LambdaExpr *LE, DataRecursionQueue *Queue) { - TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(LE->getBody()); - return true; -} - // ----------------- Type traversal ----------------- // This macro makes available a variable T, the passed-in type. @@ -2404,6 +2389,7 @@ // Walk only the visible parts of lambda expressions. DEF_TRAVERSE_STMT(LambdaExpr, { + // Visit the capture list. for (unsigned I = 0, N = S->capture_size(); I != N; ++I) { const LambdaCapture *C = S->capture_begin() + I; if (C->isExplicit() || getDerived().shouldVisitImplicitCode()) { @@ -2411,25 +2397,31 @@ } } - TypeLoc TL = S->getCallOperator()->getTypeSourceInfo()->getTypeLoc(); - FunctionProtoTypeLoc Proto = TL.getAsAdjusted(); + if (getDerived().shouldVisitImplicitCode()) { + // The implicit model is simple: everything else is in the lambda class. + TRY_TO(TraverseDecl(S->getLambdaClass())); + } else { + // We need to poke around to find the bits that might be explicitly written. + TypeLoc TL = S->getCallOperator()->getTypeSourceInfo()->getTypeLoc(); + FunctionProtoTypeLoc Proto = TL.getAsAdjusted(); + + if (S->hasExplicitParameters()) { + // Visit parameters. + for (unsigned I = 0, N = Proto.getNumParams(); I != N; ++I) + TRY_TO(TraverseDecl(Proto.getParam(I))); + } + if (S->hasExplicitResultType()) + TRY_TO(TraverseTypeLoc(Proto.getReturnLoc())); - if (S->hasExplicitParameters()) { - // Visit parameters. - for (unsigned I = 0, N = Proto.getNumParams(); I != N; ++I) - TRY_TO(TraverseDecl(Proto.getParam(I))); - } - if (S->hasExplicitResultType()) - TRY_TO(TraverseTypeLoc(Proto.getReturnLoc())); + auto *T = Proto.getTypePtr(); + for (const auto &E : T->exceptions()) + TRY_TO(TraverseType(E)); - auto *T = Proto.getTypePtr(); - for (const auto &E : T->exceptions()) - TRY_TO(TraverseType(E)); + if (Expr *NE = T->getNoexceptExpr()) + TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(NE); - if (Expr *NE = T->getNoexceptExpr()) - TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(NE); - - ReturnValue = TRAVERSE_STMT_BASE(LambdaBody, LambdaExpr, S, Queue); + TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(S->getBody()); + } ShouldVisitChildren = false; }) Index: cfe/trunk/lib/CodeGen/CodeGenPGO.cpp =================================================================== --- cfe/trunk/lib/CodeGen/CodeGenPGO.cpp +++ cfe/trunk/lib/CodeGen/CodeGenPGO.cpp @@ -165,7 +165,12 @@ // Blocks and lambdas are handled as separate functions, so we need not // traverse them in the parent context. bool TraverseBlockExpr(BlockExpr *BE) { return true; } - bool TraverseLambdaBody(LambdaExpr *LE) { return true; } + bool TraverseLambdaExpr(LambdaExpr *LE) { + // Traverse the captures, but not the body. + for (const auto &C : zip(LE->captures(), LE->capture_inits())) + TraverseLambdaCapture(LE, &std::get<0>(C), std::get<1>(C)); + return true; + } bool TraverseCapturedStmt(CapturedStmt *CS) { return true; } bool VisitDecl(const Decl *D) { Index: cfe/trunk/lib/Sema/AnalysisBasedWarnings.cpp =================================================================== --- cfe/trunk/lib/Sema/AnalysisBasedWarnings.cpp +++ cfe/trunk/lib/Sema/AnalysisBasedWarnings.cpp @@ -1153,7 +1153,12 @@ bool TraverseDecl(Decl *D) { return true; } // We analyze lambda bodies separately. Skip them here. - bool TraverseLambdaBody(LambdaExpr *LE) { return true; } + bool TraverseLambdaExpr(LambdaExpr *LE) { + // Traverse the captures, but not the body. + for (const auto &C : zip(LE->captures(), LE->capture_inits())) + TraverseLambdaCapture(LE, &std::get<0>(C), std::get<1>(C)); + return true; + } private: Index: cfe/trunk/unittests/AST/ASTContextParentMapTest.cpp =================================================================== --- cfe/trunk/unittests/AST/ASTContextParentMapTest.cpp +++ cfe/trunk/unittests/AST/ASTContextParentMapTest.cpp @@ -106,5 +106,16 @@ EXPECT_THAT(Ctx.getParents(Foo), ElementsAre(DynTypedNode::create(TU))); } +TEST(GetParents, ImplicitLambdaNodes) { + MatchVerifier LambdaVerifier; + EXPECT_TRUE(LambdaVerifier.match( + "auto x = []{int y;};", + varDecl(hasName("y"), hasAncestor(functionDecl( + hasOverloadedOperatorName("()"), + hasParent(cxxRecordDecl( + isImplicit(), hasParent(lambdaExpr())))))), + Lang_CXX11)); +} + } // end namespace ast_matchers } // end namespace clang Index: cfe/trunk/unittests/Tooling/RecursiveASTVisitorTests/LambdaExpr.cpp =================================================================== --- cfe/trunk/unittests/Tooling/RecursiveASTVisitorTests/LambdaExpr.cpp +++ cfe/trunk/unittests/Tooling/RecursiveASTVisitorTests/LambdaExpr.cpp @@ -17,25 +17,33 @@ class LambdaExprVisitor : public ExpectedLocationVisitor { public: bool VisitLambdaExpr(LambdaExpr *Lambda) { - PendingBodies.push(Lambda); + PendingBodies.push(Lambda->getBody()); + PendingClasses.push(Lambda->getLambdaClass()); Match("", Lambda->getIntroducerRange().getBegin()); return true; } - /// For each call to VisitLambdaExpr, we expect a subsequent call (with - /// proper nesting) to TraverseLambdaBody. - bool TraverseLambdaBody(LambdaExpr *Lambda) { - EXPECT_FALSE(PendingBodies.empty()); - EXPECT_EQ(PendingBodies.top(), Lambda); - PendingBodies.pop(); - return TraverseStmt(Lambda->getBody()); + /// For each call to VisitLambdaExpr, we expect a subsequent call to visit + /// the body (and maybe the lambda class, which is implicit). + bool VisitStmt(Stmt *S) { + if (!PendingBodies.empty() && S == PendingBodies.top()) + PendingBodies.pop(); + return true; } - /// Determine whether TraverseLambdaBody has been called for every call to - /// VisitLambdaExpr. - bool allBodiesHaveBeenTraversed() const { - return PendingBodies.empty(); + bool VisitDecl(Decl *D) { + if (!PendingClasses.empty() && D == PendingClasses.top()) + PendingClasses.pop(); + return true; } + /// Determine whether parts of lambdas (VisitLambdaExpr) were later traversed. + bool allBodiesHaveBeenTraversed() const { return PendingBodies.empty(); } + bool allClassesHaveBeenTraversed() const { return PendingClasses.empty(); } + + bool VisitImplicitCode = false; + bool shouldVisitImplicitCode() const { return VisitImplicitCode; } + private: - std::stack PendingBodies; + std::stack PendingBodies; + std::stack PendingClasses; }; TEST(RecursiveASTVisitor, VisitsLambdaExpr) { @@ -43,13 +51,28 @@ Visitor.ExpectMatch("", 1, 12); EXPECT_TRUE(Visitor.runOver("void f() { []{ return; }(); }", LambdaExprVisitor::Lang_CXX11)); + EXPECT_TRUE(Visitor.allBodiesHaveBeenTraversed()); + EXPECT_FALSE(Visitor.allClassesHaveBeenTraversed()); +} + +TEST(RecursiveASTVisitor, LambdaInLambda) { + LambdaExprVisitor Visitor; + Visitor.ExpectMatch("", 1, 12); + Visitor.ExpectMatch("", 1, 16); + EXPECT_TRUE(Visitor.runOver("void f() { []{ []{ return; }; }(); }", + LambdaExprVisitor::Lang_CXX11)); + EXPECT_TRUE(Visitor.allBodiesHaveBeenTraversed()); + EXPECT_FALSE(Visitor.allClassesHaveBeenTraversed()); } -TEST(RecursiveASTVisitor, TraverseLambdaBodyCanBeOverridden) { +TEST(RecursiveASTVisitor, VisitsLambdaExprAndImplicitClass) { LambdaExprVisitor Visitor; + Visitor.VisitImplicitCode = true; + Visitor.ExpectMatch("", 1, 12); EXPECT_TRUE(Visitor.runOver("void f() { []{ return; }(); }", LambdaExprVisitor::Lang_CXX11)); EXPECT_TRUE(Visitor.allBodiesHaveBeenTraversed()); + EXPECT_TRUE(Visitor.allClassesHaveBeenTraversed()); } TEST(RecursiveASTVisitor, VisitsAttributedLambdaExpr) {