aboutsummaryrefslogtreecommitdiff
path: root/clang/test/AST/coroutine-locals-cleanup.cpp
blob: a7f524b0b1ac906c4a4baf02a04d2ca8cc4a108f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -std=c++20 -ast-dump %s | FileCheck %s

#include "Inputs/std-coroutine.h"

using namespace std;

struct Task {
  struct promise_type {
    Task get_return_object() noexcept {
      return Task{coroutine_handle<promise_type>::from_promise(*this)};
    }

    void return_void() noexcept {}

    struct final_awaiter {
      bool await_ready() noexcept { return false; }
      coroutine_handle<> await_suspend(coroutine_handle<promise_type> h) noexcept {
        h.destroy();
        return {};
      }
      void await_resume() noexcept {}
    };

    void unhandled_exception() noexcept {}

    final_awaiter final_suspend() noexcept { return {}; }

    suspend_always initial_suspend() noexcept { return {}; }

    template <typename Awaitable>
    auto await_transform(Awaitable &&awaitable) {
      return awaitable.co_viaIfAsync();
    }
  };

  using handle_t = coroutine_handle<promise_type>;

  class Awaiter {
  public:
    explicit Awaiter(handle_t coro) noexcept;
    Awaiter(Awaiter &&other) noexcept;
    Awaiter(const Awaiter &) = delete;
    ~Awaiter();

    bool await_ready() noexcept { return false; }
    handle_t await_suspend(coroutine_handle<> continuation) noexcept;
    void await_resume();

  private:
    handle_t coro_;
  };

  Task(handle_t coro) noexcept : coro_(coro) {}

  handle_t coro_;

  Task(const Task &t) = delete;
  Task(Task &&t) noexcept;
  ~Task();
  Task &operator=(Task t) noexcept;

  Awaiter co_viaIfAsync();
};

static Task foo() {
  co_return;
}

Task bar() {
  auto mode = 2;
  switch (mode) {
  case 1:
    co_await foo();
    break;
  case 2:
    co_await foo();
    break;
  default:
    break;
  }
}

// CHECK-LABEL: FunctionDecl {{.*}} bar 'Task ()'
// CHECK:         SwitchStmt
// CHECK:           CaseStmt
// CHECK:             ExprWithCleanups {{.*}} 'void'
// CHECK-NEXT:          CoawaitExpr
// CHECK-NEXT:            CXXBindTemporaryExpr {{.*}} 'Task' (CXXTemporary {{.*}})
// CHECK:                 MaterializeTemporaryExpr {{.*}} 'Awaiter':'Task::Awaiter'
// CHECK:                 ExprWithCleanups {{.*}} 'bool'
// CHECK-NEXT:              CXXMemberCallExpr {{.*}} 'bool'
// CHECK-NEXT:                MemberExpr {{.*}} .await_ready
// CHECK:                 ExprWithCleanups {{.*}} 'void *'

// CHECK:           CaseStmt
// CHECK:             ExprWithCleanups {{.*}} 'void'
// CHECK-NEXT:          CoawaitExpr
// CHECK-NEXT:            CXXBindTemporaryExpr {{.*}} 'Task' (CXXTemporary {{.*}})
// CHECK:                 MaterializeTemporaryExpr {{.*}} 'Awaiter':'Task::Awaiter'
// CHECK:                 ExprWithCleanups {{.*}} 'bool'
// CHECK-NEXT:              CXXMemberCallExpr {{.*}} 'bool'
// CHECK-NEXT:                MemberExpr {{.*}} .await_ready
// CHECK:                 ExprWithCleanups {{.*}} 'void *'