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