xref: /llvm-project/clang/test/AST/coroutine-locals-cleanup.cpp (revision 7c1d9b15eee3a34678addab2bab66f3020ac0753)
1 // RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -std=c++20 -ast-dump %s | FileCheck %s
2 
3 #include "Inputs/std-coroutine.h"
4 
5 using namespace std;
6 
7 struct Task {
8   struct promise_type {
get_return_objectTask::promise_type9     Task get_return_object() noexcept {
10       return Task{coroutine_handle<promise_type>::from_promise(*this)};
11     }
12 
return_voidTask::promise_type13     void return_void() noexcept {}
14 
15     struct final_awaiter {
await_readyTask::promise_type::final_awaiter16       bool await_ready() noexcept { return false; }
await_suspendTask::promise_type::final_awaiter17       coroutine_handle<> await_suspend(coroutine_handle<promise_type> h) noexcept {
18         h.destroy();
19         return {};
20       }
await_resumeTask::promise_type::final_awaiter21       void await_resume() noexcept {}
22     };
23 
unhandled_exceptionTask::promise_type24     void unhandled_exception() noexcept {}
25 
final_suspendTask::promise_type26     final_awaiter final_suspend() noexcept { return {}; }
27 
initial_suspendTask::promise_type28     suspend_always initial_suspend() noexcept { return {}; }
29 
30     template <typename Awaitable>
await_transformTask::promise_type31     auto await_transform(Awaitable &&awaitable) {
32       return awaitable.co_viaIfAsync();
33     }
34   };
35 
36   using handle_t = coroutine_handle<promise_type>;
37 
38   class Awaiter {
39   public:
40     explicit Awaiter(handle_t coro) noexcept;
41     Awaiter(Awaiter &&other) noexcept;
42     Awaiter(const Awaiter &) = delete;
43     ~Awaiter();
44 
await_ready()45     bool await_ready() noexcept { return false; }
46     handle_t await_suspend(coroutine_handle<> continuation) noexcept;
47     void await_resume();
48 
49   private:
50     handle_t coro_;
51   };
52 
TaskTask53   Task(handle_t coro) noexcept : coro_(coro) {}
54 
55   handle_t coro_;
56 
57   Task(const Task &t) = delete;
58   Task(Task &&t) noexcept;
59   ~Task();
60   Task &operator=(Task t) noexcept;
61 
62   Awaiter co_viaIfAsync();
63 };
64 
foo()65 static Task foo() {
66   co_return;
67 }
68 
bar()69 Task bar() {
70   auto mode = 2;
71   switch (mode) {
72   case 1:
73     co_await foo();
74     break;
75   case 2:
76     co_await foo();
77     break;
78   default:
79     break;
80   }
81 }
82 
83 // CHECK-LABEL: FunctionDecl {{.*}} bar 'Task ()'
84 // CHECK:         SwitchStmt
85 // CHECK:           CaseStmt
86 // CHECK:             ExprWithCleanups {{.*}} 'void'
87 // CHECK-NEXT:          CoawaitExpr
88 // CHECK-NEXT:            CXXBindTemporaryExpr {{.*}} 'Task' (CXXTemporary {{.*}})
89 // CHECK:                 MaterializeTemporaryExpr {{.*}} 'Awaiter':'Task::Awaiter'
90 // CHECK:                 ExprWithCleanups {{.*}} 'bool'
91 // CHECK-NEXT:              CXXMemberCallExpr {{.*}} 'bool'
92 // CHECK-NEXT:                MemberExpr {{.*}} .await_ready
93 // CHECK:                 ExprWithCleanups {{.*}} 'void *'
94 
95 // CHECK:           CaseStmt
96 // CHECK:             ExprWithCleanups {{.*}} 'void'
97 // CHECK-NEXT:          CoawaitExpr
98 // CHECK-NEXT:            CXXBindTemporaryExpr {{.*}} 'Task' (CXXTemporary {{.*}})
99 // CHECK:                 MaterializeTemporaryExpr {{.*}} 'Awaiter':'Task::Awaiter'
100 // CHECK:                 ExprWithCleanups {{.*}} 'bool'
101 // CHECK-NEXT:              CXXMemberCallExpr {{.*}} 'bool'
102 // CHECK-NEXT:                MemberExpr {{.*}} .await_ready
103 // CHECK:                 ExprWithCleanups {{.*}} 'void *'
104