coro-params.cpp 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  1. // Verifies that parameters are copied with move constructors
  2. // Verifies that parameter copies are destroyed
  3. // Vefifies that parameter copies are used in the body of the coroutine
  4. // Verifies that parameter copies are used to construct the promise type, if that type has a matching constructor
  5. // RUN: %clang_cc1 -std=c++1z -fcoroutines-ts -triple=x86_64-unknown-linux-gnu -emit-llvm -o - %s -disable-llvm-passes -fexceptions | FileCheck %s
  6. namespace std::experimental {
  7. template <typename... T> struct coroutine_traits;
  8. template <class Promise = void> struct coroutine_handle {
  9. coroutine_handle() = default;
  10. static coroutine_handle from_address(void *) noexcept;
  11. };
  12. template <> struct coroutine_handle<void> {
  13. static coroutine_handle from_address(void *) noexcept;
  14. coroutine_handle() = default;
  15. template <class PromiseType>
  16. coroutine_handle(coroutine_handle<PromiseType>) noexcept;
  17. };
  18. }
  19. struct suspend_always {
  20. bool await_ready() noexcept;
  21. void await_suspend(std::experimental::coroutine_handle<>) noexcept;
  22. void await_resume() noexcept;
  23. };
  24. template <typename... Args> struct std::experimental::coroutine_traits<void, Args...> {
  25. struct promise_type {
  26. void get_return_object() noexcept;
  27. suspend_always initial_suspend() noexcept;
  28. suspend_always final_suspend() noexcept;
  29. void return_void() noexcept;
  30. promise_type();
  31. ~promise_type() noexcept;
  32. void unhandled_exception() noexcept;
  33. };
  34. };
  35. // TODO: Not supported yet
  36. struct CopyOnly {
  37. int val;
  38. CopyOnly(const CopyOnly&) noexcept;
  39. CopyOnly(CopyOnly&&) = delete;
  40. ~CopyOnly();
  41. };
  42. struct MoveOnly {
  43. int val;
  44. MoveOnly(const MoveOnly&) = delete;
  45. MoveOnly(MoveOnly&&) noexcept;
  46. ~MoveOnly();
  47. };
  48. struct MoveAndCopy {
  49. int val;
  50. MoveAndCopy(const MoveAndCopy&)noexcept;
  51. MoveAndCopy(MoveAndCopy&&) noexcept;
  52. ~MoveAndCopy();
  53. };
  54. void consume(int,int,int) noexcept;
  55. // TODO: Add support for CopyOnly params
  56. // CHECK: define void @_Z1fi8MoveOnly11MoveAndCopy(i32 %val, %struct.MoveOnly* %[[MoParam:.+]], %struct.MoveAndCopy* %[[McParam:.+]]) #0 personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*
  57. void f(int val, MoveOnly moParam, MoveAndCopy mcParam) {
  58. // CHECK: %[[MoCopy:.+]] = alloca %struct.MoveOnly
  59. // CHECK: %[[McCopy:.+]] = alloca %struct.MoveAndCopy
  60. // CHECK: store i32 %val, i32* %[[ValAddr:.+]]
  61. // CHECK: call i8* @llvm.coro.begin(
  62. // CHECK: call void @_ZN8MoveOnlyC1EOS_(%struct.MoveOnly* %[[MoCopy]], %struct.MoveOnly* dereferenceable(4) %[[MoParam]])
  63. // CHECK-NEXT: call void @_ZN11MoveAndCopyC1EOS_(%struct.MoveAndCopy* %[[McCopy]], %struct.MoveAndCopy* dereferenceable(4) %[[McParam]]) #
  64. // CHECK-NEXT: invoke void @_ZNSt12experimental16coroutine_traitsIJvi8MoveOnly11MoveAndCopyEE12promise_typeC1Ev(
  65. // CHECK: call void @_ZN14suspend_always12await_resumeEv(
  66. // CHECK: %[[IntParam:.+]] = load i32, i32* %val1
  67. // CHECK: %[[MoGep:.+]] = getelementptr inbounds %struct.MoveOnly, %struct.MoveOnly* %[[MoCopy]], i32 0, i32 0
  68. // CHECK: %[[MoVal:.+]] = load i32, i32* %[[MoGep]]
  69. // CHECK: %[[McGep:.+]] = getelementptr inbounds %struct.MoveAndCopy, %struct.MoveAndCopy* %[[McCopy]], i32 0, i32 0
  70. // CHECK: %[[McVal:.+]] = load i32, i32* %[[McGep]]
  71. // CHECK: call void @_Z7consumeiii(i32 %[[IntParam]], i32 %[[MoVal]], i32 %[[McVal]])
  72. consume(val, moParam.val, mcParam.val);
  73. co_return;
  74. // Skip to final suspend:
  75. // CHECK: call void @_ZNSt12experimental16coroutine_traitsIJvi8MoveOnly11MoveAndCopyEE12promise_type13final_suspendEv(
  76. // CHECK: call void @_ZN14suspend_always12await_resumeEv(
  77. // Destroy promise, then parameter copies:
  78. // CHECK: call void @_ZNSt12experimental16coroutine_traitsIJvi8MoveOnly11MoveAndCopyEE12promise_typeD1Ev(%"struct.std::experimental::coroutine_traits<void, int, MoveOnly, MoveAndCopy>::promise_type"* %__promise) #2
  79. // CHECK-NEXT: call void @_ZN11MoveAndCopyD1Ev(%struct.MoveAndCopy* %[[McCopy]])
  80. // CHECK-NEXT: call void @_ZN8MoveOnlyD1Ev(%struct.MoveOnly* %[[MoCopy]]
  81. // CHECK-NEXT: call i8* @llvm.coro.free(
  82. }
  83. // CHECK-LABEL: void @_Z16dependent_paramsI1A1BEvT_T0_S3_(%struct.A* %x, %struct.B* %0, %struct.B* %y)
  84. template <typename T, typename U>
  85. void dependent_params(T x, U, U y) {
  86. // CHECK: %[[x_copy:.+]] = alloca %struct.A
  87. // CHECK-NEXT: %[[unnamed_copy:.+]] = alloca %struct.B
  88. // CHECK-NEXT: %[[y_copy:.+]] = alloca %struct.B
  89. // CHECK: call i8* @llvm.coro.begin
  90. // CHECK-NEXT: call void @_ZN1AC1EOS_(%struct.A* %[[x_copy]], %struct.A* dereferenceable(512) %x)
  91. // CHECK-NEXT: call void @_ZN1BC1EOS_(%struct.B* %[[unnamed_copy]], %struct.B* dereferenceable(512) %0)
  92. // CHECK-NEXT: call void @_ZN1BC1EOS_(%struct.B* %[[y_copy]], %struct.B* dereferenceable(512) %y)
  93. // CHECK-NEXT: invoke void @_ZNSt12experimental16coroutine_traitsIJv1A1BS2_EE12promise_typeC1Ev(
  94. co_return;
  95. }
  96. struct A {
  97. int WontFitIntoRegisterForSure[128];
  98. A();
  99. A(A&&) noexcept;
  100. ~A();
  101. };
  102. struct B {
  103. int WontFitIntoRegisterForSure[128];
  104. B();
  105. B(B&&) noexcept;
  106. ~B();
  107. };
  108. void call_dependent_params() {
  109. dependent_params(A{}, B{}, B{});
  110. }
  111. // Test that, when the promise type has a constructor whose signature matches
  112. // that of the coroutine function, that constructor is used. This is an
  113. // experimental feature that will be proposed for the Coroutines TS.
  114. struct promise_matching_constructor {};
  115. template<>
  116. struct std::experimental::coroutine_traits<void, promise_matching_constructor, int, float, double> {
  117. struct promise_type {
  118. promise_type(promise_matching_constructor, int, float, double) {}
  119. promise_type() = delete;
  120. void get_return_object() {}
  121. suspend_always initial_suspend() { return {}; }
  122. suspend_always final_suspend() { return {}; }
  123. void return_void() {}
  124. void unhandled_exception() {}
  125. };
  126. };
  127. // CHECK-LABEL: void @_Z38coroutine_matching_promise_constructor28promise_matching_constructorifd(i32 %0, float %1, double %2)
  128. void coroutine_matching_promise_constructor(promise_matching_constructor, int, float, double) {
  129. // CHECK: %[[INT:.+]] = load i32, i32* %5, align 4
  130. // CHECK: %[[FLOAT:.+]] = load float, float* %6, align 4
  131. // CHECK: %[[DOUBLE:.+]] = load double, double* %7, align 8
  132. // CHECK: invoke void @_ZNSt12experimental16coroutine_traitsIJv28promise_matching_constructorifdEE12promise_typeC1ES1_ifd(%"struct.std::experimental::coroutine_traits<void, promise_matching_constructor, int, float, double>::promise_type"* %__promise, i32 %[[INT]], float %[[FLOAT]], double %[[DOUBLE]])
  133. co_return;
  134. }
  135. struct some_class;
  136. struct method {};
  137. template <typename... Args> struct std::experimental::coroutine_traits<method, Args...> {
  138. struct promise_type {
  139. promise_type(some_class&, float);
  140. method get_return_object();
  141. suspend_always initial_suspend();
  142. suspend_always final_suspend();
  143. void return_void();
  144. void unhandled_exception();
  145. };
  146. };
  147. struct some_class {
  148. method good_coroutine_calls_custom_constructor(float);
  149. };
  150. // CHECK-LABEL: define void @_ZN10some_class39good_coroutine_calls_custom_constructorEf(%struct.some_class*
  151. method some_class::good_coroutine_calls_custom_constructor(float) {
  152. // CHECK: invoke void @_ZNSt12experimental16coroutine_traitsIJ6methodR10some_classfEE12promise_typeC1ES3_f(%"struct.std::experimental::coroutine_traits<method, some_class &, float>::promise_type"* %__promise, %struct.some_class* dereferenceable(1) %{{.+}}, float
  153. co_return;
  154. }