[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