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 <mailto: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
    <mailto: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

Reply via email to