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

Stephen Kelly via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Wed Jan 27 15:56:55 PST 2021


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 at lists.llvm.org 
> <mailto: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
>     <mailto: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/f773a177/attachment-0001.html>


More information about the llvm-branch-commits mailing list