Thanks for the prompt response! On Thu, Jan 28, 2021 at 12:52 AM Stephen Kelly <steve...@gmail.com> wrote:
> > Thanks for reporting. Please try https://reviews.llvm.org/D95573 > > Thanks, > > Stephen. > On 27/01/2021 22:58, Alexander Kornienko wrote: > > This patch causes practically infinite traversal times on code that > contains deeply nested lambdas. Please fix or revert the commit. > > There's a very simple test case (add more nesting, if it's still fast ;): > > void f() { > [] { > [] { > [] { > [] { > [] { > [] { > [] { > [] { > [] { > [] { > [] { > [] { > [] { > [] { > [] { > [] { > [] { > [] { > [] { > [] { > [] { > [] { > [] { > [] { > [] { > [] { > [] { > [] { > [] { > }(); > }(); > }(); > }(); > }(); > }(); > }(); > }(); > }(); > }(); > }(); > }(); > }(); > }(); > }(); > }(); > }(); > }(); > }(); > }(); > }(); > }(); > }(); > }(); > }(); > }(); > }(); > }(); > }(); > } > > Three nested lambdas are enough to demonstrate the issue by looking at the > AST dump. The body of the innermost lambda (0x45593fda99a0) is printed 8 > times, and it will be traversed 8 times as well by AST matchers: > `-FunctionDecl 0x45593fda9198 </tmp/nested-lambdas.cc:1:1, line:8:1> > line:1:6 f 'void ()' > `-CompoundStmt 0x45593fdce970 <col:10, line:8:1> > `-ExprWithCleanups 0x45593fdce958 <line:2:3, line:7:5> 'void':'void' > `-CXXOperatorCallExpr 0x45593fdce928 <line:2:3, line:7:5> > 'void':'void' '()' > |-ImplicitCastExpr 0x45593fdce8b0 <col:4, col:5> 'auto (*)() const > -> void' <FunctionToPointerDecay> > | `-DeclRefExpr 0x45593fdce890 <col:4, col:5> 'auto () const -> > void' lvalue CXXMethod 0x45593fda9490 'operator()' 'auto () const -> void' > `-ImplicitCastExpr 0x45593fdce910 <line:2:3, line:7:3> 'const > (lambda at /tmp/nested-lambdas.cc:2:3)' lvalue <NoOp> > `-MaterializeTemporaryExpr 0x45593fdce8f8 <line:2:3, line:7:3> > '(lambda at /tmp/nested-lambdas.cc:2:3)' lvalue > `-LambdaExpr 0x45593fdce788 <line:2:3, line:7:3> '(lambda at > /tmp/nested-lambdas.cc:2:3)' > |-CXXRecordDecl 0x45593fda9350 <line:2:3> col:3 implicit > class definition > | |-DefinitionData lambda pass_in_registers empty > standard_layout trivially_copyable literal can_const_default_init > | | |-DefaultConstructor defaulted_is_constexpr > | | |-CopyConstructor simple trivial has_const_param > needs_implicit implicit_has_const_param > | | |-MoveConstructor exists simple trivial needs_implicit > | | |-CopyAssignment trivial has_const_param needs_implicit > implicit_has_const_param > | | |-MoveAssignment > | | `-Destructor simple irrelevant trivial > | |-CXXMethodDecl 0x45593fda9490 <col:4, line:7:3> line:2:3 > used constexpr operator() 'auto () const -> void' inline > | | `-CompoundStmt 0x45593fdce4e0 <col:6, line:7:3> > | | `-ExprWithCleanups 0x45593fdce4c8 <line:3:3, line:6:5> > 'void':'void' > | | `-CXXOperatorCallExpr 0x45593fdce498 <line:3:3, > line:6:5> 'void':'void' '()' > | | |-ImplicitCastExpr 0x45593fdce420 <col:4, col:5> > 'auto (*)() const -> void' <FunctionToPointerDecay> > | | | `-DeclRefExpr 0x45593fdce400 <col:4, col:5> > 'auto () const -> void' lvalue CXXMethod 0x45593fda96c0 'operator()' 'auto > () const -> void' > | | `-ImplicitCastExpr 0x45593fdce480 <line:3:3, > line:6:3> 'const (lambda at /tmp/nested-lambdas.cc:3:3)' lvalue <NoOp> > | | `-MaterializeTemporaryExpr 0x45593fdce468 > <line:3:3, line:6:3> '(lambda at /tmp/nested-lambdas.cc:3:3)' lvalue > | | `-LambdaExpr 0x45593fdce2f0 <line:3:3, > line:6:3> '(lambda at /tmp/nested-lambdas.cc:3:3)' > | | |-CXXRecordDecl 0x45593fda9588 <line:3:3> > col:3 implicit class definition > | | | |-DefinitionData lambda pass_in_registers > empty standard_layout trivially_copyable literal can_const_default_init > | | | | |-DefaultConstructor > defaulted_is_constexpr > | | | | |-CopyConstructor simple trivial > has_const_param needs_implicit implicit_has_const_param > | | | | |-MoveConstructor exists simple trivial > needs_implicit > | | | | |-CopyAssignment trivial has_const_param > needs_implicit implicit_has_const_param > | | | | |-MoveAssignment > | | | | `-Destructor simple irrelevant trivial > | | | |-CXXMethodDecl 0x45593fda96c0 <col:4, > line:6:3> line:3:3 used constexpr operator() 'auto () const -> void' inline > | | | | `-CompoundStmt 0x45593fdce048 <col:6, > line:6:3> > | | | | `-ExprWithCleanups 0x45593fdce030 > <line:4:3, line:5:5> 'void':'void' > | | | | `-CXXOperatorCallExpr 0x45593fdce000 > <line:4:3, line:5:5> 'void':'void' '()' > | | | | |-ImplicitCastExpr 0x45593fda9f88 > <col:4, col:5> 'auto (*)() const -> void' <FunctionToPointerDecay> > | | | | | `-DeclRefExpr 0x45593fda9f08 > <col:4, col:5> 'auto () const -> void' lvalue CXXMethod 0x45593fda98f0 > 'operator()' 'auto () const -> void' > | | | | `-ImplicitCastExpr 0x45593fda9fe0 > <line:4:3, line:5:3> 'const (lambda at /tmp/nested-lambdas.cc:4:3)' lvalue > <NoOp> > | | | | `-MaterializeTemporaryExpr > 0x45593fda9fc8 <line:4:3, line:5:3> '(lambda at > /tmp/nested-lambdas.cc:4:3)' lvalue > | | | | `-LambdaExpr 0x45593fda9dd0 > <line:4:3, line:5:3> '(lambda at /tmp/nested-lambdas.cc:4:3)' > | | | | |-CXXRecordDecl > 0x45593fda97b8 <line:4:3> col:3 implicit class definition > | | | | | |-DefinitionData lambda > pass_in_registers empty standard_layout trivially_copyable literal > can_const_default_init > | | | | | | |-DefaultConstructor > defaulted_is_constexpr > | | | | | | |-CopyConstructor simple > trivial has_const_param needs_implicit implicit_has_const_param > | | | | | | |-MoveConstructor exists > simple trivial needs_implicit > | | | | | | |-CopyAssignment trivial > has_const_param needs_implicit implicit_has_const_param > | | | | | | |-MoveAssignment > | | | | | | `-Destructor simple > irrelevant trivial > | | | | | |-CXXMethodDecl > 0x45593fda98f0 <col:4, line:5:3> line:4:3 used constexpr operator() 'auto > () const -> void' inline > | | | | | | `-CompoundStmt > 0x45593fda99a0 <col:6, line:5:3> > | | | | | |-CXXConversionDecl > 0x45593fda9c68 <line:4:3, line:5:3> line:4:3 implicit constexpr operator > void (*)() 'auto (*() const noexcept)() -> void' inline > | | | | | |-CXXMethodDecl > 0x45593fda9d18 <col:3, line:5:3> line:4:3 implicit __invoke 'auto () -> > void' static inline > | | | | | `-CXXDestructorDecl > 0x45593fda9df8 <col:3> col:3 implicit referenced ~ 'void () noexcept' > inline default trivial > | | | | `-CompoundStmt > 0x45593fda99a0 <col:6, line:5:3> > | | | |-CXXConversionDecl 0x45593fdce188 > <line:3:3, line:6:3> line:3:3 implicit constexpr operator void (*)() 'auto > (*() const noexcept)() -> void' inline > | | | |-CXXMethodDecl 0x45593fdce238 <col:3, > line:6:3> line:3:3 implicit __invoke 'auto () -> void' static inline > | | | `-CXXDestructorDecl 0x45593fdce318 <col:3> > col:3 implicit referenced ~ 'void () noexcept' inline default trivial > | | `-CompoundStmt 0x45593fdce048 <col:6, > line:6:3> > | | `-ExprWithCleanups 0x45593fdce030 > <line:4:3, line:5:5> 'void':'void' > | | `-CXXOperatorCallExpr 0x45593fdce000 > <line:4:3, line:5:5> 'void':'void' '()' > | | |-ImplicitCastExpr 0x45593fda9f88 > <col:4, col:5> 'auto (*)() const -> void' <FunctionToPointerDecay> > | | | `-DeclRefExpr 0x45593fda9f08 <col:4, > col:5> 'auto () const -> void' lvalue CXXMethod 0x45593fda98f0 'operator()' > 'auto () const -> void' > | | `-ImplicitCastExpr 0x45593fda9fe0 > <line:4:3, line:5:3> 'const (lambda at /tmp/nested-lambdas.cc:4:3)' lvalue > <NoOp> > | | `-MaterializeTemporaryExpr > 0x45593fda9fc8 <line:4:3, line:5:3> '(lambda at > /tmp/nested-lambdas.cc:4:3)' lvalue > | | `-LambdaExpr 0x45593fda9dd0 > <line:4:3, line:5:3> '(lambda at /tmp/nested-lambdas.cc:4:3)' > | | |-CXXRecordDecl 0x45593fda97b8 > <line:4:3> col:3 implicit class definition > | | | |-DefinitionData lambda > pass_in_registers empty standard_layout trivially_copyable literal > can_const_default_init > | | | | |-DefaultConstructor > defaulted_is_constexpr > | | | | |-CopyConstructor simple > trivial has_const_param needs_implicit implicit_has_const_param > | | | | |-MoveConstructor exists > simple trivial needs_implicit > | | | | |-CopyAssignment trivial > has_const_param needs_implicit implicit_has_const_param > | | | | |-MoveAssignment > | | | | `-Destructor simple > irrelevant trivial > | | | |-CXXMethodDecl 0x45593fda98f0 > <col:4, line:5:3> line:4:3 used constexpr operator() 'auto () const -> > void' inline > | | | | `-CompoundStmt > 0x45593fda99a0 <col:6, line:5:3> > | | | |-CXXConversionDecl > 0x45593fda9c68 <line:4:3, line:5:3> line:4:3 implicit constexpr operator > void (*)() 'auto (*() const noexcept)() -> void' inline > | | | |-CXXMethodDecl 0x45593fda9d18 > <col:3, line:5:3> line:4:3 implicit __invoke 'auto () -> void' static inline > | | | `-CXXDestructorDecl > 0x45593fda9df8 <col:3> col:3 implicit referenced ~ 'void () noexcept' > inline default trivial > | | `-CompoundStmt 0x45593fda99a0 > <col:6, line:5:3> > | |-CXXConversionDecl 0x45593fdce620 <line:2:3, line:7:3> > line:2:3 implicit constexpr operator void (*)() 'auto (*() const > noexcept)() -> void' inline > | |-CXXMethodDecl 0x45593fdce6d0 <col:3, line:7:3> line:2:3 > implicit __invoke 'auto () -> void' static inline > | `-CXXDestructorDecl 0x45593fdce7b0 <col:3> col:3 implicit > referenced ~ 'void () noexcept' inline default trivial > `-CompoundStmt 0x45593fdce4e0 <col:6, line:7:3> > `-ExprWithCleanups 0x45593fdce4c8 <line:3:3, line:6:5> > 'void':'void' > `-CXXOperatorCallExpr 0x45593fdce498 <line:3:3, > line:6:5> 'void':'void' '()' > |-ImplicitCastExpr 0x45593fdce420 <col:4, col:5> 'auto > (*)() const -> void' <FunctionToPointerDecay> > | `-DeclRefExpr 0x45593fdce400 <col:4, col:5> 'auto () > const -> void' lvalue CXXMethod 0x45593fda96c0 'operator()' 'auto () const > -> void' > `-ImplicitCastExpr 0x45593fdce480 <line:3:3, line:6:3> > 'const (lambda at /tmp/nested-lambdas.cc:3:3)' lvalue <NoOp> > `-MaterializeTemporaryExpr 0x45593fdce468 <line:3:3, > line:6:3> '(lambda at /tmp/nested-lambdas.cc:3:3)' lvalue > `-LambdaExpr 0x45593fdce2f0 <line:3:3, line:6:3> > '(lambda at /tmp/nested-lambdas.cc:3:3)' > |-CXXRecordDecl 0x45593fda9588 <line:3:3> col:3 > implicit class definition > | |-DefinitionData lambda pass_in_registers > empty standard_layout trivially_copyable literal can_const_default_init > | | |-DefaultConstructor defaulted_is_constexpr > | | |-CopyConstructor simple trivial > has_const_param needs_implicit implicit_has_const_param > | | |-MoveConstructor exists simple trivial > needs_implicit > | | |-CopyAssignment trivial has_const_param > needs_implicit implicit_has_const_param > | | |-MoveAssignment > | | `-Destructor simple irrelevant trivial > | |-CXXMethodDecl 0x45593fda96c0 <col:4, > line:6:3> line:3:3 used constexpr operator() 'auto () const -> void' inline > | | `-CompoundStmt 0x45593fdce048 <col:6, > line:6:3> > | | `-ExprWithCleanups 0x45593fdce030 > <line:4:3, line:5:5> 'void':'void' > | | `-CXXOperatorCallExpr 0x45593fdce000 > <line:4:3, line:5:5> 'void':'void' '()' > | | |-ImplicitCastExpr 0x45593fda9f88 > <col:4, col:5> 'auto (*)() const -> void' <FunctionToPointerDecay> > | | | `-DeclRefExpr 0x45593fda9f08 <col:4, > col:5> 'auto () const -> void' lvalue CXXMethod 0x45593fda98f0 'operator()' > 'auto () const -> void' > | | `-ImplicitCastExpr 0x45593fda9fe0 > <line:4:3, line:5:3> 'const (lambda at /tmp/nested-lambdas.cc:4:3)' lvalue > <NoOp> > | | `-MaterializeTemporaryExpr > 0x45593fda9fc8 <line:4:3, line:5:3> '(lambda at > /tmp/nested-lambdas.cc:4:3)' lvalue > | | `-LambdaExpr 0x45593fda9dd0 > <line:4:3, line:5:3> '(lambda at /tmp/nested-lambdas.cc:4:3)' > | | |-CXXRecordDecl 0x45593fda97b8 > <line:4:3> col:3 implicit class definition > | | | |-DefinitionData lambda > pass_in_registers empty standard_layout trivially_copyable literal > can_const_default_init > | | | | |-DefaultConstructor > defaulted_is_constexpr > | | | | |-CopyConstructor simple > trivial has_const_param needs_implicit implicit_has_const_param > | | | | |-MoveConstructor exists > simple trivial needs_implicit > | | | | |-CopyAssignment trivial > has_const_param needs_implicit implicit_has_const_param > | | | | |-MoveAssignment > | | | | `-Destructor simple > irrelevant trivial > | | | |-CXXMethodDecl 0x45593fda98f0 > <col:4, line:5:3> line:4:3 used constexpr operator() 'auto () const -> > void' inline > | | | | `-CompoundStmt > 0x45593fda99a0 <col:6, line:5:3> > | | | |-CXXConversionDecl > 0x45593fda9c68 <line:4:3, line:5:3> line:4:3 implicit constexpr operator > void (*)() 'auto (*() const noexcept)() -> void' inline > | | | |-CXXMethodDecl 0x45593fda9d18 > <col:3, line:5:3> line:4:3 implicit __invoke 'auto () -> void' static inline > | | | `-CXXDestructorDecl > 0x45593fda9df8 <col:3> col:3 implicit referenced ~ 'void () noexcept' > inline default trivial > | | `-CompoundStmt 0x45593fda99a0 > <col:6, line:5:3> > | |-CXXConversionDecl 0x45593fdce188 <line:3:3, > line:6:3> line:3:3 implicit constexpr operator void (*)() 'auto (*() const > noexcept)() -> void' inline > | |-CXXMethodDecl 0x45593fdce238 <col:3, > line:6:3> line:3:3 implicit __invoke 'auto () -> void' static inline > | `-CXXDestructorDecl 0x45593fdce318 <col:3> > col:3 implicit referenced ~ 'void () noexcept' inline default trivial > `-CompoundStmt 0x45593fdce048 <col:6, line:6:3> > `-ExprWithCleanups 0x45593fdce030 <line:4:3, > line:5:5> 'void':'void' > `-CXXOperatorCallExpr 0x45593fdce000 > <line:4:3, line:5:5> 'void':'void' '()' > |-ImplicitCastExpr 0x45593fda9f88 <col:4, > col:5> 'auto (*)() const -> void' <FunctionToPointerDecay> > | `-DeclRefExpr 0x45593fda9f08 <col:4, > col:5> 'auto () const -> void' lvalue CXXMethod 0x45593fda98f0 'operator()' > 'auto () const -> void' > `-ImplicitCastExpr 0x45593fda9fe0 > <line:4:3, line:5:3> 'const (lambda at /tmp/nested-lambdas.cc:4:3)' lvalue > <NoOp> > `-MaterializeTemporaryExpr > 0x45593fda9fc8 <line:4:3, line:5:3> '(lambda at > /tmp/nested-lambdas.cc:4:3)' lvalue > `-LambdaExpr 0x45593fda9dd0 <line:4:3, > line:5:3> '(lambda at /tmp/nested-lambdas.cc:4:3)' > |-CXXRecordDecl 0x45593fda97b8 > <line:4:3> col:3 implicit class definition > | |-DefinitionData lambda > pass_in_registers empty standard_layout trivially_copyable literal > can_const_default_init > | | |-DefaultConstructor > defaulted_is_constexpr > | | |-CopyConstructor simple trivial > has_const_param needs_implicit implicit_has_const_param > | | |-MoveConstructor exists simple > trivial needs_implicit > | | |-CopyAssignment trivial > has_const_param needs_implicit implicit_has_const_param > | | |-MoveAssignment > | | `-Destructor simple irrelevant > trivial > | |-CXXMethodDecl 0x45593fda98f0 > <col:4, line:5:3> line:4:3 used constexpr operator() 'auto () const -> > void' inline > | | `-CompoundStmt 0x45593fda99a0 > <col:6, line:5:3> > | |-CXXConversionDecl 0x45593fda9c68 > <line:4:3, line:5:3> line:4:3 implicit constexpr operator void (*)() 'auto > (*() const noexcept)() -> void' inline > | |-CXXMethodDecl 0x45593fda9d18 > <col:3, line:5:3> line:4:3 implicit __invoke 'auto () -> void' static inline > | `-CXXDestructorDecl 0x45593fda9df8 > <col:3> col:3 implicit referenced ~ 'void () noexcept' inline default > trivial > `-CompoundStmt 0x45593fda99a0 > <col:6, line:5:3> > > > On Tue, Jan 5, 2021 at 3:45 PM Stephen Kelly via llvm-branch-commits < > llvm-branch-commits@lists.llvm.org> wrote: > >> >> Author: Stephen Kelly >> Date: 2021-01-05T14:39:46Z >> New Revision: c3a21e5de3dc3f55e4d219afd55dec518159d356 >> >> URL: >> https://github.com/llvm/llvm-project/commit/c3a21e5de3dc3f55e4d219afd55dec518159d356 >> DIFF: >> https://github.com/llvm/llvm-project/commit/c3a21e5de3dc3f55e4d219afd55dec518159d356.diff >> >> LOG: [ASTMatchers] Ensure that we can match inside lambdas >> >> Because we don't know in ASTMatchFinder whether we're matching in AsIs >> or IgnoreUnlessSpelledInSource mode, we need to traverse the lambda >> twice, but store whether we're matching in nodes spelled in source or >> not. >> >> Differential Revision: https://reviews.llvm.org/D93688 >> >> Added: >> >> >> Modified: >> clang/include/clang/ASTMatchers/ASTMatchersInternal.h >> clang/lib/ASTMatchers/ASTMatchFinder.cpp >> clang/lib/ASTMatchers/ASTMatchersInternal.cpp >> clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp >> >> Removed: >> >> >> >> >> ################################################################################ >> diff --git a/clang/include/clang/ASTMatchers/ASTMatchersInternal.h >> b/clang/include/clang/ASTMatchers/ASTMatchersInternal.h >> index 46de4093272d..f49728d1f50e 100644 >> --- a/clang/include/clang/ASTMatchers/ASTMatchersInternal.h >> +++ b/clang/include/clang/ASTMatchers/ASTMatchersInternal.h >> @@ -723,6 +723,8 @@ class ASTMatchFinder { >> >> virtual bool IsMatchingInASTNodeNotSpelledInSource() const = 0; >> >> + virtual bool IsMatchingInASTNodeNotAsIs() const = 0; >> + >> bool isTraversalIgnoringImplicitNodes() const; >> >> protected: >> >> diff --git a/clang/lib/ASTMatchers/ASTMatchFinder.cpp >> b/clang/lib/ASTMatchers/ASTMatchFinder.cpp >> index 762885fa0052..af21e2283d8b 100644 >> --- a/clang/lib/ASTMatchers/ASTMatchFinder.cpp >> +++ b/clang/lib/ASTMatchers/ASTMatchFinder.cpp >> @@ -475,6 +475,55 @@ class MatchASTVisitor : public >> RecursiveASTVisitor<MatchASTVisitor>, >> } >> } >> return true; >> + } else if (auto *LE = dyn_cast<LambdaExpr>(S)) { >> + for (auto I : llvm::zip(LE->captures(), LE->capture_inits())) { >> + auto C = std::get<0>(I); >> + ASTNodeNotSpelledInSourceScope RAII( >> + this, TraversingASTNodeNotSpelledInSource || >> !C.isExplicit()); >> + TraverseLambdaCapture(LE, &C, std::get<1>(I)); >> + } >> + >> + { >> + ASTNodeNotSpelledInSourceScope RAII(this, true); >> + TraverseDecl(LE->getLambdaClass()); >> > > The line above triggers an additional traversal of all nested lambdas, > leading to exponential time growth. > > + } >> + { >> + ASTNodeNotAsIsSourceScope RAII(this, true); >> + >> + // We need to poke around to find the bits that might be >> explicitly >> + // written. >> + TypeLoc TL = >> LE->getCallOperator()->getTypeSourceInfo()->getTypeLoc(); >> + FunctionProtoTypeLoc Proto = >> TL.getAsAdjusted<FunctionProtoTypeLoc>(); >> + >> + if (auto *TPL = LE->getTemplateParameterList()) { >> + for (NamedDecl *D : *TPL) { >> + TraverseDecl(D); >> + } >> + if (Expr *RequiresClause = TPL->getRequiresClause()) { >> + TraverseStmt(RequiresClause); >> + } >> + } >> + >> + if (LE->hasExplicitParameters()) { >> + // Visit parameters. >> + for (ParmVarDecl *Param : Proto.getParams()) >> + TraverseDecl(Param); >> + } >> + >> + const auto *T = Proto.getTypePtr(); >> + for (const auto &E : T->exceptions()) >> + TraverseType(E); >> + >> + if (Expr *NE = T->getNoexceptExpr()) >> + TraverseStmt(NE, Queue); >> + >> + if (LE->hasExplicitResultType()) >> + TraverseTypeLoc(Proto.getReturnLoc()); >> + TraverseStmt(LE->getTrailingRequiresClause()); >> + >> + TraverseStmt(LE->getBody()); >> + } >> + return true; >> } >> return RecursiveASTVisitor<MatchASTVisitor>::dataTraverseNode(S, >> Queue); >> } >> @@ -617,6 +666,9 @@ class MatchASTVisitor : public >> RecursiveASTVisitor<MatchASTVisitor>, >> bool IsMatchingInASTNodeNotSpelledInSource() const override { >> return TraversingASTNodeNotSpelledInSource; >> } >> + bool IsMatchingInASTNodeNotAsIs() const override { >> + return TraversingASTNodeNotAsIs; >> + } >> >> bool TraverseTemplateInstantiations(ClassTemplateDecl *D) { >> ASTNodeNotSpelledInSourceScope RAII(this, true); >> @@ -638,6 +690,7 @@ class MatchASTVisitor : public >> RecursiveASTVisitor<MatchASTVisitor>, >> >> private: >> bool TraversingASTNodeNotSpelledInSource = false; >> + bool TraversingASTNodeNotAsIs = false; >> bool TraversingASTChildrenNotSpelledInSource = false; >> >> struct ASTNodeNotSpelledInSourceScope { >> @@ -654,6 +707,18 @@ class MatchASTVisitor : public >> RecursiveASTVisitor<MatchASTVisitor>, >> bool MB; >> }; >> >> + struct ASTNodeNotAsIsSourceScope { >> + ASTNodeNotAsIsSourceScope(MatchASTVisitor *V, bool B) >> + : MV(V), MB(V->TraversingASTNodeNotAsIs) { >> + V->TraversingASTNodeNotAsIs = B; >> + } >> + ~ASTNodeNotAsIsSourceScope() { MV->TraversingASTNodeNotAsIs = MB; } >> + >> + private: >> + MatchASTVisitor *MV; >> + bool MB; >> + }; >> + >> struct ASTChildrenNotSpelledInSource { >> ASTChildrenNotSpelledInSource(MatchASTVisitor *V, bool B) >> : MV(V), MB(V->TraversingASTChildrenNotSpelledInSource) { >> >> diff --git a/clang/lib/ASTMatchers/ASTMatchersInternal.cpp >> b/clang/lib/ASTMatchers/ASTMatchersInternal.cpp >> index 3c19bceb079e..eb0fffcc3c37 100644 >> --- a/clang/lib/ASTMatchers/ASTMatchersInternal.cpp >> +++ b/clang/lib/ASTMatchers/ASTMatchersInternal.cpp >> @@ -293,6 +293,10 @@ bool DynTypedMatcher::matches(const DynTypedNode >> &DynNode, >> Finder->IsMatchingInASTNodeNotSpelledInSource()) >> return false; >> >> + if (!Finder->isTraversalIgnoringImplicitNodes() && >> + Finder->IsMatchingInASTNodeNotAsIs()) >> + return false; >> + >> auto N = >> >> Finder->getASTContext().getParentMapContext().traverseIgnored(DynNode); >> >> @@ -317,6 +321,10 @@ bool DynTypedMatcher::matchesNoKindCheck(const >> DynTypedNode &DynNode, >> Finder->IsMatchingInASTNodeNotSpelledInSource()) >> return false; >> >> + if (!Finder->isTraversalIgnoringImplicitNodes() && >> + Finder->IsMatchingInASTNodeNotAsIs()) >> + return false; >> + >> auto N = >> >> Finder->getASTContext().getParentMapContext().traverseIgnored(DynNode); >> >> >> diff --git a/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp >> b/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp >> index a3a3a911b85c..1dc5179ce857 100644 >> --- a/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp >> +++ b/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp >> @@ -3065,6 +3065,33 @@ void func14() { >> traverse(TK_IgnoreUnlessSpelledInSource, >> functionDecl(hasName("func14"), >> hasDescendant(floatLiteral()))), >> langCxx20OrLater())); >> + >> + Code = R"cpp( >> +void foo() { >> + int explicit_captured = 0; >> + int implicit_captured = 0; >> + auto l = [&, explicit_captured](int i) { >> + if (i || explicit_captured || implicit_captured) return; >> + }; >> +} >> +)cpp"; >> + >> + EXPECT_TRUE(matches(Code, traverse(TK_AsIs, ifStmt()))); >> + EXPECT_TRUE( >> + matches(Code, traverse(TK_IgnoreUnlessSpelledInSource, ifStmt()))); >> + >> + auto lambdaExplicitCapture = declRefExpr( >> + to(varDecl(hasName("explicit_captured"))), >> unless(hasAncestor(ifStmt()))); >> + auto lambdaImplicitCapture = declRefExpr( >> + to(varDecl(hasName("implicit_captured"))), >> unless(hasAncestor(ifStmt()))); >> + >> + EXPECT_TRUE(matches(Code, traverse(TK_AsIs, lambdaExplicitCapture))); >> + EXPECT_TRUE(matches( >> + Code, traverse(TK_IgnoreUnlessSpelledInSource, >> lambdaExplicitCapture))); >> + >> + EXPECT_TRUE(matches(Code, traverse(TK_AsIs, lambdaImplicitCapture))); >> + EXPECT_FALSE(matches( >> + Code, traverse(TK_IgnoreUnlessSpelledInSource, >> lambdaImplicitCapture))); >> } >> >> TEST(IgnoringImpCasts, MatchesImpCasts) { >> >> >> >> _______________________________________________ >> llvm-branch-commits mailing list >> llvm-branch-commits@lists.llvm.org >> https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits >> >
_______________________________________________ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits