[clang] Implement lifetime analysis for lifetime_capture_by(X) (#115921)
[llvm-project.git] / clang / test / CodeGenCoroutines / coro-await-elidable.cpp
blobdeb19b4a5004372147cabc0ec4276c4b7c626025
1 // This file tests the coro_await_elidable attribute semantics.
2 // RUN: %clang_cc1 -triple=x86_64-unknown-linux-gnu -std=c++20 -disable-llvm-passes -emit-llvm %s -o - | FileCheck %s
4 #include "Inputs/coroutine.h"
5 #include "Inputs/utility.h"
7 template <typename T>
8 struct [[clang::coro_await_elidable]] Task {
9 struct promise_type {
10 struct FinalAwaiter {
11 bool await_ready() const noexcept { return false; }
13 template <typename P>
14 std::coroutine_handle<> await_suspend(std::coroutine_handle<P> coro) noexcept {
15 if (!coro)
16 return std::noop_coroutine();
17 return coro.promise().continuation;
19 void await_resume() noexcept {}
22 Task get_return_object() noexcept {
23 return std::coroutine_handle<promise_type>::from_promise(*this);
26 std::suspend_always initial_suspend() noexcept { return {}; }
27 FinalAwaiter final_suspend() noexcept { return {}; }
28 void unhandled_exception() noexcept {}
29 void return_value(T x) noexcept {
30 value = x;
33 std::coroutine_handle<> continuation;
34 T value;
37 Task(std::coroutine_handle<promise_type> handle) : handle(handle) {}
38 ~Task() {
39 if (handle)
40 handle.destroy();
43 struct Awaiter {
44 Awaiter(Task *t) : task(t) {}
45 bool await_ready() const noexcept { return false; }
46 void await_suspend(std::coroutine_handle<void> continuation) noexcept {}
47 T await_resume() noexcept {
48 return task->handle.promise().value;
51 Task *task;
54 auto operator co_await() {
55 return Awaiter{this};
58 private:
59 std::coroutine_handle<promise_type> handle;
62 // CHECK-LABEL: define{{.*}} @_Z6calleev{{.*}} {
63 Task<int> callee() {
64 co_return 1;
67 // CHECK-LABEL: define{{.*}} @_Z8elidablev{{.*}} {
68 Task<int> elidable() {
69 // CHECK: %[[TASK_OBJ:.+]] = alloca %struct.Task
70 // CHECK: call void @_Z6calleev(ptr dead_on_unwind writable sret(%struct.Task) align 8 %[[TASK_OBJ]]) #[[ELIDE_SAFE:.+]]
71 co_return co_await callee();
74 // CHECK-LABEL: define{{.*}} @_Z11nonelidablev{{.*}} {
75 Task<int> nonelidable() {
76 // CHECK: %[[TASK_OBJ:.+]] = alloca %struct.Task
77 auto t = callee();
78 // Because we aren't co_awaiting a prvalue, we cannot elide here.
79 // CHECK: call void @_Z6calleev(ptr dead_on_unwind writable sret(%struct.Task) align 8 %[[TASK_OBJ]])
80 // CHECK-NOT: #[[ELIDE_SAFE]]
81 co_await t;
82 co_await std::move(t);
84 co_return 1;
87 // CHECK-LABEL: define{{.*}} @_Z8addTasksO4TaskIiES1_{{.*}} {
88 Task<int> addTasks([[clang::coro_await_elidable_argument]] Task<int> &&t1, Task<int> &&t2) {
89 int i1 = co_await t1;
90 int i2 = co_await t2;
91 co_return i1 + i2;
94 // CHECK-LABEL: define{{.*}} @_Z10returnSamei{{.*}} {
95 Task<int> returnSame(int i) {
96 co_return i;
99 // CHECK-LABEL: define{{.*}} @_Z21elidableWithMustAwaitv{{.*}} {
100 Task<int> elidableWithMustAwait() {
101 // CHECK: call void @_Z10returnSamei(ptr {{.*}}, i32 noundef 2) #[[ELIDE_SAFE]]
102 // CHECK: call void @_Z10returnSamei(ptr {{.*}}, i32 noundef 3){{$}}
103 co_return co_await addTasks(returnSame(2), returnSame(3));
106 template <typename... Args>
107 Task<int> sumAll([[clang::coro_await_elidable_argument]] Args && ... tasks);
109 // CHECK-LABEL: define{{.*}} @_Z16elidableWithPackv{{.*}} {
110 Task<int> elidableWithPack() {
111 // CHECK: call void @_Z10returnSamei(ptr {{.*}}, i32 noundef 1){{$}}
112 // CHECK: call void @_Z10returnSamei(ptr {{.*}}, i32 noundef 2) #[[ELIDE_SAFE]]
113 // CHECK: call void @_Z10returnSamei(ptr {{.*}}, i32 noundef 3) #[[ELIDE_SAFE]]
114 auto t = returnSame(1);
115 co_return co_await sumAll(t, returnSame(2), returnSame(3));
119 // CHECK-LABEL: define{{.*}} @_Z25elidableWithPackRecursivev{{.*}} {
120 Task<int> elidableWithPackRecursive() {
121 // CHECK: call void @_Z10returnSamei(ptr {{.*}}, i32 noundef 1) #[[ELIDE_SAFE]]
122 // CHECK: call void @_Z10returnSamei(ptr {{.*}}, i32 noundef 2){{$}}
123 // CHECK: call void @_Z10returnSamei(ptr {{.*}}, i32 noundef 3) #[[ELIDE_SAFE]]
124 co_return co_await sumAll(addTasks(returnSame(1), returnSame(2)), returnSame(3));
127 // CHECK: attributes #[[ELIDE_SAFE]] = { coro_elide_safe }