Index: clang/docs/LibASTMatchersReference.html =================================================================== --- clang/docs/LibASTMatchersReference.html +++ clang/docs/LibASTMatchersReference.html @@ -1331,6 +1331,16 @@ +Matcher<Stmt>coawaitExprMatcher<CoawaitExpr>... +
Matches co_await expressions.
+
+Given
+  co_await 1;
+coawaitExpr()
+  matches 'co_await 1'
+
+ + Matcher<Stmt>compoundLiteralExprMatcher<CompoundLiteralExpr>...
Matches compound (i.e. non-scalar) literals
 
@@ -1377,6 +1387,26 @@
 
+Matcher<Stmt>coreturnStmtMatcher<CoreturnStmt>... +
Matches co_return statements.
+
+Given
+  while (true) { co_return; }
+coreturnStmt()
+  matches 'co_return'
+
+ + +Matcher<Stmt>coyieldExprMatcher<CoyieldExpr>... +
Matches co_yield expressions.
+
+Given
+  co_yield 1;
+coyieldExpr()
+  matches 'co_yield 1'
+
+ + Matcher<Stmt>cudaKernelCallExprMatcher<CUDAKernelCallExpr>...
Matches CUDA kernel call expression.
 
@@ -1692,6 +1722,11 @@
 
+Matcher<Stmt>dependentCoawaitExprMatcher<DependentCoawaitExpr>... +
Matches co_await expressions where the type of the promise is dependent
+
+ + Matcher<Stmt>designatedInitExprMatcher<DesignatedInitExpr>...
Matches C99 designated initializer expressions [C99 6.7.8].
 
@@ -7146,7 +7181,8 @@
     f = 42;
 }
 The matcher:
-  decompositionDecl(hasBinding(0, bindingDecl(hasName("f").bind("fBinding"))))
+  decompositionDecl(hasBinding(0,
+  bindingDecl(hasName("f").bind("fBinding"))))
 matches the decomposition decl with 'f' bound to "fBinding".
 
