[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