diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h --- a/clang/include/clang/AST/RecursiveASTVisitor.h +++ b/clang/include/clang/AST/RecursiveASTVisitor.h @@ -186,6 +186,9 @@ /// code, e.g., implicit constructors and destructors. bool shouldVisitImplicitCode() const { return false; } + /// Return whether this visitor should recurse into lambda body + bool shouldVisitLambdaBody() const { return true; } + /// Return whether this visitor should traverse post-order. bool shouldTraversePostOrder() const { return false; } @@ -2057,6 +2060,14 @@ // by clang. (!D->isDefaulted() || getDerived().shouldVisitImplicitCode()); + if (const auto *MD = dyn_cast(D)) { + if (const CXXRecordDecl *RD = MD->getParent()) { + if (RD->isLambda()) { + VisitBody = VisitBody && getDerived().shouldVisitLambdaBody(); + } + } + } + if (VisitBody) { TRY_TO(TraverseStmt(D->getBody())); // Function body. } diff --git a/clang/lib/ASTMatchers/ASTMatchFinder.cpp b/clang/lib/ASTMatchers/ASTMatchFinder.cpp --- a/clang/lib/ASTMatchers/ASTMatchFinder.cpp +++ b/clang/lib/ASTMatchers/ASTMatchFinder.cpp @@ -556,9 +556,9 @@ if (LE->hasExplicitResultType()) TraverseTypeLoc(Proto.getReturnLoc()); TraverseStmt(LE->getTrailingRequiresClause()); - - TraverseStmt(LE->getBody()); } + + TraverseStmt(LE->getBody()); return true; } return RecursiveASTVisitor::dataTraverseNode(S, Queue); @@ -697,6 +697,10 @@ bool shouldVisitTemplateInstantiations() const { return true; } bool shouldVisitImplicitCode() const { return true; } + // We visit the lambda body explicitly, so instruct the RAV + // to not visit it on our behalf too. + bool shouldVisitLambdaBody() const { return false; } + bool IsMatchingInASTNodeNotSpelledInSource() const override { return TraversingASTNodeNotSpelledInSource; } diff --git a/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp b/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp --- a/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp +++ b/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp @@ -3853,6 +3853,78 @@ } } +TEST(IgnoringImpCasts, PathologicalLambda) { + + // Test that deeply nested lambdas are not a performance penalty + StringRef Code = R"cpp( +void f() { + [] { + [] { + [] { + [] { + [] { + [] { + [] { + [] { + [] { + [] { + [] { + [] { + [] { + [] { + [] { + [] { + [] { + [] { + [] { + [] { + [] { + [] { + [] { + [] { + [] { + [] { + [] { + [] { + [] { + int i = 42; + (void)i; + }(); + }(); + }(); + }(); + }(); + }(); + }(); + }(); + }(); + }(); + }(); + }(); + }(); + }(); + }(); + }(); + }(); + }(); + }(); + }(); + }(); + }(); + }(); + }(); + }(); + }(); + }(); + }(); + }(); +} + )cpp"; + + EXPECT_TRUE(matches(Code, integerLiteral(equals(42)))); + EXPECT_TRUE(matches(Code, functionDecl(hasDescendant(integerLiteral(equals(42)))))); +} + TEST(IgnoringImpCasts, MatchesImpCasts) { // This test checks that ignoringImpCasts matches when implicit casts are // present and its inner matcher alone does not match.