summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHans Wennborg <hans@hanshq.net>2017-08-03 16:12:51 +0000
committerHans Wennborg <hans@hanshq.net>2017-08-03 16:12:51 +0000
commit676729f19a8b81c98a72239633feecdb54ed08cf (patch)
treec1070094979d4d1e3648dbba94cc59c6183b3d6d
parentc4d55f5857a1e3a7f41bc75914fd43da30ae6326 (diff)
Merging r308996:
------------------------------------------------------------------------ r308996 | gornishanov | 2017-07-25 11:01:49 -0700 (Tue, 25 Jul 2017) | 9 lines [coroutines] Add serialization/deserialization of coroutines Reviewers: rsmith Reviewed By: rsmith Subscribers: EricWF, cfe-commits Differential Revision: https://reviews.llvm.org/D35383 ------------------------------------------------------------------------ git-svn-id: https://llvm.org/svn/llvm-project/cfe/branches/release_50@309954 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--include/clang/AST/StmtCXX.h5
-rw-r--r--include/clang/Serialization/ASTBitCodes.h9
-rw-r--r--lib/AST/StmtCXX.cpp14
-rw-r--r--lib/Serialization/ASTReaderStmt.cpp66
-rw-r--r--lib/Serialization/ASTWriterStmt.cpp49
-rw-r--r--test/PCH/coroutines.cpp77
6 files changed, 190 insertions, 30 deletions
diff --git a/include/clang/AST/StmtCXX.h b/include/clang/AST/StmtCXX.h
index d6c9654fef..77f81838e5 100644
--- a/include/clang/AST/StmtCXX.h
+++ b/include/clang/AST/StmtCXX.h
@@ -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
diff --git a/include/clang/Serialization/ASTBitCodes.h b/include/clang/Serialization/ASTBitCodes.h
index 6b40781a12..9227b33d2c 100644
--- a/include/clang/Serialization/ASTBitCodes.h
+++ b/include/clang/Serialization/ASTBitCodes.h
@@ -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
diff --git a/lib/AST/StmtCXX.cpp b/lib/AST/StmtCXX.cpp
index 8466cd61f0..666f5dcc9d 100644
--- a/lib/AST/StmtCXX.cpp
+++ b/lib/AST/StmtCXX.cpp
@@ -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();
diff --git a/lib/Serialization/ASTReaderStmt.cpp b/lib/Serialization/ASTReaderStmt.cpp
index 21adcddd3a..3f5da02994 100644
--- a/lib/Serialization/ASTReaderStmt.cpp
+++ b/lib/Serialization/ASTReaderStmt.cpp
@@ -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) {
@@ -3947,6 +3964,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.
diff --git a/lib/Serialization/ASTWriterStmt.cpp b/lib/Serialization/ASTWriterStmt.cpp
index ae2e0b88c3..6971339663 100644
--- a/lib/Serialization/ASTWriterStmt.cpp
+++ b/lib/Serialization/ASTWriterStmt.cpp
@@ -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 *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) {
diff --git a/test/PCH/coroutines.cpp b/test/PCH/coroutines.cpp
new file mode 100644
index 0000000000..46a2872420
--- /dev/null
+++ b/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 <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