brintos

brintos / llvm-project-archived public Read only

0
0
Text · 6.8 KiB · 9e96a29 Raw
200 lines · cpp
1// 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-attributes2 3#include "Inputs/std-coroutine.h"4 5using std::suspend_always;6using std::suspend_never;7 8template <typename T> struct [[clang::coro_lifetimebound, clang::coro_return_type]] Co {9  struct promise_type {10    Co<T> get_return_object() {11      return {};12    }13    suspend_always initial_suspend();14    suspend_always final_suspend() noexcept;15    void unhandled_exception();16    void return_value(const T &t);17 18    template <typename U>19    auto await_transform(const Co<U> &) {20      struct awaitable {21        bool await_ready() noexcept { return false; }22        void await_suspend(std::coroutine_handle<>) noexcept {}23        U await_resume() noexcept { return {}; }24      };25      return awaitable{};26    }27  };28};29 30Co<int> foo_coro(const int& b) {31  if (b > 0)32    co_return 1;33  co_return 2;34}35 36int getInt() { return 0; }37 38Co<int> bar_coro(const int &b, int c) {39  int x = co_await foo_coro(b);40  int y = co_await foo_coro(1);41  int z = co_await foo_coro(getInt());42  auto unsafe1 = foo_coro(1); // expected-warning {{temporary whose address is used as value of local variable}}43  auto unsafe2 = foo_coro(getInt()); // expected-warning {{temporary whose address is used as value of local variable}}44  auto  safe1 = foo_coro(b);45  auto  safe2 = foo_coro(c);46  co_return co_await foo_coro(co_await foo_coro(1));47}48 49[[clang::coro_wrapper]] Co<int> plain_return_co(int b) {50  return foo_coro(b); // expected-warning {{address of stack memory associated with parameter}}51}52 53[[clang::coro_wrapper]] Co<int> safe_forwarding(const int& b) {54  return foo_coro(b);55}56 57[[clang::coro_wrapper]] Co<int> unsafe_wrapper(int b) {58  return safe_forwarding(b); // expected-warning {{address of stack memory associated with parameter}}59}60 61[[clang::coro_wrapper]] Co<int> complex_plain_return(int b) {62  return b > 0 63      ? foo_coro(1)   // expected-warning {{returning address of local temporary object}}64      : bar_coro(0, 1); // expected-warning {{returning address of local temporary object}}65}66 67// =============================================================================68// Lambdas69// =============================================================================70namespace lambdas {71void lambdas() {72  auto unsafe_lambda = [] [[clang::coro_wrapper]] (int b) {73    return foo_coro(b); // expected-warning {{address of stack memory associated with parameter}}74  };75  auto coro_lambda = [] (const int&) -> Co<int> {76    co_return 0;77  };78  auto unsafe_coro_lambda = [&] (const int& b) -> Co<int> {79    int x = co_await coro_lambda(b);80    auto safe = coro_lambda(b);81    auto unsafe1 = coro_lambda(1); // expected-warning {{temporary whose address is used as value of local variable}}82    auto unsafe2 = coro_lambda(getInt()); // expected-warning {{temporary whose address is used as value of local variable}}83    auto unsafe3 = coro_lambda(co_await coro_lambda(b)); // expected-warning {{temporary whose address is used as value of local variable}}84    co_return co_await safe;85  };86  auto safe_lambda = [](int b) -> Co<int> {87    int x = co_await foo_coro(1);88    co_return x + co_await foo_coro(b);89  };90}91 92Co<int> lambda_captures() {93  int a = 1;94  // Temporary lambda object dies.95  auto lamb = [a](int x, const int& y) -> Co<int> { // expected-warning {{temporary whose address is used as value of local variable 'lamb'}}96    co_return x + y + a;97  }(1, a);98  // Object dies but it has no capture.99  auto no_capture = []() -> Co<int> { co_return 1; }();100  auto bad_no_capture = [](const int& a) -> Co<int> { co_return a; }(1); // expected-warning {{temporary}}101  // Temporary lambda object with lifetime extension under co_await.102  int res = co_await [a](int x, const int& y) -> Co<int> {103    co_return x + y + a;104  }(1, a);105  // Lambda object on stack should be fine.106  auto lamb2 = [a]() -> Co<int> { co_return a; };107  auto on_stack = lamb2();108  auto res2 = co_await on_stack;109  co_return 1;110}111} // namespace lambdas112 113// =============================================================================114// Member coroutines115// =============================================================================116namespace member_coroutines{117struct S {118  Co<int> member(const int& a) { co_return a; }119};120 121Co<int> use() {122  S s;123  int a = 1;124  auto test1 = s.member(1);  // expected-warning {{temporary whose address is used as value of local variable}}125  auto test2 = s.member(a);126  auto test3 = S{}.member(a);  // expected-warning {{temporary whose address is used as value of local variable}}127  co_return 1;128}129 130[[clang::coro_wrapper]] Co<int> wrapper(const int& a) {131  S s;132  return s.member(a); // expected-warning {{address of stack memory}}133}134} // member_coroutines135 136// =============================================================================137// Safe usage when parameters are value138// =============================================================================139namespace by_value {140Co<int> value_coro(int b) { co_return co_await foo_coro(b); }141[[clang::coro_wrapper]] Co<int> wrapper1(int b) { return value_coro(b); }142[[clang::coro_wrapper]] Co<int> wrapper2(const int& b) { return value_coro(b); }143} // namespace by_value144 145// =============================================================================146// Lifetime bound but not a Coroutine Return Type: No analysis.147// =============================================================================148namespace not_a_crt {149template <typename T> struct [[clang::coro_lifetimebound]] CoNoCRT {150  struct promise_type {151    CoNoCRT<T> get_return_object() {152      return {};153    }154    suspend_always initial_suspend();155    suspend_always final_suspend() noexcept;156    void unhandled_exception();157    void return_value(const T &t);158  };159};160 161CoNoCRT<int> foo_coro(const int& a) { co_return a; }162CoNoCRT<int> bar(int a) { 163  auto x = foo_coro(a);164  co_return 1;165}166} // namespace not_a_crt167 168// =============================================================================169// Not lifetime bound coroutine wrappers: [[clang::coro_disable_lifetimebound]].170// =============================================================================171namespace disable_lifetimebound {172Co<int> foo(int x) {  co_return x; }173 174[[clang::coro_wrapper, clang::coro_disable_lifetimebound]]175Co<int> foo_wrapper(const int& x) { return foo(x); }176 177[[clang::coro_wrapper]] Co<int> caller() {178  // The call to foo_wrapper is wrapper is safe.179  return foo_wrapper(1);180}181 182struct S{183[[clang::coro_wrapper, clang::coro_disable_lifetimebound]]184Co<int> member(const int& x) { return foo(x); }185};186 187Co<int> use() {188  S s;189  int a = 1;190  auto test1 = s.member(1); // param is not flagged.191  auto test2 = S{}.member(a); // 'this' is not flagged.192  co_return 1;193}194 195[[clang::coro_wrapper]] Co<int> return_stack_addr(const int& a) {196  S s;197  return s.member(a); // return of stack addr is not flagged.198}199} // namespace disable_lifetimebound200