forked from OSchip/llvm-project
[coroutines] Add serialization/deserialization of coroutines
Reviewers: rsmith Reviewed By: rsmith Subscribers: EricWF, cfe-commits Differential Revision: https://reviews.llvm.org/D35383 llvm-svn: 308996
This commit is contained in:
parent
864c953773
commit
f5ecb5e1b4
|
@ -317,6 +317,7 @@ class CoroutineBodyStmt final
|
|||
unsigned NumParams;
|
||||
|
||||
friend class ASTStmtReader;
|
||||
friend class ASTReader;
|
||||
friend TrailingObjects;
|
||||
|
||||
Stmt **getStoredStmts() { return getTrailingObjects<Stmt *>(); }
|
||||
|
@ -347,6 +348,8 @@ private:
|
|||
|
||||
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 @@ public:
|
|||
SubStmts[SubStmt::PromiseCall] = PromiseCall;
|
||||
}
|
||||
|
||||
CoreturnStmt(EmptyShell) : CoreturnStmt({}, {}, {}) {}
|
||||
|
||||
SourceLocation getKeywordLoc() const { return CoreturnLoc; }
|
||||
|
||||
/// \brief Retrieve the operand of the 'co_return' statement. Will be nullptr
|
||||
|
|
|
@ -1545,9 +1545,14 @@ namespace clang {
|
|||
|
||||
// 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
|
||||
|
|
|
@ -96,6 +96,20 @@ CoroutineBodyStmt *CoroutineBodyStmt::Create(
|
|||
return new (Mem) CoroutineBodyStmt(Args);
|
||||
}
|
||||
|
||||
CoroutineBodyStmt *CoroutineBodyStmt::Create(const ASTContext &C, EmptyShell,
|
||||
unsigned NumParams) {
|
||||
std::size_t Size = totalSizeToAlloc<Stmt *>(
|
||||
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<Stmt *>(nullptr));
|
||||
return Result;
|
||||
}
|
||||
|
||||
CoroutineBodyStmt::CoroutineBodyStmt(CoroutineBodyStmt::CtorArgs const &Args)
|
||||
: Stmt(CoroutineBodyStmtClass), NumParams(Args.ParamMoves.size()) {
|
||||
Stmt **SubStmts = getStoredStmts();
|
||||
|
|
|
@ -367,28 +367,45 @@ void ASTStmtReader::VisitMSAsmStmt(MSAsmStmt *S) {
|
|||
}
|
||||
|
||||
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<OpaqueValueExpr>(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<OpaqueValueExpr>(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 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) {
|
|||
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.
|
||||
|
|
|
@ -286,7 +286,7 @@ void ASTStmtWriter::VisitMSAsmStmt(MSAsmStmt *S) {
|
|||
}
|
||||
|
||||
// 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 @@ void ASTStmtWriter::VisitMSAsmStmt(MSAsmStmt *S) {
|
|||
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 *S) {
|
||||
// FIXME: Implement coroutine serialization.
|
||||
llvm_unreachable("unimplemented");
|
||||
void ASTStmtWriter::VisitCoyieldExpr(CoyieldExpr *E) {
|
||||
VisitCoroutineSuspendExpr(E);
|
||||
Code = serialization::EXPR_COYIELD;
|
||||
}
|
||||
|
||||
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) {
|
||||
|
|
|
@ -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 <typename... T> struct coroutine_traits;
|
||||
|
||||
template <class Promise = void> struct coroutine_handle {
|
||||
coroutine_handle() = default;
|
||||
static coroutine_handle from_address(void *) noexcept;
|
||||
};
|
||||
template <> struct coroutine_handle<void> {
|
||||
static coroutine_handle from_address(void *) noexcept;
|
||||
coroutine_handle() = default;
|
||||
template <class PromiseType>
|
||||
coroutine_handle(coroutine_handle<PromiseType>) noexcept;
|
||||
};
|
||||
}
|
||||
|
||||
struct suspend_always {
|
||||
bool await_ready() noexcept;
|
||||
void await_suspend(std::experimental::coroutine_handle<>) noexcept;
|
||||
void await_resume() noexcept;
|
||||
};
|
||||
|
||||
template <typename... Args> struct std::experimental::coroutine_traits<void, Args...> {
|
||||
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 <typename... Args> struct std::experimental::coroutine_traits<int, Args...> {
|
||||
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 <typename T>
|
||||
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 <typename T>
|
||||
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
|
Loading…
Reference in New Issue