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 }
9 
10 struct suspend_always {
11   bool await_ready() { return false; }
12   void await_suspend() {}
13   void await_resume() {}
14 };
15 
16 struct global_new_delete_tag {};
17 
18 template<>
19 struct std::experimental::coroutine_traits<void, global_new_delete_tag> {
20   struct promise_type {
21     void get_return_object() {}
22     suspend_always initial_suspend() { return {}; }
23     suspend_always final_suspend() { return {}; }
24     void return_void() {}
25   };
26 };
27 
28 // CHECK-LABEL: f0(
29 extern "C" void f0(global_new_delete_tag) {
30   // CHECK: %[[ID:.+]] = call token @llvm.coro.id(i32 16
31   // CHECK: %[[SIZE:.+]] = call i64 @llvm.coro.size.i64()
32   // CHECK: call i8* @_Znwm(i64 %[[SIZE]])
33 
34   // CHECK: %[[FRAME:.+]] = call i8* @llvm.coro.frame()
35   // CHECK: %[[MEM:.+]] = call i8* @llvm.coro.free(token %[[ID]], i8* %[[FRAME]])
36   // CHECK: call void @_ZdlPv(i8* %[[MEM]])
37   co_await suspend_always{};
38 }
39 
40 struct promise_new_tag {};
41 
42 template<>
43 struct std::experimental::coroutine_traits<void, promise_new_tag> {
44   struct promise_type {
45     void *operator new(unsigned long);
46     void get_return_object() {}
47     suspend_always initial_suspend() { return {}; }
48     suspend_always final_suspend() { return {}; }
49     void return_void() {}
50   };
51 };
52 
53 // CHECK-LABEL: f1(
54 extern "C" void f1(promise_new_tag ) {
55   // CHECK: %[[ID:.+]] = call token @llvm.coro.id(i32 16
56   // CHECK: %[[SIZE:.+]] = call i64 @llvm.coro.size.i64()
57   // CHECK: call i8* @_ZNSt12experimental16coroutine_traitsIJv15promise_new_tagEE12promise_typenwEm(i64 %[[SIZE]])
58 
59   // CHECK: %[[FRAME:.+]] = call i8* @llvm.coro.frame()
60   // CHECK: %[[MEM:.+]] = call i8* @llvm.coro.free(token %[[ID]], i8* %[[FRAME]])
61   // CHECK: call void @_ZdlPv(i8* %[[MEM]])
62   co_await suspend_always{};
63 }
64 
65 struct promise_delete_tag {};
66 
67 template<>
68 struct std::experimental::coroutine_traits<void, promise_delete_tag> {
69   struct promise_type {
70     void operator delete(void*);
71     void get_return_object() {}
72     suspend_always initial_suspend() { return {}; }
73     suspend_always final_suspend() { return {}; }
74     void return_void() {}
75   };
76 };
77 
78 // CHECK-LABEL: f2(
79 extern "C" void f2(promise_delete_tag) {
80   // CHECK: %[[ID:.+]] = call token @llvm.coro.id(i32 16
81   // CHECK: %[[SIZE:.+]] = call i64 @llvm.coro.size.i64()
82   // CHECK: call i8* @_Znwm(i64 %[[SIZE]])
83 
84   // CHECK: %[[FRAME:.+]] = call i8* @llvm.coro.frame()
85   // CHECK: %[[MEM:.+]] = call i8* @llvm.coro.free(token %[[ID]], i8* %[[FRAME]])
86   // CHECK: call void @_ZNSt12experimental16coroutine_traitsIJv18promise_delete_tagEE12promise_typedlEPv(i8* %[[MEM]])
87   co_await suspend_always{};
88 }
89 
90 struct promise_sized_delete_tag {};
91 
92 template<>
93 struct std::experimental::coroutine_traits<void, promise_sized_delete_tag> {
94   struct promise_type {
95     void operator delete(void*, unsigned long);
96     void get_return_object() {}
97     suspend_always initial_suspend() { return {}; }
98     suspend_always final_suspend() { return {}; }
99     void return_void() {}
100   };
101 };
102 
103 // CHECK-LABEL: f3(
104 extern "C" void f3(promise_sized_delete_tag) {
105   // CHECK: %[[ID:.+]] = call token @llvm.coro.id(i32 16
106   // CHECK: %[[SIZE:.+]] = call i64 @llvm.coro.size.i64()
107   // CHECK: call i8* @_Znwm(i64 %[[SIZE]])
108 
109   // CHECK: %[[FRAME:.+]] = call i8* @llvm.coro.frame()
110   // CHECK: %[[MEM:.+]] = call i8* @llvm.coro.free(token %[[ID]], i8* %[[FRAME]])
111   // CHECK: %[[SIZE2:.+]] = call i64 @llvm.coro.size.i64()
112   // CHECK: call void @_ZNSt12experimental16coroutine_traitsIJv24promise_sized_delete_tagEE12promise_typedlEPvm(i8* %[[MEM]], i64 %[[SIZE2]])
113   co_await suspend_always{};
114 }
115