1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168
|
// Tests that we can mark await-suspend as noinline correctly.
//
// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -emit-llvm -o - %s \
// RUN: -O1 -disable-llvm-passes | FileCheck %s
#include "Inputs/coroutine.h"
struct Task {
struct promise_type {
struct FinalAwaiter {
bool await_ready() const noexcept { return false; }
template <typename PromiseType>
std::coroutine_handle<> await_suspend(std::coroutine_handle<PromiseType> h) noexcept {
return h.promise().continuation;
}
void await_resume() noexcept {}
};
Task get_return_object() noexcept {
return std::coroutine_handle<promise_type>::from_promise(*this);
}
std::suspend_always initial_suspend() noexcept { return {}; }
FinalAwaiter final_suspend() noexcept { return {}; }
void unhandled_exception() noexcept {}
void return_void() noexcept {}
std::coroutine_handle<> continuation;
};
Task(std::coroutine_handle<promise_type> handle);
~Task();
private:
std::coroutine_handle<promise_type> handle;
};
struct StatefulAwaiter {
int value;
bool await_ready() const noexcept { return false; }
template <typename PromiseType>
void await_suspend(std::coroutine_handle<PromiseType> h) noexcept {}
void await_resume() noexcept {}
};
typedef std::suspend_always NoStateAwaiter;
using AnotherStatefulAwaiter = StatefulAwaiter;
template <class T>
struct TemplatedAwaiter {
T value;
bool await_ready() const noexcept { return false; }
template <typename PromiseType>
void await_suspend(std::coroutine_handle<PromiseType> h) noexcept {}
void await_resume() noexcept {}
};
class Awaitable {};
StatefulAwaiter operator co_await(Awaitable) {
return StatefulAwaiter{};
}
StatefulAwaiter GlobalAwaiter;
class Awaitable2 {};
StatefulAwaiter& operator co_await(Awaitable2) {
return GlobalAwaiter;
}
struct AlwaysInlineStatefulAwaiter {
void* value;
bool await_ready() const noexcept { return false; }
template <typename PromiseType>
__attribute__((always_inline))
void await_suspend(std::coroutine_handle<PromiseType> h) noexcept {}
void await_resume() noexcept {}
};
Task testing() {
co_await std::suspend_always{};
co_await StatefulAwaiter{};
co_await AnotherStatefulAwaiter{};
// Test lvalue case.
StatefulAwaiter awaiter;
co_await awaiter;
// The explicit call to await_suspend is not considered suspended.
awaiter.await_suspend(std::coroutine_handle<void>::from_address(nullptr));
co_await TemplatedAwaiter<int>{};
TemplatedAwaiter<int> TemplatedAwaiterInstace;
co_await TemplatedAwaiterInstace;
co_await Awaitable{};
co_await Awaitable2{};
co_await AlwaysInlineStatefulAwaiter{};
}
struct AwaitTransformTask {
struct promise_type {
struct FinalAwaiter {
bool await_ready() const noexcept { return false; }
template <typename PromiseType>
std::coroutine_handle<> await_suspend(std::coroutine_handle<PromiseType> h) noexcept {
return h.promise().continuation;
}
void await_resume() noexcept {}
};
AwaitTransformTask get_return_object() noexcept {
return std::coroutine_handle<promise_type>::from_promise(*this);
}
std::suspend_always initial_suspend() noexcept { return {}; }
FinalAwaiter final_suspend() noexcept { return {}; }
void unhandled_exception() noexcept {}
void return_void() noexcept {}
template <typename Awaitable>
auto await_transform(Awaitable &&awaitable) {
return awaitable;
}
std::coroutine_handle<> continuation;
};
AwaitTransformTask(std::coroutine_handle<promise_type> handle);
~AwaitTransformTask();
private:
std::coroutine_handle<promise_type> handle;
};
struct awaitableWithGetAwaiter {
bool await_ready() const noexcept { return false; }
template <typename PromiseType>
void await_suspend(std::coroutine_handle<PromiseType> h) noexcept {}
void await_resume() noexcept {}
};
AwaitTransformTask testingWithAwaitTransform() {
co_await awaitableWithGetAwaiter{};
}
// CHECK: define{{.*}}@_ZNSt14suspend_always13await_suspendESt16coroutine_handleIvE{{.*}}#[[NORMAL_ATTR:[0-9]+]]
// CHECK: define{{.*}}@_ZN15StatefulAwaiter13await_suspendIN4Task12promise_typeEEEvSt16coroutine_handleIT_E{{.*}}#[[NOINLINE_ATTR:[0-9]+]]
// CHECK: define{{.*}}@_ZN15StatefulAwaiter13await_suspendIvEEvSt16coroutine_handleIT_E{{.*}}#[[NORMAL_ATTR]]
// CHECK: define{{.*}}@_ZN16TemplatedAwaiterIiE13await_suspendIN4Task12promise_typeEEEvSt16coroutine_handleIT_E{{.*}}#[[NOINLINE_ATTR]]
// CHECK: define{{.*}}@_ZN27AlwaysInlineStatefulAwaiter13await_suspendIN4Task12promise_typeEEEvSt16coroutine_handleIT_E{{.*}}#[[ALWAYS_INLINE_ATTR:[0-9]+]]
// CHECK: define{{.*}}@_ZN4Task12promise_type12FinalAwaiter13await_suspendIS0_EESt16coroutine_handleIvES3_IT_E{{.*}}#[[NORMAL_ATTR]]
// CHECK: define{{.*}}@_ZN23awaitableWithGetAwaiter13await_suspendIN18AwaitTransformTask12promise_typeEEEvSt16coroutine_handleIT_E{{.*}}#[[NORMAL_ATTR]]
// CHECK: define{{.*}}@_ZN18AwaitTransformTask12promise_type12FinalAwaiter13await_suspendIS0_EESt16coroutine_handleIvES3_IT_E{{.*}}#[[NORMAL_ATTR]]
// CHECK-NOT: attributes #[[NORMAL_ATTR]] = noinline
// CHECK: attributes #[[NOINLINE_ATTR]] = {{.*}}noinline
// CHECK-NOT: attributes #[[ALWAYS_INLINE_ATTR]] = {{.*}}noinline
// CHECK: attributes #[[ALWAYS_INLINE_ATTR]] = {{.*}}alwaysinline
|