blob: 20c9c551d464120d29a5535c6161c906587d8ff3 [file] [log] [blame]
Richard Smithcfd53b42015-10-22 06:13:50 +00001//===--- SemaCoroutines.cpp - Semantic Analysis for Coroutines ------------===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This file implements semantic analysis for C++ Coroutines.
11//
12//===----------------------------------------------------------------------===//
13
14#include "clang/Sema/SemaInternal.h"
Richard Smith9f690bd2015-10-27 06:02:45 +000015#include "clang/AST/Decl.h"
16#include "clang/AST/ExprCXX.h"
17#include "clang/AST/StmtCXX.h"
18#include "clang/Lex/Preprocessor.h"
19#include "clang/Sema/Overload.h"
Richard Smithcfd53b42015-10-22 06:13:50 +000020using namespace clang;
21using namespace sema;
22
Richard Smith9f690bd2015-10-27 06:02:45 +000023/// Look up the std::coroutine_traits<...>::promise_type for the given
24/// function type.
25static QualType lookupPromiseType(Sema &S, const FunctionProtoType *FnType,
26 SourceLocation Loc) {
27 // FIXME: Cache std::coroutine_traits once we've found it.
28 NamespaceDecl *Std = S.getStdNamespace();
29 if (!Std) {
30 S.Diag(Loc, diag::err_implied_std_coroutine_traits_not_found);
31 return QualType();
32 }
33
34 LookupResult Result(S, &S.PP.getIdentifierTable().get("coroutine_traits"),
35 Loc, Sema::LookupOrdinaryName);
36 if (!S.LookupQualifiedName(Result, Std)) {
37 S.Diag(Loc, diag::err_implied_std_coroutine_traits_not_found);
38 return QualType();
39 }
40
41 ClassTemplateDecl *CoroTraits = Result.getAsSingle<ClassTemplateDecl>();
42 if (!CoroTraits) {
43 Result.suppressDiagnostics();
44 // We found something weird. Complain about the first thing we found.
45 NamedDecl *Found = *Result.begin();
46 S.Diag(Found->getLocation(), diag::err_malformed_std_coroutine_traits);
47 return QualType();
48 }
49
50 // Form template argument list for coroutine_traits<R, P1, P2, ...>.
51 TemplateArgumentListInfo Args(Loc, Loc);
52 Args.addArgument(TemplateArgumentLoc(
53 TemplateArgument(FnType->getReturnType()),
54 S.Context.getTrivialTypeSourceInfo(FnType->getReturnType(), Loc)));
55 for (QualType T : FnType->getParamTypes())
56 Args.addArgument(TemplateArgumentLoc(
57 TemplateArgument(T), S.Context.getTrivialTypeSourceInfo(T, Loc)));
58
59 // Build the template-id.
60 QualType CoroTrait =
61 S.CheckTemplateIdType(TemplateName(CoroTraits), Loc, Args);
62 if (CoroTrait.isNull())
63 return QualType();
64 if (S.RequireCompleteType(Loc, CoroTrait,
65 diag::err_coroutine_traits_missing_specialization))
66 return QualType();
67
68 CXXRecordDecl *RD = CoroTrait->getAsCXXRecordDecl();
69 assert(RD && "specialization of class template is not a class?");
70
71 // Look up the ::promise_type member.
72 LookupResult R(S, &S.PP.getIdentifierTable().get("promise_type"), Loc,
73 Sema::LookupOrdinaryName);
74 S.LookupQualifiedName(R, RD);
75 auto *Promise = R.getAsSingle<TypeDecl>();
76 if (!Promise) {
77 S.Diag(Loc, diag::err_implied_std_coroutine_traits_promise_type_not_found)
78 << RD;
79 return QualType();
80 }
81
82 // The promise type is required to be a class type.
83 QualType PromiseType = S.Context.getTypeDeclType(Promise);
84 if (!PromiseType->getAsCXXRecordDecl()) {
Richard Smith9b2f53e2015-11-19 02:36:35 +000085 // Use the fully-qualified name of the type.
86 auto *NNS = NestedNameSpecifier::Create(S.Context, nullptr, Std);
87 NNS = NestedNameSpecifier::Create(S.Context, NNS, false,
88 CoroTrait.getTypePtr());
89 PromiseType = S.Context.getElaboratedType(ETK_None, NNS, PromiseType);
90
Richard Smith9f690bd2015-10-27 06:02:45 +000091 S.Diag(Loc, diag::err_implied_std_coroutine_traits_promise_type_not_class)
92 << PromiseType;
93 return QualType();
94 }
95
96 return PromiseType;
97}
98
99/// Check that this is a context in which a coroutine suspension can appear.
Richard Smithcfd53b42015-10-22 06:13:50 +0000100static FunctionScopeInfo *
101checkCoroutineContext(Sema &S, SourceLocation Loc, StringRef Keyword) {
Richard Smith744b2242015-11-20 02:54:01 +0000102 // 'co_await' and 'co_yield' are not permitted in unevaluated operands.
103 if (S.isUnevaluatedContext()) {
104 S.Diag(Loc, diag::err_coroutine_unevaluated_context) << Keyword;
Richard Smithcfd53b42015-10-22 06:13:50 +0000105 return nullptr;
Richard Smith744b2242015-11-20 02:54:01 +0000106 }
Richard Smithcfd53b42015-10-22 06:13:50 +0000107
108 // Any other usage must be within a function.
109 auto *FD = dyn_cast<FunctionDecl>(S.CurContext);
110 if (!FD) {
111 S.Diag(Loc, isa<ObjCMethodDecl>(S.CurContext)
112 ? diag::err_coroutine_objc_method
113 : diag::err_coroutine_outside_function) << Keyword;
114 } else if (isa<CXXConstructorDecl>(FD) || isa<CXXDestructorDecl>(FD)) {
115 // Coroutines TS [special]/6:
116 // A special member function shall not be a coroutine.
117 //
118 // FIXME: We assume that this really means that a coroutine cannot
119 // be a constructor or destructor.
120 S.Diag(Loc, diag::err_coroutine_ctor_dtor)
121 << isa<CXXDestructorDecl>(FD) << Keyword;
122 } else if (FD->isConstexpr()) {
123 S.Diag(Loc, diag::err_coroutine_constexpr) << Keyword;
124 } else if (FD->isVariadic()) {
125 S.Diag(Loc, diag::err_coroutine_varargs) << Keyword;
126 } else {
127 auto *ScopeInfo = S.getCurFunction();
128 assert(ScopeInfo && "missing function scope for function");
Richard Smith9f690bd2015-10-27 06:02:45 +0000129
130 // If we don't have a promise variable, build one now.
Richard Smith23da82c2015-11-20 22:40:06 +0000131 if (!ScopeInfo->CoroutinePromise) {
Richard Smith9f690bd2015-10-27 06:02:45 +0000132 QualType T =
Richard Smith23da82c2015-11-20 22:40:06 +0000133 FD->getType()->isDependentType()
134 ? S.Context.DependentTy
135 : lookupPromiseType(S, FD->getType()->castAs<FunctionProtoType>(),
136 Loc);
Richard Smith9f690bd2015-10-27 06:02:45 +0000137 if (T.isNull())
138 return nullptr;
139
140 // Create and default-initialize the promise.
141 ScopeInfo->CoroutinePromise =
142 VarDecl::Create(S.Context, FD, FD->getLocation(), FD->getLocation(),
143 &S.PP.getIdentifierTable().get("__promise"), T,
144 S.Context.getTrivialTypeSourceInfo(T, Loc), SC_None);
145 S.CheckVariableDeclarationType(ScopeInfo->CoroutinePromise);
146 if (!ScopeInfo->CoroutinePromise->isInvalidDecl())
147 S.ActOnUninitializedDecl(ScopeInfo->CoroutinePromise, false);
148 }
149
Richard Smithcfd53b42015-10-22 06:13:50 +0000150 return ScopeInfo;
151 }
152
153 return nullptr;
154}
155
Richard Smith9f690bd2015-10-27 06:02:45 +0000156/// Build a call to 'operator co_await' if there is a suitable operator for
157/// the given expression.
158static ExprResult buildOperatorCoawaitCall(Sema &SemaRef, Scope *S,
159 SourceLocation Loc, Expr *E) {
160 UnresolvedSet<16> Functions;
161 SemaRef.LookupOverloadedOperatorName(OO_Coawait, S, E->getType(), QualType(),
162 Functions);
163 return SemaRef.CreateOverloadedUnaryOp(Loc, UO_Coawait, Functions, E);
164}
Richard Smithcfd53b42015-10-22 06:13:50 +0000165
Richard Smith9f690bd2015-10-27 06:02:45 +0000166struct ReadySuspendResumeResult {
167 bool IsInvalid;
168 Expr *Results[3];
169};
170
Richard Smith23da82c2015-11-20 22:40:06 +0000171static ExprResult buildMemberCall(Sema &S, Expr *Base, SourceLocation Loc,
172 StringRef Name,
173 MutableArrayRef<Expr *> Args) {
174 DeclarationNameInfo NameInfo(&S.PP.getIdentifierTable().get(Name), Loc);
175
176 // FIXME: Fix BuildMemberReferenceExpr to take a const CXXScopeSpec&.
177 CXXScopeSpec SS;
178 ExprResult Result = S.BuildMemberReferenceExpr(
179 Base, Base->getType(), Loc, /*IsPtr=*/false, SS,
180 SourceLocation(), nullptr, NameInfo, /*TemplateArgs=*/nullptr,
181 /*Scope=*/nullptr);
182 if (Result.isInvalid())
183 return ExprError();
184
185 return S.ActOnCallExpr(nullptr, Result.get(), Loc, Args, Loc, nullptr);
186}
187
Richard Smith9f690bd2015-10-27 06:02:45 +0000188/// Build calls to await_ready, await_suspend, and await_resume for a co_await
189/// expression.
190static ReadySuspendResumeResult buildCoawaitCalls(Sema &S, SourceLocation Loc,
191 Expr *E) {
192 // Assume invalid until we see otherwise.
193 ReadySuspendResumeResult Calls = {true, {}};
194
195 const StringRef Funcs[] = {"await_ready", "await_suspend", "await_resume"};
196 for (size_t I = 0, N = llvm::array_lengthof(Funcs); I != N; ++I) {
Richard Smith9f690bd2015-10-27 06:02:45 +0000197 Expr *Operand = new (S.Context) OpaqueValueExpr(
Richard Smith1f38edd2015-11-22 03:13:02 +0000198 Loc, E->getType(), VK_LValue, E->getObjectKind(), E);
Richard Smith9f690bd2015-10-27 06:02:45 +0000199
Richard Smith9f690bd2015-10-27 06:02:45 +0000200 // FIXME: Pass coroutine handle to await_suspend.
Richard Smith23da82c2015-11-20 22:40:06 +0000201 ExprResult Result = buildMemberCall(S, Operand, Loc, Funcs[I], None);
Richard Smith9f690bd2015-10-27 06:02:45 +0000202 if (Result.isInvalid())
203 return Calls;
204 Calls.Results[I] = Result.get();
205 }
206
207 Calls.IsInvalid = false;
208 return Calls;
209}
210
211ExprResult Sema::ActOnCoawaitExpr(Scope *S, SourceLocation Loc, Expr *E) {
Richard Smith10610f72015-11-20 22:57:24 +0000212 if (E->getType()->isPlaceholderType()) {
213 ExprResult R = CheckPlaceholderExpr(E);
214 if (R.isInvalid()) return ExprError();
215 E = R.get();
216 }
217
Richard Smith9f690bd2015-10-27 06:02:45 +0000218 ExprResult Awaitable = buildOperatorCoawaitCall(*this, S, Loc, E);
219 if (Awaitable.isInvalid())
220 return ExprError();
221 return BuildCoawaitExpr(Loc, Awaitable.get());
222}
223ExprResult Sema::BuildCoawaitExpr(SourceLocation Loc, Expr *E) {
224 auto *Coroutine = checkCoroutineContext(*this, Loc, "co_await");
Richard Smith744b2242015-11-20 02:54:01 +0000225 if (!Coroutine)
226 return ExprError();
Richard Smith9f690bd2015-10-27 06:02:45 +0000227
Richard Smith9f690bd2015-10-27 06:02:45 +0000228 if (E->getType()->isPlaceholderType()) {
229 ExprResult R = CheckPlaceholderExpr(E);
230 if (R.isInvalid()) return ExprError();
231 E = R.get();
232 }
233
Richard Smith10610f72015-11-20 22:57:24 +0000234 if (E->getType()->isDependentType()) {
235 Expr *Res = new (Context) CoawaitExpr(Loc, Context.DependentTy, E);
236 Coroutine->CoroutineStmts.push_back(Res);
237 return Res;
238 }
239
Richard Smith1f38edd2015-11-22 03:13:02 +0000240 // If the expression is a temporary, materialize it as an lvalue so that we
241 // can use it multiple times.
242 if (E->getValueKind() == VK_RValue)
243 E = new (Context) MaterializeTemporaryExpr(E->getType(), E, true);
Richard Smith9f690bd2015-10-27 06:02:45 +0000244
245 // Build the await_ready, await_suspend, await_resume calls.
246 ReadySuspendResumeResult RSS = buildCoawaitCalls(*this, Loc, E);
247 if (RSS.IsInvalid)
248 return ExprError();
249
250 Expr *Res = new (Context) CoawaitExpr(Loc, E, RSS.Results[0], RSS.Results[1],
251 RSS.Results[2]);
Richard Smith744b2242015-11-20 02:54:01 +0000252 Coroutine->CoroutineStmts.push_back(Res);
Richard Smithcfd53b42015-10-22 06:13:50 +0000253 return Res;
254}
255
Richard Smith23da82c2015-11-20 22:40:06 +0000256static ExprResult buildYieldValueCall(Sema &S, FunctionScopeInfo *Coroutine,
257 SourceLocation Loc, Expr *E) {
258 assert(Coroutine->CoroutinePromise && "no promise for coroutine");
259
260 // Form a reference to the promise.
261 auto *Promise = Coroutine->CoroutinePromise;
262 ExprResult PromiseRef = S.BuildDeclRefExpr(
263 Promise, Promise->getType().getNonReferenceType(), VK_LValue, Loc);
264 if (PromiseRef.isInvalid())
265 return ExprError();
266
267 // Call 'yield_value', passing in E.
268 return buildMemberCall(S, PromiseRef.get(), Loc, "yield_value", E);
269}
270
Richard Smith9f690bd2015-10-27 06:02:45 +0000271ExprResult Sema::ActOnCoyieldExpr(Scope *S, SourceLocation Loc, Expr *E) {
Richard Smith10610f72015-11-20 22:57:24 +0000272 if (E->getType()->isPlaceholderType()) {
273 ExprResult R = CheckPlaceholderExpr(E);
274 if (R.isInvalid()) return ExprError();
275 E = R.get();
276 }
277
Richard Smith23da82c2015-11-20 22:40:06 +0000278 auto *Coroutine = checkCoroutineContext(*this, Loc, "co_yield");
279 if (!Coroutine)
280 return ExprError();
281
282 // Build yield_value call.
283 ExprResult Awaitable = buildYieldValueCall(*this, Coroutine, Loc, E);
Richard Smith9f690bd2015-10-27 06:02:45 +0000284 if (Awaitable.isInvalid())
285 return ExprError();
Richard Smith23da82c2015-11-20 22:40:06 +0000286
287 // Build 'operator co_await' call.
288 Awaitable = buildOperatorCoawaitCall(*this, S, Loc, Awaitable.get());
289 if (Awaitable.isInvalid())
290 return ExprError();
291
Richard Smith9f690bd2015-10-27 06:02:45 +0000292 return BuildCoyieldExpr(Loc, Awaitable.get());
293}
294ExprResult Sema::BuildCoyieldExpr(SourceLocation Loc, Expr *E) {
295 auto *Coroutine = checkCoroutineContext(*this, Loc, "co_yield");
Richard Smith744b2242015-11-20 02:54:01 +0000296 if (!Coroutine)
297 return ExprError();
Richard Smithcfd53b42015-10-22 06:13:50 +0000298
Richard Smith10610f72015-11-20 22:57:24 +0000299 if (E->getType()->isPlaceholderType()) {
300 ExprResult R = CheckPlaceholderExpr(E);
301 if (R.isInvalid()) return ExprError();
302 E = R.get();
303 }
304
Richard Smithd7bed4d2015-11-22 02:57:17 +0000305 if (E->getType()->isDependentType()) {
306 Expr *Res = new (Context) CoyieldExpr(Loc, Context.DependentTy, E);
307 Coroutine->CoroutineStmts.push_back(Res);
308 return Res;
309 }
310
Richard Smith1f38edd2015-11-22 03:13:02 +0000311 // If the expression is a temporary, materialize it as an lvalue so that we
312 // can use it multiple times.
313 if (E->getValueKind() == VK_RValue)
314 E = new (Context) MaterializeTemporaryExpr(E->getType(), E, true);
Richard Smithd7bed4d2015-11-22 02:57:17 +0000315
316 // Build the await_ready, await_suspend, await_resume calls.
317 ReadySuspendResumeResult RSS = buildCoawaitCalls(*this, Loc, E);
318 if (RSS.IsInvalid)
319 return ExprError();
320
321 Expr *Res = new (Context) CoyieldExpr(Loc, E, RSS.Results[0], RSS.Results[1],
322 RSS.Results[2]);
Richard Smith744b2242015-11-20 02:54:01 +0000323 Coroutine->CoroutineStmts.push_back(Res);
Richard Smithcfd53b42015-10-22 06:13:50 +0000324 return Res;
325}
326
327StmtResult Sema::ActOnCoreturnStmt(SourceLocation Loc, Expr *E) {
Richard Smith9f690bd2015-10-27 06:02:45 +0000328 return BuildCoreturnStmt(Loc, E);
329}
330StmtResult Sema::BuildCoreturnStmt(SourceLocation Loc, Expr *E) {
Richard Smith10610f72015-11-20 22:57:24 +0000331 if (E && E->getType()->isPlaceholderType()) {
332 ExprResult R = CheckPlaceholderExpr(E);
333 if (R.isInvalid()) return StmtError();
334 E = R.get();
335 }
336
Richard Smith9f690bd2015-10-27 06:02:45 +0000337 auto *Coroutine = checkCoroutineContext(*this, Loc, "co_return");
Richard Smith744b2242015-11-20 02:54:01 +0000338 if (!Coroutine)
339 return StmtError();
Richard Smithcfd53b42015-10-22 06:13:50 +0000340
Richard Smith9f690bd2015-10-27 06:02:45 +0000341 // FIXME: Build return_* calls.
342 Stmt *Res = new (Context) CoreturnStmt(Loc, E);
Richard Smith744b2242015-11-20 02:54:01 +0000343 Coroutine->CoroutineStmts.push_back(Res);
Richard Smithcfd53b42015-10-22 06:13:50 +0000344 return Res;
345}
346
347void Sema::CheckCompletedCoroutineBody(FunctionDecl *FD, Stmt *Body) {
348 FunctionScopeInfo *Fn = getCurFunction();
349 assert(Fn && !Fn->CoroutineStmts.empty() && "not a coroutine");
350
351 // Coroutines [stmt.return]p1:
352 // A return statement shall not appear in a coroutine.
Richard Smith9f690bd2015-10-27 06:02:45 +0000353 if (Fn->FirstReturnLoc.isValid()) {
354 Diag(Fn->FirstReturnLoc, diag::err_return_in_coroutine);
Richard Smithcfd53b42015-10-22 06:13:50 +0000355 auto *First = Fn->CoroutineStmts[0];
356 Diag(First->getLocStart(), diag::note_declared_coroutine_here)
Richard Smith9f690bd2015-10-27 06:02:45 +0000357 << (isa<CoawaitExpr>(First) ? 0 :
358 isa<CoyieldExpr>(First) ? 1 : 2);
Richard Smithcfd53b42015-10-22 06:13:50 +0000359 }
360
361 bool AnyCoawaits = false;
362 bool AnyCoyields = false;
363 for (auto *CoroutineStmt : Fn->CoroutineStmts) {
Richard Smith9f690bd2015-10-27 06:02:45 +0000364 AnyCoawaits |= isa<CoawaitExpr>(CoroutineStmt);
365 AnyCoyields |= isa<CoyieldExpr>(CoroutineStmt);
Richard Smithcfd53b42015-10-22 06:13:50 +0000366 }
367
368 if (!AnyCoawaits && !AnyCoyields)
369 Diag(Fn->CoroutineStmts.front()->getLocStart(),
Richard Smith9f690bd2015-10-27 06:02:45 +0000370 diag::ext_coroutine_without_co_await_co_yield);
Richard Smithcfd53b42015-10-22 06:13:50 +0000371
Richard Smith9f690bd2015-10-27 06:02:45 +0000372 // FIXME: Perform analysis of initial and final suspend,
373 // and set_exception call.
Richard Smithcfd53b42015-10-22 06:13:50 +0000374}