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,27 @@ extern const internal::VariadicDynCastAllOfMatcher compoundLiteralExpr; +/// Matches co_await expression +/// +/// Example match: co_await 1 +/// \code +/// co_await 1; +/// \endcode +extern const internal::VariadicDynCastAllOfMatcher + coawaitExpr; +/// Matches dependent co_await expression while the type of the promise +/// is dependent +extern const internal::VariadicDynCastAllOfMatcher + dependendCoawaitExpr; +/// Matches co_yield expression +/// +/// Example match: co_yield 1 +/// \code +/// co_yield 1; +/// \endcode +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 + dependendCoawaitExpr; +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 @@ -171,6 +171,7 @@ REGISTER_MATCHER(constantExpr); REGISTER_MATCHER(containsDeclaration); REGISTER_MATCHER(continueStmt); + REGISTER_MATCHER(coreturnStmt); REGISTER_MATCHER(cudaKernelCallExpr); REGISTER_MATCHER(cxxBindTemporaryExpr); REGISTER_MATCHER(cxxBoolLiteral); @@ -191,6 +192,9 @@ REGISTER_MATCHER(cxxMemberCallExpr); REGISTER_MATCHER(cxxMethodDecl); REGISTER_MATCHER(cxxNewExpr); + REGISTER_MATCHER(coawaitExpr); + REGISTER_MATCHER(dependendCoawaitExpr); + REGISTER_MATCHER(coyieldExpr); REGISTER_MATCHER(cxxNoexceptExpr); REGISTER_MATCHER(cxxNullPtrLiteralExpr); REGISTER_MATCHER(cxxOperatorCallExpr); Index: clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp =================================================================== --- clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp +++ clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp @@ -510,6 +510,68 @@ varDecl(hasName("lPtrDecay")))))))); } +TEST(Matcher, MatchesCoroutine) { + StringRef Code = 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 +void check_match_co_await() { + co_await a; +} +void check_match_co_yield() { + co_yield 1.0; +} +void check_match_co_return() { + co_return 1; +} +)cpp"; + + EXPECT_TRUE(matches(Code, coawaitExpr(), Lang_CXX20)); + EXPECT_TRUE(matches(Code, coyieldExpr(), Lang_CXX20)); + EXPECT_TRUE(matches(Code, coreturnStmt(), Lang_CXX20)); +} + TEST(Matcher, isClassMessage) { EXPECT_TRUE(matchesObjC( "@interface NSString +(NSString *) stringWithFormat; @end "