summaryrefslogtreecommitdiff
path: root/test/CodeGenCoroutines
diff options
context:
space:
mode:
authorGor Nishanov <GorNishanov@gmail.com>2017-05-24 02:38:26 +0000
committerGor Nishanov <GorNishanov@gmail.com>2017-05-24 02:38:26 +0000
commiteb4bbc485efa53f413a482ea7240c4b9918713c3 (patch)
tree6942e7ee0b33bec937ce15eca77238f603aaa1bb /test/CodeGenCoroutines
parent7bd1253c5a47c7344c6f8349f9d19b634e6091b4 (diff)
[coroutines] Implement correct GRO lifetime
Summary: Sema creates a declaration for gro variable as: auto $gro = $promise.get_return_object(); However, gro variable has to outlive coroutine frame and coroutine promise, but, it can only be initialized after the coroutine promise was created, thus, we split its emission in two parts: EmitGroAlloca emits an alloca and sets up the cleanups. Later when the coroutine promise is available we initialize the gro and set the flag that the cleanup is now active. Duplicate of: https://reviews.llvm.org/D31670 (which arc patch refuses to apply for some reason) Reviewers: GorNishanov, rsmith Reviewed By: GorNishanov Subscribers: EricWF, cfe-commits Differential Revision: https://reviews.llvm.org/D33477 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@303716 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'test/CodeGenCoroutines')
-rw-r--r--test/CodeGenCoroutines/coro-gro.cpp86
1 files changed, 86 insertions, 0 deletions
diff --git a/test/CodeGenCoroutines/coro-gro.cpp b/test/CodeGenCoroutines/coro-gro.cpp
new file mode 100644
index 0000000000..95bf206972
--- /dev/null
+++ b/test/CodeGenCoroutines/coro-gro.cpp
@@ -0,0 +1,86 @@
+// Verifies lifetime of __gro local variable
+// Verify that coroutine promise and allocated memory are freed up on exception.
+// RUN: %clang_cc1 -std=c++1z -fcoroutines-ts -triple=x86_64-unknown-linux-gnu -emit-llvm -o - %s -disable-llvm-passes | FileCheck %s
+
+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;
+};
+
+struct GroType {
+ ~GroType();
+ operator int() noexcept;
+};
+
+template <> struct std::experimental::coroutine_traits<int> {
+ struct promise_type {
+ GroType get_return_object() noexcept;
+ suspend_always initial_suspend() noexcept;
+ suspend_always final_suspend() noexcept;
+ void return_void() noexcept;
+ promise_type();
+ ~promise_type();
+ void unhandled_exception() noexcept;
+ };
+};
+
+struct Cleanup { ~Cleanup(); };
+void doSomething() noexcept;
+
+// CHECK: define i32 @_Z1fv(
+int f() {
+ // CHECK: %[[RetVal:.+]] = alloca i32
+ // CHECK: %[[GroActive:.+]] = alloca i1
+
+ // CHECK: %[[Size:.+]] = call i64 @llvm.coro.size.i64()
+ // CHECK: call i8* @_Znwm(i64 %[[Size]])
+ // CHECK: store i1 false, i1* %[[GroActive]]
+ // CHECK: call void @_ZNSt12experimental16coroutine_traitsIJiEE12promise_typeC1Ev(
+ // CHECK: call void @_ZNSt12experimental16coroutine_traitsIJiEE12promise_type17get_return_objectEv(
+ // CHECK: store i1 true, i1* %[[GroActive]]
+
+ Cleanup cleanup;
+ doSomething();
+ co_return;
+
+ // CHECK: call void @_Z11doSomethingv(
+ // CHECK: call void @_ZNSt12experimental16coroutine_traitsIJiEE12promise_type11return_voidEv(
+ // CHECK: call void @_ZN7CleanupD1Ev(
+
+ // Destroy promise and free the memory.
+
+ // CHECK: call void @_ZNSt12experimental16coroutine_traitsIJiEE12promise_typeD1Ev(
+ // CHECK: %[[Mem:.+]] = call i8* @llvm.coro.free(
+ // CHECK: call void @_ZdlPv(i8* %[[Mem]])
+
+ // Initialize retval from Gro and destroy Gro
+
+ // CHECK: %[[Conv:.+]] = call i32 @_ZN7GroTypecviEv(
+ // CHECK: store i32 %[[Conv]], i32* %[[RetVal]]
+ // CHECK: %[[IsActive:.+]] = load i1, i1* %[[GroActive]]
+ // CHECK: br i1 %[[IsActive]], label %[[CleanupGro:.+]], label %[[Done:.+]]
+
+ // CHECK: [[CleanupGro]]:
+ // CHECK: call void @_ZN7GroTypeD1Ev(
+ // CHECK: br label %[[Done]]
+
+ // CHECK: [[Done]]:
+ // CHECK: %[[LoadRet:.+]] = load i32, i32* %[[RetVal]]
+ // CHECK: ret i32 %[[LoadRet]]
+}