1 // RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fcoroutines-ts -std=c++14 -emit-llvm %s -o - -disable-llvm-passes | FileCheck %s
2 
3 namespace std {
4 namespace experimental {
5 template <typename... T>
6 struct coroutine_traits; // expected-note {{declared here}}
7 
8 template <class Promise = void>
9 struct coroutine_handle {
10   coroutine_handle() = default;
11   static coroutine_handle from_address(void *) { return {}; }
12 };
13 
14 template <>
15 struct coroutine_handle<void> {
16   static coroutine_handle from_address(void *) { return {}; }
17   coroutine_handle() = default;
18   template <class PromiseType>
19   coroutine_handle(coroutine_handle<PromiseType>) {}
20 };
21 
22 }
23 }
24 
25 struct suspend_always {
26   bool await_ready() { return false; }
27   void await_suspend(std::experimental::coroutine_handle<>) {}
28   void await_resume() {}
29 };
30 
31 struct global_new_delete_tag {};
32 
33 template<>
34 struct std::experimental::coroutine_traits<void, global_new_delete_tag> {
35   struct promise_type {
36     void get_return_object() {}
37     suspend_always initial_suspend() { return {}; }
38     suspend_always final_suspend() { return {}; }
39     void return_void() {}
40   };
41 };
42 
43 // CHECK-LABEL: f0(
44 extern "C" void f0(global_new_delete_tag) {
45   // CHECK: %[[ID:.+]] = call token @llvm.coro.id(i32 16
46   // CHECK: %[[SIZE:.+]] = call i64 @llvm.coro.size.i64()
47   // CHECK: call i8* @_Znwm(i64 %[[SIZE]])
48 
49   // CHECK: %[[FRAME:.+]] = call i8* @llvm.coro.frame()
50   // CHECK: %[[MEM:.+]] = call i8* @llvm.coro.free(token %[[ID]], i8* %[[FRAME]])
51   // CHECK: call void @_ZdlPv(i8* %[[MEM]])
52   co_return;
53 }
54 
55 struct promise_new_tag {};
56 
57 template<>
58 struct std::experimental::coroutine_traits<void, promise_new_tag> {
59   struct promise_type {
60     void *operator new(unsigned long);
61     void get_return_object() {}
62     suspend_always initial_suspend() { return {}; }
63     suspend_always final_suspend() { return {}; }
64     void return_void() {}
65   };
66 };
67 
68 // CHECK-LABEL: f1(
69 extern "C" void f1(promise_new_tag ) {
70   // CHECK: %[[ID:.+]] = call token @llvm.coro.id(i32 16
71   // CHECK: %[[SIZE:.+]] = call i64 @llvm.coro.size.i64()
72   // CHECK: call i8* @_ZNSt12experimental16coroutine_traitsIJv15promise_new_tagEE12promise_typenwEm(i64 %[[SIZE]])
73 
74   // CHECK: %[[FRAME:.+]] = call i8* @llvm.coro.frame()
75   // CHECK: %[[MEM:.+]] = call i8* @llvm.coro.free(token %[[ID]], i8* %[[FRAME]])
76   // CHECK: call void @_ZdlPv(i8* %[[MEM]])
77   co_return;
78 }
79 
80 struct promise_delete_tag {};
81 
82 template<>
83 struct std::experimental::coroutine_traits<void, promise_delete_tag> {
84   struct promise_type {
85     void operator delete(void*);
86     void get_return_object() {}
87     suspend_always initial_suspend() { return {}; }
88     suspend_always final_suspend() { return {}; }
89     void return_void() {}
90   };
91 };
92 
93 // CHECK-LABEL: f2(
94 extern "C" void f2(promise_delete_tag) {
95   // CHECK: %[[ID:.+]] = call token @llvm.coro.id(i32 16
96   // CHECK: %[[SIZE:.+]] = call i64 @llvm.coro.size.i64()
97   // CHECK: call i8* @_Znwm(i64 %[[SIZE]])
98 
99   // CHECK: %[[FRAME:.+]] = call i8* @llvm.coro.frame()
100   // CHECK: %[[MEM:.+]] = call i8* @llvm.coro.free(token %[[ID]], i8* %[[FRAME]])
101   // CHECK: call void @_ZNSt12experimental16coroutine_traitsIJv18promise_delete_tagEE12promise_typedlEPv(i8* %[[MEM]])
102   co_return;
103 }
104 
105 struct promise_sized_delete_tag {};
106 
107 template<>
108 struct std::experimental::coroutine_traits<void, promise_sized_delete_tag> {
109   struct promise_type {
110     void operator delete(void*, unsigned long);
111     void get_return_object() {}
112     suspend_always initial_suspend() { return {}; }
113     suspend_always final_suspend() { return {}; }
114     void return_void() {}
115   };
116 };
117 
118 // CHECK-LABEL: f3(
119 extern "C" void f3(promise_sized_delete_tag) {
120   // CHECK: %[[ID:.+]] = call token @llvm.coro.id(i32 16
121   // CHECK: %[[SIZE:.+]] = call i64 @llvm.coro.size.i64()
122   // CHECK: call i8* @_Znwm(i64 %[[SIZE]])
123 
124   // CHECK: %[[FRAME:.+]] = call i8* @llvm.coro.frame()
125   // CHECK: %[[MEM:.+]] = call i8* @llvm.coro.free(token %[[ID]], i8* %[[FRAME]])
126   // CHECK: %[[SIZE2:.+]] = call i64 @llvm.coro.size.i64()
127   // CHECK: call void @_ZNSt12experimental16coroutine_traitsIJv24promise_sized_delete_tagEE12promise_typedlEPvm(i8* %[[MEM]], i64 %[[SIZE2]])
128   co_return;
129 }
130