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 // RUN: %clang_cc1 -std=c++1z -fcoroutines-ts -triple=x86_64-unknown-linux-gnu -emit-llvm -o - %s -disable-llvm-passes -fexceptions | FileCheck %s
5 
6 namespace std::experimental {
7 template <typename... T> struct coroutine_traits;
8 
9 template <class Promise = void> struct coroutine_handle {
10   coroutine_handle() = default;
11   static coroutine_handle from_address(void *) noexcept;
12 };
13 template <> struct coroutine_handle<void> {
14   static coroutine_handle from_address(void *) noexcept;
15   coroutine_handle() = default;
16   template <class PromiseType>
17   coroutine_handle(coroutine_handle<PromiseType>) noexcept;
18 };
19 }
20 
21 struct suspend_always {
22   bool await_ready() noexcept;
23   void await_suspend(std::experimental::coroutine_handle<>) noexcept;
24   void await_resume() noexcept;
25 };
26 
27 template <typename... Args> struct std::experimental::coroutine_traits<void, Args...> {
28   struct promise_type {
29     void get_return_object() noexcept;
30     suspend_always initial_suspend() noexcept;
31     suspend_always final_suspend() noexcept;
32     void return_void() noexcept;
33     promise_type();
34     ~promise_type() noexcept;
35     void unhandled_exception() noexcept;
36   };
37 };
38 
39 // TODO: Not supported yet
40 struct CopyOnly {
41   int val;
42   CopyOnly(const CopyOnly&) noexcept;
43   CopyOnly(CopyOnly&&) = delete;
44   ~CopyOnly();
45 };
46 
47 struct MoveOnly {
48   int val;
49   MoveOnly(const MoveOnly&) = delete;
50   MoveOnly(MoveOnly&&) noexcept;
51   ~MoveOnly();
52 };
53 
54 struct MoveAndCopy {
55   int val;
56   MoveAndCopy(const MoveAndCopy&)noexcept;
57   MoveAndCopy(MoveAndCopy&&) noexcept;
58   ~MoveAndCopy();
59 };
60 
61 void consume(int,int,int) noexcept;
62 
63 // TODO: Add support for CopyOnly params
64 // CHECK: define void @_Z1fi8MoveOnly11MoveAndCopy(i32 %val, %struct.MoveOnly* %[[MoParam:.+]], %struct.MoveAndCopy* %[[McParam:.+]]) #0 personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*
65 void f(int val, MoveOnly moParam, MoveAndCopy mcParam) {
66   // CHECK: %[[MoCopy:.+]] = alloca %struct.MoveOnly
67   // CHECK: %[[McCopy:.+]] = alloca %struct.MoveAndCopy
68   // CHECK: store i32 %val, i32* %[[ValAddr:.+]]
69 
70   // CHECK: call i8* @llvm.coro.begin(
71   // CHECK-NEXT: call void @_ZN8MoveOnlyC1EOS_(%struct.MoveOnly* %[[MoCopy]], %struct.MoveOnly* dereferenceable(4) %[[MoParam]])
72   // CHECK-NEXT: call void @_ZN11MoveAndCopyC1EOS_(%struct.MoveAndCopy* %[[McCopy]], %struct.MoveAndCopy* dereferenceable(4) %[[McParam]]) #
73   // CHECK-NEXT: invoke void @_ZNSt12experimental16coroutine_traitsIJvi8MoveOnly11MoveAndCopyEE12promise_typeC1Ev(
74 
75   // CHECK: call void @_ZN14suspend_always12await_resumeEv(
76   // CHECK: %[[IntParam:.+]] = load i32, i32* %val.addr
77   // CHECK: %[[MoGep:.+]] = getelementptr inbounds %struct.MoveOnly, %struct.MoveOnly* %[[MoCopy]], i32 0, i32 0
78   // CHECK: %[[MoVal:.+]] = load i32, i32* %[[MoGep]]
79   // CHECK: %[[McGep:.+]] =  getelementptr inbounds %struct.MoveAndCopy, %struct.MoveAndCopy* %[[McCopy]], i32 0, i32 0
80   // CHECK: %[[McVal:.+]] = load i32, i32* %[[McGep]]
81   // CHECK: call void @_Z7consumeiii(i32 %[[IntParam]], i32 %[[MoVal]], i32 %[[McVal]])
82 
83   consume(val, moParam.val, mcParam.val);
84   co_return;
85 
86   // Skip to final suspend:
87   // CHECK: call void @_ZNSt12experimental16coroutine_traitsIJvi8MoveOnly11MoveAndCopyEE12promise_type13final_suspendEv(
88   // CHECK: call void @_ZN14suspend_always12await_resumeEv(
89 
90   // Destroy promise, then parameter copies:
91   // CHECK: call void @_ZNSt12experimental16coroutine_traitsIJvi8MoveOnly11MoveAndCopyEE12promise_typeD1Ev(%"struct.std::experimental::coroutine_traits<void, int, MoveOnly, MoveAndCopy>::promise_type"* %__promise) #2
92   // CHECK-NEXT: call void @_ZN11MoveAndCopyD1Ev(%struct.MoveAndCopy* %[[McCopy]])
93   // CHECK-NEXT: call void @_ZN8MoveOnlyD1Ev(%struct.MoveOnly* %[[MoCopy]]
94   // CHECK-NEXT: call i8* @llvm.coro.free(
95 }
96