Index: cfe/trunk/include/clang/AST/StmtCXX.h =================================================================== --- cfe/trunk/include/clang/AST/StmtCXX.h +++ cfe/trunk/include/clang/AST/StmtCXX.h @@ -317,6 +317,7 @@ unsigned NumParams; friend class ASTStmtReader; + friend class ASTReader; friend TrailingObjects; Stmt **getStoredStmts() { return getTrailingObjects(); } @@ -347,6 +348,8 @@ public: static CoroutineBodyStmt *Create(const ASTContext &C, CtorArgs const &Args); + static CoroutineBodyStmt *Create(const ASTContext &C, EmptyShell, + unsigned NumParams); bool hasDependentPromiseType() const { return getPromiseDecl()->getType()->isDependentType(); @@ -444,6 +447,8 @@ SubStmts[SubStmt::PromiseCall] = PromiseCall; } + CoreturnStmt(EmptyShell) : CoreturnStmt({}, {}, {}) {} + SourceLocation getKeywordLoc() const { return CoreturnLoc; } /// \brief Retrieve the operand of the 'co_return' statement. Will be nullptr Index: cfe/trunk/include/clang/Serialization/ASTBitCodes.h =================================================================== --- cfe/trunk/include/clang/Serialization/ASTBitCodes.h +++ cfe/trunk/include/clang/Serialization/ASTBitCodes.h @@ -1545,9 +1545,14 @@ // ARC EXPR_OBJC_BRIDGED_CAST, // ObjCBridgedCastExpr - + STMT_MS_DEPENDENT_EXISTS, // MSDependentExistsStmt - EXPR_LAMBDA // LambdaExpr + EXPR_LAMBDA, // LambdaExpr + STMT_COROUTINE_BODY, + STMT_CORETURN, + EXPR_COAWAIT, + EXPR_COYIELD, + EXPR_DEPENDENT_COAWAIT, }; /// \brief The kinds of designators that can occur in a Index: cfe/trunk/lib/AST/StmtCXX.cpp =================================================================== --- cfe/trunk/lib/AST/StmtCXX.cpp +++ cfe/trunk/lib/AST/StmtCXX.cpp @@ -96,6 +96,20 @@ return new (Mem) CoroutineBodyStmt(Args); } +CoroutineBodyStmt *CoroutineBodyStmt::Create(const ASTContext &C, EmptyShell, + unsigned NumParams) { + std::size_t Size = totalSizeToAlloc( + CoroutineBodyStmt::FirstParamMove + NumParams); + + void *Mem = C.Allocate(Size, alignof(CoroutineBodyStmt)); + auto *Result = new (Mem) CoroutineBodyStmt(CtorArgs()); + Result->NumParams = NumParams; + auto *ParamBegin = Result->getStoredStmts() + SubStmt::FirstParamMove; + std::uninitialized_fill(ParamBegin, ParamBegin + NumParams, + static_cast(nullptr)); + return Result; +} + CoroutineBodyStmt::CoroutineBodyStmt(CoroutineBodyStmt::CtorArgs const &Args) : Stmt(CoroutineBodyStmtClass), NumParams(Args.ParamMoves.size()) { Stmt **SubStmts = getStoredStmts(); Index: cfe/trunk/lib/Serialization/ASTReaderStmt.cpp =================================================================== --- cfe/trunk/lib/Serialization/ASTReaderStmt.cpp +++ cfe/trunk/lib/Serialization/ASTReaderStmt.cpp @@ -367,28 +367,45 @@ } void ASTStmtReader::VisitCoroutineBodyStmt(CoroutineBodyStmt *S) { - // FIXME: Implement coroutine serialization. - llvm_unreachable("unimplemented"); + VisitStmt(S); + assert(Record.peekInt() == S->NumParams); + Record.skipInts(1); + auto *StoredStmts = S->getStoredStmts(); + for (unsigned i = 0; + i < CoroutineBodyStmt::SubStmt::FirstParamMove + S->NumParams; ++i) + StoredStmts[i] = Record.readSubStmt(); } void ASTStmtReader::VisitCoreturnStmt(CoreturnStmt *S) { - // FIXME: Implement coroutine serialization. - llvm_unreachable("unimplemented"); + VisitStmt(S); + S->CoreturnLoc = Record.readSourceLocation(); + for (auto &SubStmt: S->SubStmts) + SubStmt = Record.readSubStmt(); + S->IsImplicit = Record.readInt() != 0; } -void ASTStmtReader::VisitCoawaitExpr(CoawaitExpr *S) { - // FIXME: Implement coroutine serialization. - llvm_unreachable("unimplemented"); +void ASTStmtReader::VisitCoawaitExpr(CoawaitExpr *E) { + VisitExpr(E); + E->KeywordLoc = ReadSourceLocation(); + for (auto &SubExpr: E->SubExprs) + SubExpr = Record.readSubStmt(); + E->OpaqueValue = cast_or_null(Record.readSubStmt()); + E->setIsImplicit(Record.readInt() != 0); } -void ASTStmtReader::VisitDependentCoawaitExpr(DependentCoawaitExpr *S) { - // FIXME: Implement coroutine serialization. - llvm_unreachable("unimplemented"); +void ASTStmtReader::VisitCoyieldExpr(CoyieldExpr *E) { + VisitExpr(E); + E->KeywordLoc = ReadSourceLocation(); + for (auto &SubExpr: E->SubExprs) + SubExpr = Record.readSubStmt(); + E->OpaqueValue = cast_or_null(Record.readSubStmt()); } -void ASTStmtReader::VisitCoyieldExpr(CoyieldExpr *S) { - // FIXME: Implement coroutine serialization. - llvm_unreachable("unimplemented"); +void ASTStmtReader::VisitDependentCoawaitExpr(DependentCoawaitExpr *E) { + VisitExpr(E); + E->KeywordLoc = ReadSourceLocation(); + for (auto &SubExpr: E->SubExprs) + SubExpr = Record.readSubStmt(); } void ASTStmtReader::VisitCapturedStmt(CapturedStmt *S) { @@ -3985,6 +4002,29 @@ S = LambdaExpr::CreateDeserialized(Context, NumCaptures); break; } + + case STMT_COROUTINE_BODY: { + unsigned NumParams = Record[ASTStmtReader::NumStmtFields]; + S = CoroutineBodyStmt::Create(Context, Empty, NumParams); + break; + } + + case STMT_CORETURN: + S = new (Context) CoreturnStmt(Empty); + break; + + case EXPR_COAWAIT: + S = new (Context) CoawaitExpr(Empty); + break; + + case EXPR_COYIELD: + S = new (Context) CoyieldExpr(Empty); + break; + + case EXPR_DEPENDENT_COAWAIT: + S = new (Context) DependentCoawaitExpr(Empty); + break; + } // We hit a STMT_STOP, so we're done with this expression. Index: cfe/trunk/lib/Serialization/ASTWriterStmt.cpp =================================================================== --- cfe/trunk/lib/Serialization/ASTWriterStmt.cpp +++ cfe/trunk/lib/Serialization/ASTWriterStmt.cpp @@ -286,7 +286,7 @@ } // Outputs - for (unsigned I = 0, N = S->getNumOutputs(); I != N; ++I) { + for (unsigned I = 0, N = S->getNumOutputs(); I != N; ++I) { Record.AddStmt(S->getOutputExpr(I)); Record.AddString(S->getOutputConstraint(I)); } @@ -300,29 +300,48 @@ Code = serialization::STMT_MSASM; } -void ASTStmtWriter::VisitCoroutineBodyStmt(CoroutineBodyStmt *S) { - // FIXME: Implement coroutine serialization. - llvm_unreachable("unimplemented"); +void ASTStmtWriter::VisitCoroutineBodyStmt(CoroutineBodyStmt *CoroStmt) { + VisitStmt(CoroStmt); + Record.push_back(CoroStmt->getParamMoves().size()); + for (Stmt *S : CoroStmt->children()) + Record.AddStmt(S); + Code = serialization::STMT_COROUTINE_BODY; } void ASTStmtWriter::VisitCoreturnStmt(CoreturnStmt *S) { - // FIXME: Implement coroutine serialization. - llvm_unreachable("unimplemented"); + VisitStmt(S); + Record.AddSourceLocation(S->getKeywordLoc()); + Record.AddStmt(S->getOperand()); + Record.AddStmt(S->getPromiseCall()); + Record.push_back(S->isImplicit()); + Code = serialization::STMT_CORETURN; } -void ASTStmtWriter::VisitCoawaitExpr(CoawaitExpr *S) { - // FIXME: Implement coroutine serialization. - llvm_unreachable("unimplemented"); +void ASTStmtWriter::VisitCoroutineSuspendExpr(CoroutineSuspendExpr *E) { + VisitExpr(E); + Record.AddSourceLocation(E->getKeywordLoc()); + for (Stmt *S : E->children()) + Record.AddStmt(S); + Record.AddStmt(E->getOpaqueValue()); } -void ASTStmtWriter::VisitDependentCoawaitExpr(DependentCoawaitExpr *S) { - // FIXME: Implement coroutine serialization. - llvm_unreachable("unimplemented"); +void ASTStmtWriter::VisitCoawaitExpr(CoawaitExpr *E) { + VisitCoroutineSuspendExpr(E); + Record.push_back(E->isImplicit()); + Code = serialization::EXPR_COAWAIT; +} + +void ASTStmtWriter::VisitCoyieldExpr(CoyieldExpr *E) { + VisitCoroutineSuspendExpr(E); + Code = serialization::EXPR_COYIELD; } -void ASTStmtWriter::VisitCoyieldExpr(CoyieldExpr *S) { - // FIXME: Implement coroutine serialization. - llvm_unreachable("unimplemented"); +void ASTStmtWriter::VisitDependentCoawaitExpr(DependentCoawaitExpr *E) { + VisitExpr(E); + Record.AddSourceLocation(E->getKeywordLoc()); + for (Stmt *S : E->children()) + Record.AddStmt(S); + Code = serialization::EXPR_DEPENDENT_COAWAIT; } void ASTStmtWriter::VisitCapturedStmt(CapturedStmt *S) { Index: cfe/trunk/test/PCH/coroutines.cpp =================================================================== --- cfe/trunk/test/PCH/coroutines.cpp +++ cfe/trunk/test/PCH/coroutines.cpp @@ -0,0 +1,77 @@ +// Test this without pch. +// RUN: %clang_cc1 -include %s -verify -std=c++1z -fcoroutines-ts %s + +// Test with pch. +// RUN: %clang_cc1 -std=c++1z -fcoroutines-ts -emit-pch -o %t %s +// RUN: %clang_cc1 -include-pch %t -verify -std=c++1z -fcoroutines-ts %s + +#ifndef HEADER +#define HEADER + +namespace std::experimental { +template struct coroutine_traits; + +template struct coroutine_handle { + coroutine_handle() = default; + static coroutine_handle from_address(void *) noexcept; +}; +template <> struct coroutine_handle { + static coroutine_handle from_address(void *) noexcept; + coroutine_handle() = default; + template + coroutine_handle(coroutine_handle) noexcept; +}; +} + +struct suspend_always { + bool await_ready() noexcept; + void await_suspend(std::experimental::coroutine_handle<>) noexcept; + void await_resume() noexcept; +}; + +template struct std::experimental::coroutine_traits { + struct promise_type { + void get_return_object() noexcept; + suspend_always initial_suspend() noexcept; + suspend_always final_suspend() noexcept; + void return_void() noexcept; + suspend_always yield_value(int) noexcept; + promise_type(); + ~promise_type() noexcept; + void unhandled_exception() noexcept; + }; +}; + +template struct std::experimental::coroutine_traits { + struct promise_type { + int get_return_object() noexcept; + suspend_always initial_suspend() noexcept; + suspend_always final_suspend() noexcept; + void return_value(int) noexcept; + promise_type(); + ~promise_type() noexcept; + void unhandled_exception() noexcept; + }; +}; + +template +void f(T x) { // checks coawait_expr and coroutine_body_stmt + co_yield 42; // checks coyield_expr + co_await x; // checks dependent_coawait + co_return; // checks coreturn_stmt +} + +template +int f2(T x) { // checks coawait_expr and coroutine_body_stmt + co_return x; // checks coreturn_stmt with expr +} + +#else + +// expected-no-diagnostics +void g() { + f(suspend_always{}); + f2(42); +} + +#endif