Index: clang/include/clang/ASTMatchers/ASTMatchers.h =================================================================== --- clang/include/clang/ASTMatchers/ASTMatchers.h +++ clang/include/clang/ASTMatchers/ASTMatchers.h @@ -2172,6 +2172,17 @@ extern const internal::VariadicDynCastAllOfMatcher continueStmt; +/// Matches co_return statements. +/// +/// Given +/// \code +/// while (true) { co_return; } +/// \endcode +/// coreturnStmt() +/// matches 'co_return' +extern const internal::VariadicDynCastAllOfMatcher + coreturnStmt; + /// Matches return statements. /// /// Given @@ -2389,6 +2400,30 @@ extern const internal::VariadicDynCastAllOfMatcher compoundLiteralExpr; +/// Matches co_await expressions. +/// +/// Given +/// \code +/// co_await 1; +/// \endcode +/// coawaitExpr() +/// matches 'co_await 1' +extern const internal::VariadicDynCastAllOfMatcher + coawaitExpr; +/// Matches co_await expressions where the type of the promise is dependent +extern const internal::VariadicDynCastAllOfMatcher + dependentCoawaitExpr; +/// Matches co_yield expressions. +/// +/// Given +/// \code +/// co_yield 1; +/// \endcode +/// coyieldExpr() +/// matches 'co_yield 1' +extern const internal::VariadicDynCastAllOfMatcher + coyieldExpr; + /// Matches nullptr literal. extern const internal::VariadicDynCastAllOfMatcher cxxNullPtrLiteralExpr; Index: clang/lib/ASTMatchers/ASTMatchersInternal.cpp =================================================================== --- clang/lib/ASTMatchers/ASTMatchersInternal.cpp +++ clang/lib/ASTMatchers/ASTMatchersInternal.cpp @@ -883,6 +883,7 @@ const internal::VariadicDynCastAllOfMatcher doStmt; const internal::VariadicDynCastAllOfMatcher breakStmt; const internal::VariadicDynCastAllOfMatcher continueStmt; +const internal::VariadicDynCastAllOfMatcher coreturnStmt; const internal::VariadicDynCastAllOfMatcher returnStmt; const internal::VariadicDynCastAllOfMatcher gotoStmt; const internal::VariadicDynCastAllOfMatcher labelStmt; @@ -915,6 +916,12 @@ const internal::VariadicDynCastAllOfMatcher cxxNullPtrLiteralExpr; const internal::VariadicDynCastAllOfMatcher chooseExpr; +const internal::VariadicDynCastAllOfMatcher + coawaitExpr; +const internal::VariadicDynCastAllOfMatcher + dependentCoawaitExpr; +const internal::VariadicDynCastAllOfMatcher + coyieldExpr; const internal::VariadicDynCastAllOfMatcher gnuNullExpr; const internal::VariadicDynCastAllOfMatcher genericSelectionExpr; Index: clang/lib/ASTMatchers/Dynamic/Registry.cpp =================================================================== --- clang/lib/ASTMatchers/Dynamic/Registry.cpp +++ clang/lib/ASTMatchers/Dynamic/Registry.cpp @@ -166,11 +166,14 @@ REGISTER_MATCHER(complexType); REGISTER_MATCHER(compoundLiteralExpr); REGISTER_MATCHER(compoundStmt); + REGISTER_MATCHER(coawaitExpr); REGISTER_MATCHER(conditionalOperator); REGISTER_MATCHER(constantArrayType); REGISTER_MATCHER(constantExpr); REGISTER_MATCHER(containsDeclaration); REGISTER_MATCHER(continueStmt); + REGISTER_MATCHER(coreturnStmt); + REGISTER_MATCHER(coyieldExpr); REGISTER_MATCHER(cudaKernelCallExpr); REGISTER_MATCHER(cxxBindTemporaryExpr); REGISTER_MATCHER(cxxBoolLiteral); @@ -214,6 +217,7 @@ REGISTER_MATCHER(decltypeType); REGISTER_MATCHER(deducedTemplateSpecializationType); REGISTER_MATCHER(defaultStmt); + REGISTER_MATCHER(dependentCoawaitExpr); REGISTER_MATCHER(dependentSizedArrayType); REGISTER_MATCHER(designatedInitExpr); REGISTER_MATCHER(designatorCountIs); Index: clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp =================================================================== --- clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp +++ clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp @@ -510,6 +510,83 @@ varDecl(hasName("lPtrDecay")))))))); } +TEST(Matcher, MatchesCoroutine) { + FileContentMappings M; + M.push_back(std::make_pair("/coro_header", R"cpp( +namespace std { +namespace experimental { + +template +struct void_t_imp { + using type = void; +}; +template +using void_t = typename void_t_imp::type; + +template +struct traits_sfinae_base {}; + +template +struct traits_sfinae_base> { + using promise_type = typename T::promise_type; +}; + +template +struct coroutine_traits : public traits_sfinae_base {}; +}} // namespace std::experimental +struct awaitable { + bool await_ready() noexcept; + template + void await_suspend(F) noexcept; + void await_resume() noexcept; +} a; +struct promise { + void get_return_object(); + awaitable initial_suspend(); + awaitable final_suspend() noexcept; + awaitable yield_value(int); // expected-note 2{{candidate}} + void return_value(int); // expected-note 2{{here}} + void unhandled_exception(); +}; +template +struct std::experimental::coroutine_traits { using promise_type = promise; }; +namespace std { +namespace experimental { +template +struct coroutine_handle { + static coroutine_handle from_address(void *) noexcept; +}; +}} // namespace std::experimental +)cpp")); + StringRef CoReturnCode = R"cpp( +#include +void check_match_co_return() { + co_return 1; +} +)cpp"; + EXPECT_TRUE(matchesConditionally(CoReturnCode, + coreturnStmt(isExpansionInMainFile()), + true, {"-std=c++20", "-I/"}, M)); + StringRef CoAwaitCode = R"cpp( +#include +void check_match_co_await() { + co_await a; +} +)cpp"; + EXPECT_TRUE(matchesConditionally(CoAwaitCode, + coawaitExpr(isExpansionInMainFile()), + true, {"-std=c++20", "-I/"}, M)); + StringRef CoYieldCode = R"cpp( +#include +void check_match_co_yield() { + co_yield 1.0; +} +)cpp"; + EXPECT_TRUE(matchesConditionally(CoYieldCode, + coyieldExpr(isExpansionInMainFile()), + true, {"-std=c++20", "-I/"}, M)); +} + TEST(Matcher, isClassMessage) { EXPECT_TRUE(matchesObjC( "@interface NSString +(NSString *) stringWithFormat; @end "