coro-cleanup.cpp 3.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  1. // Verify that coroutine promise and allocated memory are freed up on exception.
  2. // RUN: %clang_cc1 -std=c++1z -fcoroutines-ts -triple=x86_64-unknown-linux-gnu -emit-llvm -o - %s -fexceptions -fcxx-exceptions -disable-llvm-passes | FileCheck %s
  3. namespace std::experimental {
  4. template <typename... T> struct coroutine_traits;
  5. template <class Promise = void> struct coroutine_handle {
  6. coroutine_handle() = default;
  7. static coroutine_handle from_address(void *) noexcept;
  8. };
  9. template <> struct coroutine_handle<void> {
  10. static coroutine_handle from_address(void *) noexcept;
  11. coroutine_handle() = default;
  12. template <class PromiseType>
  13. coroutine_handle(coroutine_handle<PromiseType>) noexcept;
  14. };
  15. }
  16. struct suspend_always {
  17. bool await_ready() noexcept;
  18. void await_suspend(std::experimental::coroutine_handle<>) noexcept;
  19. void await_resume() noexcept;
  20. };
  21. template <> struct std::experimental::coroutine_traits<void> {
  22. struct promise_type {
  23. void get_return_object() noexcept;
  24. suspend_always initial_suspend() noexcept;
  25. suspend_always final_suspend() noexcept;
  26. void return_void() noexcept;
  27. promise_type();
  28. ~promise_type();
  29. void unhandled_exception() noexcept;
  30. };
  31. };
  32. struct Cleanup { ~Cleanup(); };
  33. void may_throw();
  34. // CHECK-LABEL: define void @_Z1fv(
  35. void f() {
  36. // CHECK: call i8* @_Znwm(i64
  37. // If promise constructor throws, check that we free the memory.
  38. // CHECK: invoke void @_ZNSt12experimental16coroutine_traitsIJvEE12promise_typeC1Ev(
  39. // CHECK-NEXT: to label %{{.+}} unwind label %[[DeallocPad:.+]]
  40. // CHECK: [[DeallocPad]]:
  41. // CHECK-NEXT: landingpad
  42. // CHECK-NEXT: cleanup
  43. // CHECK: br label %[[Dealloc:.+]]
  44. Cleanup cleanup;
  45. may_throw();
  46. // if may_throw throws, check that we destroy the promise and free the memory.
  47. // CHECK: invoke void @_Z9may_throwv(
  48. // CHECK-NEXT: to label %{{.+}} unwind label %[[CatchPad:.+]]
  49. // CHECK: [[CatchPad]]:
  50. // CHECK-NEXT: landingpad
  51. // CHECK-NEXT: catch i8* null
  52. // CHECK: call void @_ZN7CleanupD1Ev(
  53. // CHECK: br label %[[Catch:.+]]
  54. // CHECK: [[Catch]]:
  55. // CHECK: call i8* @__cxa_begin_catch(
  56. // CHECK: call void @_ZNSt12experimental16coroutine_traitsIJvEE12promise_type19unhandled_exceptionEv(
  57. // CHECK: invoke void @__cxa_end_catch()
  58. // CHECK-NEXT: to label %[[Cont:.+]] unwind
  59. // CHECK: [[Cont]]:
  60. // CHECK-NEXT: br label %[[Cont2:.+]]
  61. // CHECK: [[Cont2]]:
  62. // CHECK-NEXT: br label %[[Cleanup:.+]]
  63. // CHECK: [[Cleanup]]:
  64. // CHECK: call void @_ZNSt12experimental16coroutine_traitsIJvEE12promise_typeD1Ev(
  65. // CHECK: %[[Mem0:.+]] = call i8* @llvm.coro.free(
  66. // CHECK: call void @_ZdlPv(i8* %[[Mem0]]
  67. // CHECK: [[Dealloc]]:
  68. // CHECK: %[[Mem:.+]] = call i8* @llvm.coro.free(
  69. // CHECK: call void @_ZdlPv(i8* %[[Mem]])
  70. co_return;
  71. }
  72. // CHECK-LABEL: define void @_Z1gv(
  73. void g() {
  74. for (;;)
  75. co_await suspend_always{};
  76. // Since this is the endless loop there should be no fallthrough handler (call to 'return_void').
  77. // CHECK-NOT: call void @_ZNSt12experimental16coroutine_traitsIJvEE12promise_type11return_voidEv
  78. }