[llvm-branch-commits] [clang] c3a21e5 - [ASTMatchers] Ensure that we can match inside lambdas

Alexander Kornienko via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Wed Jan 27 14:58:52 PST 2021


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 at 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 at lists.llvm.org
> https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-branch-commits/attachments/20210127/350ffa5b/attachment-0001.html>


More information about the llvm-branch-commits mailing list