summaryrefslogtreecommitdiffstats
path: root/clang/test/SemaCXX/coroutines.cpp
blob: 53226f7af21a34014ab43c167c318274b3e3af2a (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
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
// RUN: %clang_cc1 -std=c++14 -fcoroutines -verify %s

struct awaitable {
  bool await_ready();
  void await_suspend(); // FIXME: coroutine_handle
  void await_resume();
} a;

void no_coroutine_traits() {
  co_await a; // expected-error {{need to include <coroutine>}}
}

namespace std {
  template<typename ...T> struct coroutine_traits; // expected-note {{declared here}}
};

void no_specialization() {
  co_await a; // expected-error {{implicit instantiation of undefined template 'std::coroutine_traits<void>'}}
}

template<typename ...T> struct std::coroutine_traits<int, T...> {};

int no_promise_type() {
  co_await a; // expected-error {{this function cannot be a coroutine: 'std::coroutine_traits<int>' has no member named 'promise_type'}}
}

template<> struct std::coroutine_traits<double, double> { typedef int promise_type; };
double bad_promise_type(double) {
  co_await a; // expected-error {{this function cannot be a coroutine: 'std::coroutine_traits<double, double>::promise_type' (aka 'int') is not a class}}
}

template<> struct std::coroutine_traits<double, int> {
  struct promise_type {};
};
double bad_promise_type_2(int) {
  co_yield 0; // expected-error {{no member named 'yield_value' in 'std::coroutine_traits<double, int>::promise_type'}}
}

struct promise; // expected-note {{forward declaration}}
template<typename ...T> struct std::coroutine_traits<void, T...> { using promise_type = promise; };

  // FIXME: This diagnostic is terrible.
void undefined_promise() { // expected-error {{variable has incomplete type 'promise_type'}}
  co_await a;
}

struct yielded_thing { const char *p; short a, b; };

struct promise {
  awaitable yield_value(int); // expected-note {{candidate}}
  awaitable yield_value(yielded_thing); // expected-note {{candidate}}
};

void yield() {
  co_yield 0;
  co_yield {"foo", 1, 2};
  co_yield {1e100}; // expected-error {{cannot be narrowed}} expected-note {{explicit cast}} expected-warning {{changes value}} expected-warning {{braces around scalar}}
  co_yield {"foo", __LONG_LONG_MAX__}; // expected-error {{cannot be narrowed}} expected-note {{explicit cast}} expected-warning {{changes value}}
  co_yield {"foo"};
  co_yield "foo"; // expected-error {{no matching}}
}

void mixed_yield() {
  co_yield 0; // expected-note {{use of 'co_yield'}}
  return; // expected-error {{not allowed in coroutine}}
}

void mixed_await() {
  co_await a; // expected-note {{use of 'co_await'}}
  return; // expected-error {{not allowed in coroutine}}
}

void only_coreturn() {
  co_return; // expected-warning {{'co_return' used in a function that uses neither 'co_await' nor 'co_yield'}}
}

void mixed_coreturn(bool b) {
  if (b)
    // expected-warning@+1 {{'co_return' used in a function that uses neither}}
    co_return; // expected-note {{use of 'co_return'}}
  else
    return; // expected-error {{not allowed in coroutine}}
}

struct CtorDtor {
  CtorDtor() {
    co_yield 0; // expected-error {{'co_yield' cannot be used in a constructor}}
  }
  CtorDtor(awaitable a) {
    // The spec doesn't say this is ill-formed, but it must be.
    co_await a; // expected-error {{'co_await' cannot be used in a constructor}}
  }
  ~CtorDtor() {
    co_return 0; // expected-error {{'co_return' cannot be used in a destructor}}
  }
  // FIXME: The spec says this is ill-formed.
  void operator=(CtorDtor&) {
    co_yield 0;
  }
};

void unevaluated() {
  decltype(co_await a); // expected-error {{cannot be used in an unevaluated context}}
  sizeof(co_await a); // expected-error {{cannot be used in an unevaluated context}}
  typeid(co_await a); // expected-error {{cannot be used in an unevaluated context}}
  decltype(co_yield a); // expected-error {{cannot be used in an unevaluated context}}
  sizeof(co_yield a); // expected-error {{cannot be used in an unevaluated context}}
  typeid(co_yield a); // expected-error {{cannot be used in an unevaluated context}}
}

constexpr void constexpr_coroutine() {
  co_yield 0; // expected-error {{'co_yield' cannot be used in a constexpr function}}
}

void varargs_coroutine(const char *, ...) {
  co_await a; // expected-error {{'co_await' cannot be used in a varargs function}}
}

struct outer {};

namespace dependent_operator_co_await_lookup {
  template<typename T> void await_template(T t) {
    // no unqualified lookup results
    co_await t; // expected-error {{no member named 'await_ready' in 'dependent_operator_co_await_lookup::not_awaitable'}}
    // expected-error@-1 {{call to function 'operator co_await' that is neither visible in the template definition nor found by argument-dependent lookup}}
  };
  template void await_template(awaitable);

  struct indirectly_awaitable { indirectly_awaitable(outer); };
  awaitable operator co_await(indirectly_awaitable); // expected-note {{should be declared prior to}}
  template void await_template(indirectly_awaitable);

  struct not_awaitable {};
  template void await_template(not_awaitable); // expected-note {{instantiation}}

  template<typename T> void await_template_2(T t) {
    // one unqualified lookup result
    co_await t;
  };
  template void await_template(outer); // expected-note {{instantiation}}
  template void await_template_2(outer);
}

namespace placeholder {
  awaitable f(), f(int); // expected-note 2{{possible target}}
  int g(), g(int); // expected-note 4{{possible target}}
  void x() {
    co_await f; // expected-error {{reference to overloaded function}}
  }
  void y() {
    co_yield g; // expected-error {{reference to overloaded function}}
  }
  void z() {
    co_await a;
    co_return g; // expected-error {{reference to overloaded function}}
  }
}
OpenPOWER on IntegriCloud