xref: /llvm-project/clang/test/SemaCXX/warn-unsequenced-coro.cpp (revision 0b8daee028a87ab8a6f8fe54d2eb2d5b5c2babd4)
1 // RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fsyntax-only -verify -std=c++20 -I%S/Inputs -Wno-unused -Wno-uninitialized -Wunsequenced %s
2 
3 // expected-no-diagnostics
4 
5 #include "std-coroutine.h"
6 
7 typedef __PTRDIFF_TYPE__ ptrdiff_t;
8 
9 using namespace std;
10 
11 template<class T>
12 struct Task {
13     struct promise_type {
14         Task<T> get_return_object() noexcept;
15         suspend_always initial_suspend() noexcept;
16         suspend_always final_suspend() noexcept;
17         void return_value(T);
18         void unhandled_exception();
yield_valueTask::promise_type19         auto yield_value(Task<T>) noexcept { return final_suspend(); }
20     };
await_readyTask21     bool await_ready() noexcept { return false; }
await_suspendTask22     void await_suspend(coroutine_handle<>) noexcept {}
23     T await_resume();
24 };
25 
26 template<>
27 struct Task<void> {
28     struct promise_type {
29         Task<void> get_return_object() noexcept;
30         suspend_always initial_suspend() noexcept;
31         suspend_always final_suspend() noexcept;
32         void return_void() noexcept;
33         void unhandled_exception() noexcept;
yield_valueTask::promise_type34         auto yield_value(Task<void>) noexcept { return final_suspend(); }
35     };
await_readyTask36     bool await_ready() noexcept { return false; }
await_suspendTask37     void await_suspend(coroutine_handle<>) noexcept {}
await_resumeTask38     void await_resume() noexcept {}
39 };
40 
41 template <typename T>
42 class generator
43 {
44   struct Promise
45   {
get_return_objectgenerator::Promise46     auto get_return_object() { return generator{*this}; }
initial_suspendgenerator::Promise47     auto initial_suspend() { return suspend_never{}; }
final_suspendgenerator::Promise48     auto final_suspend() noexcept { return suspend_always{}; }
unhandled_exceptiongenerator::Promise49     void unhandled_exception() {}
return_voidgenerator::Promise50     void return_void() {}
51 
yield_valuegenerator::Promise52     auto yield_value(T value)
53     {
54       value_ = std::move(value);
55       return suspend_always{};
56     }
57 
58     T value_;
59   };
60 
61   using Handle = coroutine_handle<Promise>;
62 
63   struct sentinel{};
64   struct iterator
65   {
66     using iterator_category = input_iterator_tag;
67     using value_type = T;
68     using difference_type = ptrdiff_t;
69     using reference = T &;
70     using const_reference = const T &;
71     using pointer = T *;
72 
operator ++generator::iterator73     iterator &operator++()
74     {
75       h_.resume();
76       return *this;
77     }
operator *generator::iterator78     const_reference &operator*() const { return h_.promise().value_; }
operator !=generator::iterator79     bool operator!=(sentinel) { return !h_.done(); }
80 
81     Handle h_;
82   };
83 
generator(Promise & p)84   explicit generator(Promise &p) : h_(Handle::from_promise(p)) {}
85   Handle h_;
86 public:
87   using promise_type = Promise;
begin()88   auto begin() { return iterator{h_}; }
end()89   auto end() { return sentinel{}; }
90 };
91 
c(int i)92 Task<void> c(int i) {
93   co_await (i = 0, std::suspend_always{});
94 }
95 
range(int start,int end)96 generator<int> range(int start, int end)
97 {
98   while (start < end)
99     co_yield start++;
100 }
101 
102 Task<int> go(int const& val);
go1(int x)103 Task<int> go1(int x) {
104   co_return co_await go(++x);
105 }