1e825cc4eSUtkarsh Saxena // RUN: %clang_cc1 -triple x86_64-apple-darwin9 %s -std=c++20 -fsyntax-only -verify -Wall -Wextra -Wno-error=unreachable-code -Wno-unused -Wno-c++23-lambda-attributes
2fbfd2c99SUtkarsh Saxena
3fbfd2c99SUtkarsh Saxena #include "Inputs/std-coroutine.h"
4fbfd2c99SUtkarsh Saxena
5fbfd2c99SUtkarsh Saxena using std::suspend_always;
6fbfd2c99SUtkarsh Saxena using std::suspend_never;
7fbfd2c99SUtkarsh Saxena
8fbfd2c99SUtkarsh Saxena template <typename T> struct [[clang::coro_lifetimebound, clang::coro_return_type]] Co {
9fbfd2c99SUtkarsh Saxena struct promise_type {
get_return_objectCo::promise_type10fbfd2c99SUtkarsh Saxena Co<T> get_return_object() {
11fbfd2c99SUtkarsh Saxena return {};
12fbfd2c99SUtkarsh Saxena }
13fbfd2c99SUtkarsh Saxena suspend_always initial_suspend();
14fbfd2c99SUtkarsh Saxena suspend_always final_suspend() noexcept;
15fbfd2c99SUtkarsh Saxena void unhandled_exception();
16fbfd2c99SUtkarsh Saxena void return_value(const T &t);
17fbfd2c99SUtkarsh Saxena
18fbfd2c99SUtkarsh Saxena template <typename U>
await_transformCo::promise_type19fbfd2c99SUtkarsh Saxena auto await_transform(const Co<U> &) {
20fbfd2c99SUtkarsh Saxena struct awaitable {
21fbfd2c99SUtkarsh Saxena bool await_ready() noexcept { return false; }
22fbfd2c99SUtkarsh Saxena void await_suspend(std::coroutine_handle<>) noexcept {}
23fbfd2c99SUtkarsh Saxena U await_resume() noexcept { return {}; }
24fbfd2c99SUtkarsh Saxena };
25fbfd2c99SUtkarsh Saxena return awaitable{};
26fbfd2c99SUtkarsh Saxena }
27fbfd2c99SUtkarsh Saxena };
28fbfd2c99SUtkarsh Saxena };
29fbfd2c99SUtkarsh Saxena
foo_coro(const int & b)30fbfd2c99SUtkarsh Saxena Co<int> foo_coro(const int& b) {
31fbfd2c99SUtkarsh Saxena if (b > 0)
32fbfd2c99SUtkarsh Saxena co_return 1;
33fbfd2c99SUtkarsh Saxena co_return 2;
34fbfd2c99SUtkarsh Saxena }
35fbfd2c99SUtkarsh Saxena
getInt()36fbfd2c99SUtkarsh Saxena int getInt() { return 0; }
37fbfd2c99SUtkarsh Saxena
bar_coro(const int & b,int c)38fbfd2c99SUtkarsh Saxena Co<int> bar_coro(const int &b, int c) {
39fbfd2c99SUtkarsh Saxena int x = co_await foo_coro(b);
40fbfd2c99SUtkarsh Saxena int y = co_await foo_coro(1);
41fbfd2c99SUtkarsh Saxena int z = co_await foo_coro(getInt());
42fbfd2c99SUtkarsh Saxena auto unsafe1 = foo_coro(1); // expected-warning {{temporary whose address is used as value of local variable}}
43fbfd2c99SUtkarsh Saxena auto unsafe2 = foo_coro(getInt()); // expected-warning {{temporary whose address is used as value of local variable}}
44fbfd2c99SUtkarsh Saxena auto safe1 = foo_coro(b);
45fbfd2c99SUtkarsh Saxena auto safe2 = foo_coro(c);
46fbfd2c99SUtkarsh Saxena co_return co_await foo_coro(co_await foo_coro(1));
47fbfd2c99SUtkarsh Saxena }
48fbfd2c99SUtkarsh Saxena
plain_return_co(int b)49fbfd2c99SUtkarsh Saxena [[clang::coro_wrapper]] Co<int> plain_return_co(int b) {
50fbfd2c99SUtkarsh Saxena return foo_coro(b); // expected-warning {{address of stack memory associated with parameter}}
51fbfd2c99SUtkarsh Saxena }
52fbfd2c99SUtkarsh Saxena
safe_forwarding(const int & b)53fbfd2c99SUtkarsh Saxena [[clang::coro_wrapper]] Co<int> safe_forwarding(const int& b) {
54fbfd2c99SUtkarsh Saxena return foo_coro(b);
55fbfd2c99SUtkarsh Saxena }
56fbfd2c99SUtkarsh Saxena
unsafe_wrapper(int b)57fbfd2c99SUtkarsh Saxena [[clang::coro_wrapper]] Co<int> unsafe_wrapper(int b) {
58fbfd2c99SUtkarsh Saxena return safe_forwarding(b); // expected-warning {{address of stack memory associated with parameter}}
59fbfd2c99SUtkarsh Saxena }
60fbfd2c99SUtkarsh Saxena
complex_plain_return(int b)61fbfd2c99SUtkarsh Saxena [[clang::coro_wrapper]] Co<int> complex_plain_return(int b) {
62fbfd2c99SUtkarsh Saxena return b > 0
63fbfd2c99SUtkarsh Saxena ? foo_coro(1) // expected-warning {{returning address of local temporary object}}
64fbfd2c99SUtkarsh Saxena : bar_coro(0, 1); // expected-warning {{returning address of local temporary object}}
65fbfd2c99SUtkarsh Saxena }
66fbfd2c99SUtkarsh Saxena
67*667e58a7SUtkarsh Saxena // =============================================================================
68*667e58a7SUtkarsh Saxena // Lambdas
69*667e58a7SUtkarsh Saxena // =============================================================================
70*667e58a7SUtkarsh Saxena namespace lambdas {
lambdas()71fbfd2c99SUtkarsh Saxena void lambdas() {
72e825cc4eSUtkarsh Saxena auto unsafe_lambda = [] [[clang::coro_wrapper]] (int b) {
73fbfd2c99SUtkarsh Saxena return foo_coro(b); // expected-warning {{address of stack memory associated with parameter}}
74fbfd2c99SUtkarsh Saxena };
75fbfd2c99SUtkarsh Saxena auto coro_lambda = [] (const int&) -> Co<int> {
76fbfd2c99SUtkarsh Saxena co_return 0;
77fbfd2c99SUtkarsh Saxena };
78fbfd2c99SUtkarsh Saxena auto unsafe_coro_lambda = [&] (const int& b) -> Co<int> {
79fbfd2c99SUtkarsh Saxena int x = co_await coro_lambda(b);
80fbfd2c99SUtkarsh Saxena auto safe = coro_lambda(b);
81fbfd2c99SUtkarsh Saxena auto unsafe1 = coro_lambda(1); // expected-warning {{temporary whose address is used as value of local variable}}
82fbfd2c99SUtkarsh Saxena auto unsafe2 = coro_lambda(getInt()); // expected-warning {{temporary whose address is used as value of local variable}}
83fbfd2c99SUtkarsh Saxena auto unsafe3 = coro_lambda(co_await coro_lambda(b)); // expected-warning {{temporary whose address is used as value of local variable}}
84fbfd2c99SUtkarsh Saxena co_return co_await safe;
85fbfd2c99SUtkarsh Saxena };
86fbfd2c99SUtkarsh Saxena auto safe_lambda = [](int b) -> Co<int> {
87fbfd2c99SUtkarsh Saxena int x = co_await foo_coro(1);
88fbfd2c99SUtkarsh Saxena co_return x + co_await foo_coro(b);
89fbfd2c99SUtkarsh Saxena };
90fbfd2c99SUtkarsh Saxena }
91*667e58a7SUtkarsh Saxena
lambda_captures()92*667e58a7SUtkarsh Saxena Co<int> lambda_captures() {
93*667e58a7SUtkarsh Saxena int a = 1;
94*667e58a7SUtkarsh Saxena // Temporary lambda object dies.
95*667e58a7SUtkarsh Saxena auto lamb = [a](int x, const int& y) -> Co<int> { // expected-warning {{temporary whose address is used as value of local variable 'lamb'}}
96*667e58a7SUtkarsh Saxena co_return x + y + a;
97*667e58a7SUtkarsh Saxena }(1, a);
98*667e58a7SUtkarsh Saxena // Object dies but it has no capture.
99*667e58a7SUtkarsh Saxena auto no_capture = []() -> Co<int> { co_return 1; }();
100*667e58a7SUtkarsh Saxena auto bad_no_capture = [](const int& a) -> Co<int> { co_return a; }(1); // expected-warning {{temporary}}
101*667e58a7SUtkarsh Saxena // Temporary lambda object with lifetime extension under co_await.
102*667e58a7SUtkarsh Saxena int res = co_await [a](int x, const int& y) -> Co<int> {
103*667e58a7SUtkarsh Saxena co_return x + y + a;
104*667e58a7SUtkarsh Saxena }(1, a);
105*667e58a7SUtkarsh Saxena // Lambda object on stack should be fine.
106*667e58a7SUtkarsh Saxena auto lamb2 = [a]() -> Co<int> { co_return a; };
107*667e58a7SUtkarsh Saxena auto on_stack = lamb2();
108*667e58a7SUtkarsh Saxena auto res2 = co_await on_stack;
109*667e58a7SUtkarsh Saxena co_return 1;
110*667e58a7SUtkarsh Saxena }
111*667e58a7SUtkarsh Saxena } // namespace lambdas
112*667e58a7SUtkarsh Saxena
113*667e58a7SUtkarsh Saxena // =============================================================================
114*667e58a7SUtkarsh Saxena // Member coroutines
115*667e58a7SUtkarsh Saxena // =============================================================================
116*667e58a7SUtkarsh Saxena namespace member_coroutines{
117*667e58a7SUtkarsh Saxena struct S {
membermember_coroutines::S118*667e58a7SUtkarsh Saxena Co<int> member(const int& a) { co_return a; }
119*667e58a7SUtkarsh Saxena };
120*667e58a7SUtkarsh Saxena
use()121*667e58a7SUtkarsh Saxena Co<int> use() {
122*667e58a7SUtkarsh Saxena S s;
123*667e58a7SUtkarsh Saxena int a = 1;
124*667e58a7SUtkarsh Saxena auto test1 = s.member(1); // expected-warning {{temporary whose address is used as value of local variable}}
125*667e58a7SUtkarsh Saxena auto test2 = s.member(a);
126*667e58a7SUtkarsh Saxena auto test3 = S{}.member(a); // expected-warning {{temporary whose address is used as value of local variable}}
127*667e58a7SUtkarsh Saxena co_return 1;
128*667e58a7SUtkarsh Saxena }
129*667e58a7SUtkarsh Saxena
wrapper(const int & a)130*667e58a7SUtkarsh Saxena [[clang::coro_wrapper]] Co<int> wrapper(const int& a) {
131*667e58a7SUtkarsh Saxena S s;
132*667e58a7SUtkarsh Saxena return s.member(a); // expected-warning {{address of stack memory}}
133*667e58a7SUtkarsh Saxena }
134*667e58a7SUtkarsh Saxena } // member_coroutines
135*667e58a7SUtkarsh Saxena
136fbfd2c99SUtkarsh Saxena // =============================================================================
137fbfd2c99SUtkarsh Saxena // Safe usage when parameters are value
138fbfd2c99SUtkarsh Saxena // =============================================================================
139fbfd2c99SUtkarsh Saxena namespace by_value {
value_coro(int b)140fbfd2c99SUtkarsh Saxena Co<int> value_coro(int b) { co_return co_await foo_coro(b); }
wrapper1(int b)141fbfd2c99SUtkarsh Saxena [[clang::coro_wrapper]] Co<int> wrapper1(int b) { return value_coro(b); }
wrapper2(const int & b)142fbfd2c99SUtkarsh Saxena [[clang::coro_wrapper]] Co<int> wrapper2(const int& b) { return value_coro(b); }
143*667e58a7SUtkarsh Saxena } // namespace by_value
144fbfd2c99SUtkarsh Saxena
145fbfd2c99SUtkarsh Saxena // =============================================================================
146fbfd2c99SUtkarsh Saxena // Lifetime bound but not a Coroutine Return Type: No analysis.
147fbfd2c99SUtkarsh Saxena // =============================================================================
148fbfd2c99SUtkarsh Saxena namespace not_a_crt {
149fbfd2c99SUtkarsh Saxena template <typename T> struct [[clang::coro_lifetimebound]] CoNoCRT {
150fbfd2c99SUtkarsh Saxena struct promise_type {
get_return_objectnot_a_crt::CoNoCRT::promise_type151fbfd2c99SUtkarsh Saxena CoNoCRT<T> get_return_object() {
152fbfd2c99SUtkarsh Saxena return {};
153fbfd2c99SUtkarsh Saxena }
154fbfd2c99SUtkarsh Saxena suspend_always initial_suspend();
155fbfd2c99SUtkarsh Saxena suspend_always final_suspend() noexcept;
156fbfd2c99SUtkarsh Saxena void unhandled_exception();
157fbfd2c99SUtkarsh Saxena void return_value(const T &t);
158fbfd2c99SUtkarsh Saxena };
159fbfd2c99SUtkarsh Saxena };
160fbfd2c99SUtkarsh Saxena
foo_coro(const int & a)161fbfd2c99SUtkarsh Saxena CoNoCRT<int> foo_coro(const int& a) { co_return a; }
bar(int a)162fbfd2c99SUtkarsh Saxena CoNoCRT<int> bar(int a) {
163fbfd2c99SUtkarsh Saxena auto x = foo_coro(a);
164fbfd2c99SUtkarsh Saxena co_return 1;
165fbfd2c99SUtkarsh Saxena }
166fbfd2c99SUtkarsh Saxena } // namespace not_a_crt
167190a75b5SUtkarsh Saxena
168190a75b5SUtkarsh Saxena // =============================================================================
169190a75b5SUtkarsh Saxena // Not lifetime bound coroutine wrappers: [[clang::coro_disable_lifetimebound]].
170190a75b5SUtkarsh Saxena // =============================================================================
171190a75b5SUtkarsh Saxena namespace disable_lifetimebound {
foo(int x)172190a75b5SUtkarsh Saxena Co<int> foo(int x) { co_return x; }
173190a75b5SUtkarsh Saxena
174190a75b5SUtkarsh Saxena [[clang::coro_wrapper, clang::coro_disable_lifetimebound]]
foo_wrapper(const int & x)175190a75b5SUtkarsh Saxena Co<int> foo_wrapper(const int& x) { return foo(x); }
176190a75b5SUtkarsh Saxena
caller()177190a75b5SUtkarsh Saxena [[clang::coro_wrapper]] Co<int> caller() {
178190a75b5SUtkarsh Saxena // The call to foo_wrapper is wrapper is safe.
179190a75b5SUtkarsh Saxena return foo_wrapper(1);
180190a75b5SUtkarsh Saxena }
181*667e58a7SUtkarsh Saxena
182*667e58a7SUtkarsh Saxena struct S{
183*667e58a7SUtkarsh Saxena [[clang::coro_wrapper, clang::coro_disable_lifetimebound]]
memberdisable_lifetimebound::S184*667e58a7SUtkarsh Saxena Co<int> member(const int& x) { return foo(x); }
185*667e58a7SUtkarsh Saxena };
186*667e58a7SUtkarsh Saxena
use()187*667e58a7SUtkarsh Saxena Co<int> use() {
188*667e58a7SUtkarsh Saxena S s;
189*667e58a7SUtkarsh Saxena int a = 1;
190*667e58a7SUtkarsh Saxena auto test1 = s.member(1); // param is not flagged.
191*667e58a7SUtkarsh Saxena auto test2 = S{}.member(a); // 'this' is not flagged.
192*667e58a7SUtkarsh Saxena co_return 1;
193*667e58a7SUtkarsh Saxena }
194*667e58a7SUtkarsh Saxena
return_stack_addr(const int & a)195*667e58a7SUtkarsh Saxena [[clang::coro_wrapper]] Co<int> return_stack_addr(const int& a) {
196*667e58a7SUtkarsh Saxena S s;
197*667e58a7SUtkarsh Saxena return s.member(a); // return of stack addr is not flagged.
198*667e58a7SUtkarsh Saxena }
199190a75b5SUtkarsh Saxena } // namespace disable_lifetimebound
200