Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[coroutines] [NFC] Add tests for return_void, unhandled_exception and…
… promise dtor Summary: * Test that coroutine promise destructor is called. * Test that we call return_void on fallthrough * Test that we call unhandled exception in a try catch surrounding the body Reviewers: EricWF, GorNishanov Reviewed By: GorNishanov Subscribers: cfe-commits Differential Revision: https://reviews.llvm.org/D33479 llvm-svn: 303748
- Loading branch information
1 parent
183863f
commit ab7e8ae
Showing
4 changed files
with
238 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
#pragma once | ||
|
||
namespace std { namespace experimental { inline namespace coroutines_v1 { | ||
|
||
template <typename R, typename...> struct coroutine_traits { | ||
using promise_type = typename R::promise_type; | ||
}; | ||
|
||
template <typename Promise = void> struct coroutine_handle; | ||
|
||
template <> struct coroutine_handle<void> { | ||
static coroutine_handle from_address(void *addr) noexcept { | ||
coroutine_handle me; | ||
me.ptr = addr; | ||
return me; | ||
} | ||
void operator()() { resume(); } | ||
void *address() const { return ptr; } | ||
void resume() const { __builtin_coro_resume(ptr); } | ||
void destroy() const { __builtin_coro_destroy(ptr); } | ||
bool done() const { return __builtin_coro_done(ptr); } | ||
coroutine_handle &operator=(decltype(nullptr)) { | ||
ptr = nullptr; | ||
return *this; | ||
} | ||
coroutine_handle(decltype(nullptr)) : ptr(nullptr) {} | ||
coroutine_handle() : ptr(nullptr) {} | ||
// void reset() { ptr = nullptr; } // add to P0057? | ||
explicit operator bool() const { return ptr; } | ||
|
||
protected: | ||
void *ptr; | ||
}; | ||
|
||
template <typename Promise> struct coroutine_handle : coroutine_handle<> { | ||
using coroutine_handle<>::operator=; | ||
|
||
static coroutine_handle from_address(void *addr) noexcept { | ||
coroutine_handle me; | ||
me.ptr = addr; | ||
return me; | ||
} | ||
|
||
Promise &promise() const { | ||
return *reinterpret_cast<Promise *>( | ||
__builtin_coro_promise(ptr, alignof(Promise), false)); | ||
} | ||
static coroutine_handle from_promise(Promise &promise) { | ||
coroutine_handle p; | ||
p.ptr = __builtin_coro_promise(&promise, alignof(Promise), true); | ||
return p; | ||
} | ||
}; | ||
|
||
template <typename _PromiseT> | ||
bool operator==(coroutine_handle<_PromiseT> const& _Left, | ||
coroutine_handle<_PromiseT> const& _Right) noexcept | ||
{ | ||
return _Left.address() == _Right.address(); | ||
} | ||
|
||
template <typename _PromiseT> | ||
bool operator!=(coroutine_handle<_PromiseT> const& _Left, | ||
coroutine_handle<_PromiseT> const& _Right) noexcept | ||
{ | ||
return !(_Left == _Right); | ||
} | ||
|
||
struct suspend_always { | ||
bool await_ready() { return false; } | ||
void await_suspend(coroutine_handle<>) {} | ||
void await_resume() {} | ||
}; | ||
struct suspend_never { | ||
bool await_ready() { return true; } | ||
void await_suspend(coroutine_handle<>) {} | ||
void await_resume() {} | ||
}; | ||
|
||
}}} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
// RUN: %clang_cc1 -std=c++14 -fcoroutines-ts -triple=x86_64-pc-windows-msvc18.0.0 -emit-llvm -o - %s -fexceptions -fcxx-exceptions -disable-llvm-passes | FileCheck %s | ||
// -triple=x86_64-unknown-linux-gnu | ||
|
||
#include "Inputs/coroutine.h" | ||
|
||
namespace coro = std::experimental::coroutines_v1; | ||
|
||
struct coro_t { | ||
void* p; | ||
~coro_t(); | ||
struct promise_type { | ||
coro_t get_return_object(); | ||
coro::suspend_never initial_suspend(); | ||
coro::suspend_never final_suspend(); | ||
void return_void(); | ||
promise_type(); | ||
~promise_type(); | ||
void unhandled_exception(); | ||
}; | ||
}; | ||
|
||
struct Cleanup { ~Cleanup(); }; | ||
void may_throw(); | ||
|
||
coro_t f() { | ||
Cleanup cleanup; | ||
may_throw(); | ||
co_return; | ||
} | ||
|
||
// CHECK-LABEL: define void @"\01?f@@YA?AUcoro_t@@XZ"( | ||
// CHECK: %gro.active = alloca i1 | ||
// CHECK: store i1 false, i1* %gro.active | ||
|
||
// CHECK: invoke %"struct.coro_t::promise_type"* @"\01??0promise_type@coro_t@@QEAA@XZ"( | ||
// CHECK: invoke void @"\01?get_return_object@promise_type@coro_t@@QEAA?AU2@XZ"( | ||
// CHECK: store i1 true, i1* %gro.active | ||
|
||
// CHECK: %[[IS_ACTIVE:.+]] = load i1, i1* %gro.active | ||
// CHECK: br i1 %[[IS_ACTIVE]], label %[[CLEANUP1:.+]], label | ||
|
||
// CHECK: [[CLEANUP1]]: | ||
// CHECK: %[[NRVO:.+]] = load i1, i1* %nrvo | ||
// CHECK: br i1 %[[NRVO]], label %{{.+}}, label %[[DTOR:.+]] | ||
|
||
// CHECK: [[DTOR]]: | ||
// CHECK: call void @"\01??_Dcoro_t@@QEAAXXZ"( |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
// RUN: %clang_cc1 -std=c++14 -fcoroutines-ts -triple=x86_64-unknown-linux-gnu -emit-llvm %s -o - -disable-llvm-passes | FileCheck %s | ||
|
||
#include "Inputs/coroutine.h" | ||
|
||
namespace coro = std::experimental::coroutines_v1; | ||
|
||
struct coro1 { | ||
struct promise_type { | ||
coro1 get_return_object(); | ||
coro::suspend_never initial_suspend(); | ||
coro::suspend_never final_suspend(); | ||
void return_void(); | ||
}; | ||
}; | ||
|
||
coro1 f() { | ||
co_await coro::suspend_never{}; | ||
} | ||
|
||
// CHECK-LABEL: define void @_Z1fv( | ||
// CHECK: call void @_ZNSt12experimental13coroutines_v113suspend_never12await_resumeEv(%"struct.std::experimental::coroutines_v1::suspend_never"* | ||
// CHECK: call void @_ZN5coro112promise_type11return_voidEv(%"struct.coro1::promise_type"* %__promise) | ||
|
||
struct coro2 { | ||
struct promise_type { | ||
coro2 get_return_object(); | ||
coro::suspend_never initial_suspend(); | ||
coro::suspend_never final_suspend(); | ||
void return_value(int); | ||
}; | ||
}; | ||
|
||
coro2 g() { | ||
co_return 42; | ||
} | ||
|
||
// CHECK-LABEL: define void @_Z1gv( | ||
// CHECK: call void @_ZNSt12experimental13coroutines_v113suspend_never12await_resumeEv(%"struct.std::experimental::coroutines_v1::suspend_never"* | ||
// CHECK: call void @_ZN5coro212promise_type12return_valueEi(%"struct.coro2::promise_type"* %__promise, i32 42) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
// RUN: %clang_cc1 -std=c++14 -fcoroutines-ts -triple=x86_64-pc-windows-msvc18.0.0 -emit-llvm %s -o - -fexceptions -fcxx-exceptions -disable-llvm-passes | FileCheck %s | ||
// RUN: %clang_cc1 -std=c++14 -fcoroutines-ts -triple=x86_64-unknown-linux-gnu -emit-llvm -o - %s -fexceptions -fcxx-exceptions -disable-llvm-passes | FileCheck --check-prefix=CHECK-LPAD %s | ||
|
||
#include "Inputs/coroutine.h" | ||
|
||
namespace coro = std::experimental::coroutines_v1; | ||
|
||
namespace std { | ||
using exception_ptr = int; | ||
exception_ptr current_exception(); | ||
} | ||
|
||
struct coro_t { | ||
struct promise_type { | ||
coro_t get_return_object() { | ||
coro::coroutine_handle<promise_type>{}; | ||
return {}; | ||
} | ||
coro::suspend_never initial_suspend() { return {}; } | ||
coro::suspend_never final_suspend() { return {}; } | ||
void return_void(){} | ||
void unhandled_exception() noexcept; | ||
}; | ||
}; | ||
|
||
struct Cleanup { ~Cleanup(); }; | ||
void may_throw(); | ||
|
||
coro_t f() { | ||
Cleanup x; | ||
may_throw(); | ||
co_return; | ||
} | ||
|
||
// CHECK: @"\01?f@@YA?AUcoro_t@@XZ"( | ||
// CHECK: invoke void @"\01?may_throw@@YAXXZ"() | ||
// CHECK: to label %{{.+}} unwind label %[[EHCLEANUP:.+]] | ||
// CHECK: [[EHCLEANUP]]: | ||
// CHECK: %[[INNERPAD:.+]] = cleanuppad within none [] | ||
// CHECK: call void @"\01??_DCleanup@@QEAAXXZ"( | ||
// CHECK: cleanupret from %[[INNERPAD]] unwind label %[[CATCHSW:.+]] | ||
// CHECK: [[CATCHSW]]: | ||
// CHECK: %[[CATCHSWTOK:.+]] = catchswitch within none [label %[[CATCH:.+]]] unwind label | ||
// CHECK: [[CATCH]]: | ||
// CHECK: %[[CATCHTOK:.+]] = catchpad within [[CATCHSWTOK:.+]] | ||
// CHECK: call void @"\01?unhandled_exception@promise_type@coro_t@@QEAAXXZ" | ||
// CHECK: catchret from %[[CATCHTOK]] to label %[[CATCHRETDEST:.+]] | ||
// CHECK: [[CATCHRETDEST]]: | ||
// CHECK-NEXT: br label %[[TRYCONT:.+]] | ||
// CHECK: [[TRYCONT]]: | ||
// CHECK-NEXT: br label %[[COROFIN:.+]] | ||
// CHECK: [[COROFIN]]: | ||
// CHECK-NEXT: invoke void @"\01?final_suspend@promise_type@coro_t@@QEAA?AUsuspend_never@coroutines_v1@experimental@std@@XZ"( | ||
|
||
// CHECK-LPAD: @_Z1fv( | ||
// CHECK-LPAD: invoke void @_Z9may_throwv() | ||
// CHECK-LPAD: to label %[[CONT:.+]] unwind label %[[CLEANUP:.+]] | ||
// CHECK-LPAD: [[CLEANUP]]: | ||
// CHECK-LPAD: call void @_ZN7CleanupD1Ev(%struct.Cleanup* %x) #2 | ||
// CHECK-LPAD: br label %[[CATCH:.+]] | ||
|
||
// CHECK-LPAD: [[CATCH]]: | ||
// CHECK-LPAD: call i8* @__cxa_begin_catch | ||
// CHECK-LPAD: call void @_ZN6coro_t12promise_type19unhandled_exceptionEv(%"struct.coro_t::promise_type"* %__promise) #2 | ||
// CHECK-LPAD: invoke void @__cxa_end_catch() | ||
// CHECK-LPAD-NEXT: to label %[[CATCHRETDEST:.+]] unwind label | ||
// CHECK-LPAD: [[CATCHRETDEST]]: | ||
// CHECK-LPAD-NEXT: br label %[[TRYCONT:.+]] | ||
// CHECK-LPAD: [[TRYCONT]]: | ||
// CHECK-LPAD-NEXT: br label %[[COROFIN:.+]] | ||
// CHECK-LPAD: [[COROFIN]]: | ||
// CHECK-LPAD-NEXT: invoke void @_ZN6coro_t12promise_type13final_suspendEv( |