1 // RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fcoroutines-ts -std=c++14 -fsyntax-only -ast-dump %s | FileCheck %s
2 
3 #include "Inputs/std-coroutine.h"
4 
5 using namespace std::experimental;
6 
7 struct Task {
8   struct promise_type {
9     Task get_return_object() noexcept {
10       return Task{coroutine_handle<promise_type>::from_promise(*this)};
11     }
12 
13     void return_void() noexcept {}
14 
15     struct final_awaiter {
16       bool await_ready() noexcept { return false; }
17       coroutine_handle<> await_suspend(coroutine_handle<promise_type> h) noexcept {
18         h.destroy();
19         return {};
20       }
21       void await_resume() noexcept {}
22     };
23 
24     void unhandled_exception() noexcept {}
25 
26     final_awaiter final_suspend() noexcept { return {}; }
27 
28     suspend_always initial_suspend() noexcept { return {}; }
29 
30     template <typename Awaitable>
31     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 
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 
53   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 
65 static Task foo() {
66   co_return;
67 }
68 
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:            MaterializeTemporaryExpr {{.*}} 'Task::Awaiter':'Task::Awaiter'
89 // CHECK:                 ExprWithCleanups {{.*}} 'bool'
90 // CHECK-NEXT:              CXXMemberCallExpr {{.*}} 'bool'
91 // CHECK-NEXT:                MemberExpr {{.*}} .await_ready
92 // CHECK:                 CallExpr {{.*}} 'void'
93 // CHECK-NEXT:              ImplicitCastExpr {{.*}} 'void (*)(void *)'
94 // CHECK-NEXT:                DeclRefExpr {{.*}} '__builtin_coro_resume' 'void (void *)'
95 // CHECK-NEXT:              ExprWithCleanups {{.*}} 'void *'
96 
97 // CHECK:           CaseStmt
98 // CHECK:             ExprWithCleanups {{.*}} 'void'
99 // CHECK-NEXT:          CoawaitExpr
100 // CHECK-NEXT:            MaterializeTemporaryExpr {{.*}} 'Task::Awaiter':'Task::Awaiter'
101 // CHECK:                 ExprWithCleanups {{.*}} 'bool'
102 // CHECK-NEXT:              CXXMemberCallExpr {{.*}} 'bool'
103 // CHECK-NEXT:                MemberExpr {{.*}} .await_ready
104 // CHECK:                 CallExpr {{.*}} 'void'
105 // CHECK-NEXT:              ImplicitCastExpr {{.*}} 'void (*)(void *)'
106 // CHECK-NEXT:                DeclRefExpr {{.*}} '__builtin_coro_resume' 'void (void *)'
107 // CHECK-NEXT:              ExprWithCleanups {{.*}} 'void *'
108