diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -265,7 +265,7 @@ space before parentheses. The custom options can be set using ``SpaceBeforeParensOptions``. -- Improved Cpp20 Modules support. +- Improved C++20 Modules and Coroutines support. libclang -------- diff --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp --- a/clang/lib/Format/TokenAnnotator.cpp +++ b/clang/lib/Format/TokenAnnotator.cpp @@ -1004,6 +1004,8 @@ if (CurrentToken && CurrentToken->is(Keywords.kw_await)) next(); } + if (Style.isCpp() && CurrentToken && CurrentToken->is(tok::kw_co_await)) + next(); Contexts.back().ColonIsForRangeExpr = true; next(); if (!parseParens()) @@ -2952,6 +2954,14 @@ if (Left.is(tok::kw_auto) && Right.isOneOf(tok::l_paren, tok::l_brace)) return false; + // operator co_await(x) + if (Right.is(tok::l_paren) && Left.is(tok::kw_co_await) && Left.Previous && + Left.Previous->is(tok::kw_operator)) + return false; + // co_await (x), co_yield (x), co_return (x) + if (Left.isOneOf(tok::kw_co_await, tok::kw_co_yield, tok::kw_co_return) && + Right.isNot(tok::semi)) + return true; // requires clause Concept1 && Concept2 if (Left.is(TT_ConstraintJunctions) && Right.is(tok::identifier)) return true; diff --git a/clang/lib/Format/UnwrappedLineParser.cpp b/clang/lib/Format/UnwrappedLineParser.cpp --- a/clang/lib/Format/UnwrappedLineParser.cpp +++ b/clang/lib/Format/UnwrappedLineParser.cpp @@ -2399,6 +2399,8 @@ if (Style.Language == FormatStyle::LK_JavaScript && FormatTok->is(Keywords.kw_await)) nextToken(); + if (Style.isCpp() && FormatTok->is(tok::kw_co_await)) + nextToken(); if (FormatTok->Tok.is(tok::l_paren)) parseParens(); if (FormatTok->Tok.is(tok::l_brace)) { diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp --- a/clang/unittests/Format/FormatTest.cpp +++ b/clang/unittests/Format/FormatTest.cpp @@ -22724,6 +22724,65 @@ verifyFormat("export", Style); } +TEST_F(FormatTest, CoroutineForCoawait) { + FormatStyle Style = getLLVMStyle(); + verifyFormat("for co_await (auto x : range())\n ;"); + verifyFormat("for (auto i : arr) {\n" + "}", + Style); + verifyFormat("for co_await (auto i : arr) {\n" + "}", + Style); + verifyFormat("for co_await (auto i : foo(T{})) {\n" + "}", + Style); +} + +TEST_F(FormatTest, CoroutineCoAwait) { + verifyFormat("int x = co_await foo();"); + verifyFormat("int x = (co_await foo());"); + verifyFormat("co_await (42);"); + verifyFormat("void operator co_await(int);"); + verifyFormat("void operator co_await(a);"); + verifyFormat("co_await a;"); + verifyFormat("co_await missing_await_resume{};"); + verifyFormat("co_await a; // comment"); + verifyFormat("void test0() { co_await a; }"); + verifyFormat("co_await co_await co_await foo();"); + verifyFormat("co_await foo().bar();"); + verifyFormat("co_await [this]() -> Task { co_return x; }"); + verifyFormat("co_await [this](int a, int b) -> Task { co_return co_await " + "foo(); }(x, y);"); + + FormatStyle Style = getLLVMStyle(); + Style.ColumnLimit = 40; + verifyFormat("co_await [this](int a, int b) -> Task {\n" + " co_return co_await foo();\n" + "}(x, y);", + Style); + verifyFormat("co_await;"); +} + +TEST_F(FormatTest, CoroutineCoYield) { + verifyFormat("int x = co_yield foo();"); + verifyFormat("int x = (co_yield foo());"); + verifyFormat("co_yield (42);"); + verifyFormat("co_yield {42};"); + verifyFormat("co_yield 42;"); + verifyFormat("co_yield n++;"); + verifyFormat("co_yield ++n;"); + verifyFormat("co_yield;"); +} + +TEST_F(FormatTest, CoroutineCoReturn) { + verifyFormat("co_return (42);"); + verifyFormat("co_return;"); + verifyFormat("co_return {};"); + verifyFormat("co_return x;"); + verifyFormat("co_return co_await foo();"); + verifyFormat("co_return co_yield foo();"); +} + } // namespace } // namespace format } // namespace clang