blob: 31bef09ee9a17fa672f25e61b08103ddd0b761b4 [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"
Richard Smith2af65c42015-11-24 02:34:39 +000019#include "clang/Sema/Initialization.h"
Richard Smith9f690bd2015-10-27 06:02:45 +000020#include "clang/Sema/Overload.h"
Richard Smithcfd53b42015-10-22 06:13:50 +000021using namespace clang;
22using namespace sema;
23
Richard Smith9f690bd2015-10-27 06:02:45 +000024/// Look up the std::coroutine_traits<...>::promise_type for the given
25/// function type.
26static QualType lookupPromiseType(Sema &S, const FunctionProtoType *FnType,
Eric Fiselier89bf0e72017-03-06 22:52:28 +000027 SourceLocation KwLoc,
28 SourceLocation FuncLoc) {
Richard Smith9f690bd2015-10-27 06:02:45 +000029 // FIXME: Cache std::coroutine_traits once we've found it.
Gor Nishanov3e048bb2016-10-04 00:31:16 +000030 NamespaceDecl *StdExp = S.lookupStdExperimentalNamespace();
31 if (!StdExp) {
Eric Fiselier89bf0e72017-03-06 22:52:28 +000032 S.Diag(KwLoc, diag::err_implied_std_coroutine_traits_not_found);
Richard Smith9f690bd2015-10-27 06:02:45 +000033 return QualType();
34 }
35
36 LookupResult Result(S, &S.PP.getIdentifierTable().get("coroutine_traits"),
Eric Fiselier89bf0e72017-03-06 22:52:28 +000037 FuncLoc, Sema::LookupOrdinaryName);
Gor Nishanov3e048bb2016-10-04 00:31:16 +000038 if (!S.LookupQualifiedName(Result, StdExp)) {
Eric Fiselier89bf0e72017-03-06 22:52:28 +000039 S.Diag(KwLoc, diag::err_implied_std_coroutine_traits_not_found);
Richard Smith9f690bd2015-10-27 06:02:45 +000040 return QualType();
41 }
42
43 ClassTemplateDecl *CoroTraits = Result.getAsSingle<ClassTemplateDecl>();
44 if (!CoroTraits) {
45 Result.suppressDiagnostics();
46 // We found something weird. Complain about the first thing we found.
47 NamedDecl *Found = *Result.begin();
48 S.Diag(Found->getLocation(), diag::err_malformed_std_coroutine_traits);
49 return QualType();
50 }
51
52 // Form template argument list for coroutine_traits<R, P1, P2, ...>.
Eric Fiselier89bf0e72017-03-06 22:52:28 +000053 TemplateArgumentListInfo Args(KwLoc, KwLoc);
Richard Smith9f690bd2015-10-27 06:02:45 +000054 Args.addArgument(TemplateArgumentLoc(
55 TemplateArgument(FnType->getReturnType()),
Eric Fiselier89bf0e72017-03-06 22:52:28 +000056 S.Context.getTrivialTypeSourceInfo(FnType->getReturnType(), KwLoc)));
Richard Smith71d403e2015-11-22 07:33:28 +000057 // FIXME: If the function is a non-static member function, add the type
58 // of the implicit object parameter before the formal parameters.
Richard Smith9f690bd2015-10-27 06:02:45 +000059 for (QualType T : FnType->getParamTypes())
60 Args.addArgument(TemplateArgumentLoc(
Eric Fiselier89bf0e72017-03-06 22:52:28 +000061 TemplateArgument(T), S.Context.getTrivialTypeSourceInfo(T, KwLoc)));
Richard Smith9f690bd2015-10-27 06:02:45 +000062
63 // Build the template-id.
64 QualType CoroTrait =
Eric Fiselier89bf0e72017-03-06 22:52:28 +000065 S.CheckTemplateIdType(TemplateName(CoroTraits), KwLoc, Args);
Richard Smith9f690bd2015-10-27 06:02:45 +000066 if (CoroTrait.isNull())
67 return QualType();
Eric Fiselier89bf0e72017-03-06 22:52:28 +000068 if (S.RequireCompleteType(KwLoc, CoroTrait,
Richard Smith9f690bd2015-10-27 06:02:45 +000069 diag::err_coroutine_traits_missing_specialization))
70 return QualType();
71
Eric Fiselier89bf0e72017-03-06 22:52:28 +000072 auto *RD = CoroTrait->getAsCXXRecordDecl();
Richard Smith9f690bd2015-10-27 06:02:45 +000073 assert(RD && "specialization of class template is not a class?");
74
75 // Look up the ::promise_type member.
Eric Fiselier89bf0e72017-03-06 22:52:28 +000076 LookupResult R(S, &S.PP.getIdentifierTable().get("promise_type"), KwLoc,
Richard Smith9f690bd2015-10-27 06:02:45 +000077 Sema::LookupOrdinaryName);
78 S.LookupQualifiedName(R, RD);
79 auto *Promise = R.getAsSingle<TypeDecl>();
80 if (!Promise) {
Eric Fiselier89bf0e72017-03-06 22:52:28 +000081 S.Diag(FuncLoc,
82 diag::err_implied_std_coroutine_traits_promise_type_not_found)
Gor Nishanov8df64e92016-10-27 16:28:31 +000083 << RD;
Richard Smith9f690bd2015-10-27 06:02:45 +000084 return QualType();
85 }
Richard Smith9f690bd2015-10-27 06:02:45 +000086 // The promise type is required to be a class type.
87 QualType PromiseType = S.Context.getTypeDeclType(Promise);
Eric Fiselier89bf0e72017-03-06 22:52:28 +000088
89 auto buildElaboratedType = [&]() {
Gor Nishanov3e048bb2016-10-04 00:31:16 +000090 auto *NNS = NestedNameSpecifier::Create(S.Context, nullptr, StdExp);
Richard Smith9b2f53e2015-11-19 02:36:35 +000091 NNS = NestedNameSpecifier::Create(S.Context, NNS, false,
92 CoroTrait.getTypePtr());
Eric Fiselier89bf0e72017-03-06 22:52:28 +000093 return S.Context.getElaboratedType(ETK_None, NNS, PromiseType);
94 };
Richard Smith9b2f53e2015-11-19 02:36:35 +000095
Eric Fiselier89bf0e72017-03-06 22:52:28 +000096 if (!PromiseType->getAsCXXRecordDecl()) {
97 S.Diag(FuncLoc,
98 diag::err_implied_std_coroutine_traits_promise_type_not_class)
99 << buildElaboratedType();
Richard Smith9f690bd2015-10-27 06:02:45 +0000100 return QualType();
101 }
Eric Fiselier89bf0e72017-03-06 22:52:28 +0000102 if (S.RequireCompleteType(FuncLoc, buildElaboratedType(),
103 diag::err_coroutine_promise_type_incomplete))
104 return QualType();
Richard Smith9f690bd2015-10-27 06:02:45 +0000105
106 return PromiseType;
107}
108
Eric Fiselierc8efda72016-10-27 18:43:28 +0000109static bool isValidCoroutineContext(Sema &S, SourceLocation Loc,
110 StringRef Keyword) {
Richard Smith744b2242015-11-20 02:54:01 +0000111 // 'co_await' and 'co_yield' are not permitted in unevaluated operands.
112 if (S.isUnevaluatedContext()) {
113 S.Diag(Loc, diag::err_coroutine_unevaluated_context) << Keyword;
Eric Fiselierc8efda72016-10-27 18:43:28 +0000114 return false;
Richard Smith744b2242015-11-20 02:54:01 +0000115 }
Richard Smithcfd53b42015-10-22 06:13:50 +0000116
117 // Any other usage must be within a function.
118 auto *FD = dyn_cast<FunctionDecl>(S.CurContext);
119 if (!FD) {
120 S.Diag(Loc, isa<ObjCMethodDecl>(S.CurContext)
121 ? diag::err_coroutine_objc_method
122 : diag::err_coroutine_outside_function) << Keyword;
Eric Fiselierc8efda72016-10-27 18:43:28 +0000123 return false;
Richard Smithcfd53b42015-10-22 06:13:50 +0000124 }
125
Eric Fiselierc8efda72016-10-27 18:43:28 +0000126 // An enumeration for mapping the diagnostic type to the correct diagnostic
127 // selection index.
128 enum InvalidFuncDiag {
129 DiagCtor = 0,
130 DiagDtor,
131 DiagCopyAssign,
132 DiagMoveAssign,
133 DiagMain,
134 DiagConstexpr,
135 DiagAutoRet,
136 DiagVarargs,
137 };
138 bool Diagnosed = false;
139 auto DiagInvalid = [&](InvalidFuncDiag ID) {
140 S.Diag(Loc, diag::err_coroutine_invalid_func_context) << ID << Keyword;
141 Diagnosed = true;
142 return false;
143 };
144
145 // Diagnose when a constructor, destructor, copy/move assignment operator,
146 // or the function 'main' are declared as a coroutine.
147 auto *MD = dyn_cast<CXXMethodDecl>(FD);
148 if (MD && isa<CXXConstructorDecl>(MD))
149 return DiagInvalid(DiagCtor);
150 else if (MD && isa<CXXDestructorDecl>(MD))
151 return DiagInvalid(DiagDtor);
152 else if (MD && MD->isCopyAssignmentOperator())
153 return DiagInvalid(DiagCopyAssign);
154 else if (MD && MD->isMoveAssignmentOperator())
155 return DiagInvalid(DiagMoveAssign);
156 else if (FD->isMain())
157 return DiagInvalid(DiagMain);
158
159 // Emit a diagnostics for each of the following conditions which is not met.
160 if (FD->isConstexpr())
161 DiagInvalid(DiagConstexpr);
162 if (FD->getReturnType()->isUndeducedType())
163 DiagInvalid(DiagAutoRet);
164 if (FD->isVariadic())
165 DiagInvalid(DiagVarargs);
166
167 return !Diagnosed;
168}
169
170/// Check that this is a context in which a coroutine suspension can appear.
171static FunctionScopeInfo *checkCoroutineContext(Sema &S, SourceLocation Loc,
172 StringRef Keyword) {
173 if (!isValidCoroutineContext(S, Loc, Keyword))
174 return nullptr;
175
176 assert(isa<FunctionDecl>(S.CurContext) && "not in a function scope");
177 auto *FD = cast<FunctionDecl>(S.CurContext);
178 auto *ScopeInfo = S.getCurFunction();
179 assert(ScopeInfo && "missing function scope for function");
180
181 // If we don't have a promise variable, build one now.
182 if (!ScopeInfo->CoroutinePromise) {
183 QualType T = FD->getType()->isDependentType()
184 ? S.Context.DependentTy
185 : lookupPromiseType(
Eric Fiselier89bf0e72017-03-06 22:52:28 +0000186 S, FD->getType()->castAs<FunctionProtoType>(),
187 Loc, FD->getLocation());
Eric Fiselierc8efda72016-10-27 18:43:28 +0000188 if (T.isNull())
189 return nullptr;
190
191 // Create and default-initialize the promise.
192 ScopeInfo->CoroutinePromise =
193 VarDecl::Create(S.Context, FD, FD->getLocation(), FD->getLocation(),
194 &S.PP.getIdentifierTable().get("__promise"), T,
195 S.Context.getTrivialTypeSourceInfo(T, Loc), SC_None);
196 S.CheckVariableDeclarationType(ScopeInfo->CoroutinePromise);
197 if (!ScopeInfo->CoroutinePromise->isInvalidDecl())
Richard Smith3beb7c62017-01-12 02:27:38 +0000198 S.ActOnUninitializedDecl(ScopeInfo->CoroutinePromise);
Eric Fiselierc8efda72016-10-27 18:43:28 +0000199 }
200
201 return ScopeInfo;
Richard Smithcfd53b42015-10-22 06:13:50 +0000202}
203
Gor Nishanov8df64e92016-10-27 16:28:31 +0000204static Expr *buildBuiltinCall(Sema &S, SourceLocation Loc, Builtin::ID Id,
205 MutableArrayRef<Expr *> CallArgs) {
206 StringRef Name = S.Context.BuiltinInfo.getName(Id);
207 LookupResult R(S, &S.Context.Idents.get(Name), Loc, Sema::LookupOrdinaryName);
208 S.LookupName(R, S.TUScope, /*AllowBuiltinCreation=*/true);
209
210 auto *BuiltInDecl = R.getAsSingle<FunctionDecl>();
211 assert(BuiltInDecl && "failed to find builtin declaration");
212
213 ExprResult DeclRef =
214 S.BuildDeclRefExpr(BuiltInDecl, BuiltInDecl->getType(), VK_LValue, Loc);
215 assert(DeclRef.isUsable() && "Builtin reference cannot fail");
216
217 ExprResult Call =
218 S.ActOnCallExpr(/*Scope=*/nullptr, DeclRef.get(), Loc, CallArgs, Loc);
219
220 assert(!Call.isInvalid() && "Call to builtin cannot fail!");
221 return Call.get();
222}
223
Richard Smith9f690bd2015-10-27 06:02:45 +0000224/// Build a call to 'operator co_await' if there is a suitable operator for
225/// the given expression.
226static ExprResult buildOperatorCoawaitCall(Sema &SemaRef, Scope *S,
227 SourceLocation Loc, Expr *E) {
228 UnresolvedSet<16> Functions;
229 SemaRef.LookupOverloadedOperatorName(OO_Coawait, S, E->getType(), QualType(),
230 Functions);
231 return SemaRef.CreateOverloadedUnaryOp(Loc, UO_Coawait, Functions, E);
232}
Richard Smithcfd53b42015-10-22 06:13:50 +0000233
Richard Smith9f690bd2015-10-27 06:02:45 +0000234struct ReadySuspendResumeResult {
235 bool IsInvalid;
236 Expr *Results[3];
237};
238
Richard Smith23da82c2015-11-20 22:40:06 +0000239static ExprResult buildMemberCall(Sema &S, Expr *Base, SourceLocation Loc,
240 StringRef Name,
241 MutableArrayRef<Expr *> Args) {
242 DeclarationNameInfo NameInfo(&S.PP.getIdentifierTable().get(Name), Loc);
243
244 // FIXME: Fix BuildMemberReferenceExpr to take a const CXXScopeSpec&.
245 CXXScopeSpec SS;
246 ExprResult Result = S.BuildMemberReferenceExpr(
247 Base, Base->getType(), Loc, /*IsPtr=*/false, SS,
248 SourceLocation(), nullptr, NameInfo, /*TemplateArgs=*/nullptr,
249 /*Scope=*/nullptr);
250 if (Result.isInvalid())
251 return ExprError();
252
253 return S.ActOnCallExpr(nullptr, Result.get(), Loc, Args, Loc, nullptr);
254}
255
Richard Smith9f690bd2015-10-27 06:02:45 +0000256/// Build calls to await_ready, await_suspend, and await_resume for a co_await
257/// expression.
258static ReadySuspendResumeResult buildCoawaitCalls(Sema &S, SourceLocation Loc,
259 Expr *E) {
260 // Assume invalid until we see otherwise.
261 ReadySuspendResumeResult Calls = {true, {}};
262
263 const StringRef Funcs[] = {"await_ready", "await_suspend", "await_resume"};
264 for (size_t I = 0, N = llvm::array_lengthof(Funcs); I != N; ++I) {
Richard Smith9f690bd2015-10-27 06:02:45 +0000265 Expr *Operand = new (S.Context) OpaqueValueExpr(
Gor Nishanov8df64e92016-10-27 16:28:31 +0000266 Loc, E->getType(), VK_LValue, E->getObjectKind(), E);
Richard Smith9f690bd2015-10-27 06:02:45 +0000267
Richard Smith9f690bd2015-10-27 06:02:45 +0000268 // FIXME: Pass coroutine handle to await_suspend.
Richard Smith23da82c2015-11-20 22:40:06 +0000269 ExprResult Result = buildMemberCall(S, Operand, Loc, Funcs[I], None);
Richard Smith9f690bd2015-10-27 06:02:45 +0000270 if (Result.isInvalid())
271 return Calls;
272 Calls.Results[I] = Result.get();
273 }
274
275 Calls.IsInvalid = false;
276 return Calls;
277}
278
279ExprResult Sema::ActOnCoawaitExpr(Scope *S, SourceLocation Loc, Expr *E) {
Eric Fiseliera5465282016-09-29 21:47:39 +0000280 auto *Coroutine = checkCoroutineContext(*this, Loc, "co_await");
281 if (!Coroutine) {
282 CorrectDelayedTyposInExpr(E);
283 return ExprError();
284 }
Richard Smith10610f72015-11-20 22:57:24 +0000285 if (E->getType()->isPlaceholderType()) {
286 ExprResult R = CheckPlaceholderExpr(E);
287 if (R.isInvalid()) return ExprError();
288 E = R.get();
289 }
290
Richard Smith9f690bd2015-10-27 06:02:45 +0000291 ExprResult Awaitable = buildOperatorCoawaitCall(*this, S, Loc, E);
292 if (Awaitable.isInvalid())
293 return ExprError();
Eric Fiseliera5465282016-09-29 21:47:39 +0000294
Richard Smith9f690bd2015-10-27 06:02:45 +0000295 return BuildCoawaitExpr(Loc, Awaitable.get());
296}
297ExprResult Sema::BuildCoawaitExpr(SourceLocation Loc, Expr *E) {
298 auto *Coroutine = checkCoroutineContext(*this, Loc, "co_await");
Richard Smith744b2242015-11-20 02:54:01 +0000299 if (!Coroutine)
300 return ExprError();
Richard Smith9f690bd2015-10-27 06:02:45 +0000301
Richard Smith9f690bd2015-10-27 06:02:45 +0000302 if (E->getType()->isPlaceholderType()) {
303 ExprResult R = CheckPlaceholderExpr(E);
304 if (R.isInvalid()) return ExprError();
305 E = R.get();
306 }
307
Richard Smith10610f72015-11-20 22:57:24 +0000308 if (E->getType()->isDependentType()) {
309 Expr *Res = new (Context) CoawaitExpr(Loc, Context.DependentTy, E);
310 Coroutine->CoroutineStmts.push_back(Res);
311 return Res;
312 }
313
Richard Smith1f38edd2015-11-22 03:13:02 +0000314 // If the expression is a temporary, materialize it as an lvalue so that we
315 // can use it multiple times.
316 if (E->getValueKind() == VK_RValue)
Tim Shen4a05bb82016-06-21 20:29:17 +0000317 E = CreateMaterializeTemporaryExpr(E->getType(), E, true);
Richard Smith9f690bd2015-10-27 06:02:45 +0000318
319 // Build the await_ready, await_suspend, await_resume calls.
320 ReadySuspendResumeResult RSS = buildCoawaitCalls(*this, Loc, E);
321 if (RSS.IsInvalid)
322 return ExprError();
323
324 Expr *Res = new (Context) CoawaitExpr(Loc, E, RSS.Results[0], RSS.Results[1],
325 RSS.Results[2]);
Richard Smith744b2242015-11-20 02:54:01 +0000326 Coroutine->CoroutineStmts.push_back(Res);
Richard Smithcfd53b42015-10-22 06:13:50 +0000327 return Res;
328}
329
Richard Smith4ba66602015-11-22 07:05:16 +0000330static ExprResult buildPromiseCall(Sema &S, FunctionScopeInfo *Coroutine,
331 SourceLocation Loc, StringRef Name,
332 MutableArrayRef<Expr *> Args) {
Richard Smith23da82c2015-11-20 22:40:06 +0000333 assert(Coroutine->CoroutinePromise && "no promise for coroutine");
334
335 // Form a reference to the promise.
336 auto *Promise = Coroutine->CoroutinePromise;
337 ExprResult PromiseRef = S.BuildDeclRefExpr(
338 Promise, Promise->getType().getNonReferenceType(), VK_LValue, Loc);
339 if (PromiseRef.isInvalid())
340 return ExprError();
341
342 // Call 'yield_value', passing in E.
Richard Smith4ba66602015-11-22 07:05:16 +0000343 return buildMemberCall(S, PromiseRef.get(), Loc, Name, Args);
Richard Smith23da82c2015-11-20 22:40:06 +0000344}
345
Richard Smith9f690bd2015-10-27 06:02:45 +0000346ExprResult Sema::ActOnCoyieldExpr(Scope *S, SourceLocation Loc, Expr *E) {
Richard Smith23da82c2015-11-20 22:40:06 +0000347 auto *Coroutine = checkCoroutineContext(*this, Loc, "co_yield");
Eric Fiseliera5465282016-09-29 21:47:39 +0000348 if (!Coroutine) {
349 CorrectDelayedTyposInExpr(E);
Richard Smith23da82c2015-11-20 22:40:06 +0000350 return ExprError();
Eric Fiseliera5465282016-09-29 21:47:39 +0000351 }
Richard Smith23da82c2015-11-20 22:40:06 +0000352
353 // Build yield_value call.
Richard Smith4ba66602015-11-22 07:05:16 +0000354 ExprResult Awaitable =
355 buildPromiseCall(*this, Coroutine, Loc, "yield_value", E);
Richard Smith9f690bd2015-10-27 06:02:45 +0000356 if (Awaitable.isInvalid())
357 return ExprError();
Richard Smith23da82c2015-11-20 22:40:06 +0000358
359 // Build 'operator co_await' call.
360 Awaitable = buildOperatorCoawaitCall(*this, S, Loc, Awaitable.get());
361 if (Awaitable.isInvalid())
362 return ExprError();
363
Richard Smith9f690bd2015-10-27 06:02:45 +0000364 return BuildCoyieldExpr(Loc, Awaitable.get());
365}
366ExprResult Sema::BuildCoyieldExpr(SourceLocation Loc, Expr *E) {
367 auto *Coroutine = checkCoroutineContext(*this, Loc, "co_yield");
Richard Smith744b2242015-11-20 02:54:01 +0000368 if (!Coroutine)
369 return ExprError();
Richard Smithcfd53b42015-10-22 06:13:50 +0000370
Richard Smith10610f72015-11-20 22:57:24 +0000371 if (E->getType()->isPlaceholderType()) {
372 ExprResult R = CheckPlaceholderExpr(E);
373 if (R.isInvalid()) return ExprError();
374 E = R.get();
375 }
376
Richard Smithd7bed4d2015-11-22 02:57:17 +0000377 if (E->getType()->isDependentType()) {
378 Expr *Res = new (Context) CoyieldExpr(Loc, Context.DependentTy, E);
379 Coroutine->CoroutineStmts.push_back(Res);
380 return Res;
381 }
382
Richard Smith1f38edd2015-11-22 03:13:02 +0000383 // If the expression is a temporary, materialize it as an lvalue so that we
384 // can use it multiple times.
385 if (E->getValueKind() == VK_RValue)
Tim Shen4a05bb82016-06-21 20:29:17 +0000386 E = CreateMaterializeTemporaryExpr(E->getType(), E, true);
Richard Smithd7bed4d2015-11-22 02:57:17 +0000387
388 // Build the await_ready, await_suspend, await_resume calls.
389 ReadySuspendResumeResult RSS = buildCoawaitCalls(*this, Loc, E);
390 if (RSS.IsInvalid)
391 return ExprError();
392
393 Expr *Res = new (Context) CoyieldExpr(Loc, E, RSS.Results[0], RSS.Results[1],
394 RSS.Results[2]);
Richard Smith744b2242015-11-20 02:54:01 +0000395 Coroutine->CoroutineStmts.push_back(Res);
Richard Smithcfd53b42015-10-22 06:13:50 +0000396 return Res;
397}
398
399StmtResult Sema::ActOnCoreturnStmt(SourceLocation Loc, Expr *E) {
Eric Fiseliera5465282016-09-29 21:47:39 +0000400 auto *Coroutine = checkCoroutineContext(*this, Loc, "co_return");
401 if (!Coroutine) {
402 CorrectDelayedTyposInExpr(E);
403 return StmtError();
404 }
Richard Smith9f690bd2015-10-27 06:02:45 +0000405 return BuildCoreturnStmt(Loc, E);
406}
Gor Nishanov3e048bb2016-10-04 00:31:16 +0000407
Richard Smith9f690bd2015-10-27 06:02:45 +0000408StmtResult Sema::BuildCoreturnStmt(SourceLocation Loc, Expr *E) {
Richard Smith71d403e2015-11-22 07:33:28 +0000409 auto *Coroutine = checkCoroutineContext(*this, Loc, "co_return");
410 if (!Coroutine)
411 return StmtError();
412
413 if (E && E->getType()->isPlaceholderType() &&
414 !E->getType()->isSpecificPlaceholderType(BuiltinType::Overload)) {
Richard Smith10610f72015-11-20 22:57:24 +0000415 ExprResult R = CheckPlaceholderExpr(E);
416 if (R.isInvalid()) return StmtError();
417 E = R.get();
418 }
419
Richard Smith4ba66602015-11-22 07:05:16 +0000420 // FIXME: If the operand is a reference to a variable that's about to go out
Richard Smith2af65c42015-11-24 02:34:39 +0000421 // of scope, we should treat the operand as an xvalue for this overload
Richard Smith4ba66602015-11-22 07:05:16 +0000422 // resolution.
423 ExprResult PC;
Eric Fiselier98131312016-10-06 21:23:38 +0000424 if (E && (isa<InitListExpr>(E) || !E->getType()->isVoidType())) {
Richard Smith4ba66602015-11-22 07:05:16 +0000425 PC = buildPromiseCall(*this, Coroutine, Loc, "return_value", E);
426 } else {
427 E = MakeFullDiscardedValueExpr(E).get();
428 PC = buildPromiseCall(*this, Coroutine, Loc, "return_void", None);
429 }
430 if (PC.isInvalid())
431 return StmtError();
432
433 Expr *PCE = ActOnFinishFullExpr(PC.get()).get();
434
435 Stmt *Res = new (Context) CoreturnStmt(Loc, E, PCE);
Richard Smith744b2242015-11-20 02:54:01 +0000436 Coroutine->CoroutineStmts.push_back(Res);
Richard Smithcfd53b42015-10-22 06:13:50 +0000437 return Res;
438}
439
Eric Fiselier709d1b32016-10-27 07:30:31 +0000440static ExprResult buildStdCurrentExceptionCall(Sema &S, SourceLocation Loc) {
441 NamespaceDecl *Std = S.getStdNamespace();
442 if (!Std) {
443 S.Diag(Loc, diag::err_implied_std_current_exception_not_found);
444 return ExprError();
445 }
446 LookupResult Result(S, &S.PP.getIdentifierTable().get("current_exception"),
447 Loc, Sema::LookupOrdinaryName);
448 if (!S.LookupQualifiedName(Result, Std)) {
449 S.Diag(Loc, diag::err_implied_std_current_exception_not_found);
450 return ExprError();
451 }
452
453 // FIXME The STL is free to provide more than one overload.
454 FunctionDecl *FD = Result.getAsSingle<FunctionDecl>();
455 if (!FD) {
456 S.Diag(Loc, diag::err_malformed_std_current_exception);
457 return ExprError();
458 }
459 ExprResult Res = S.BuildDeclRefExpr(FD, FD->getType(), VK_LValue, Loc);
460 Res = S.ActOnCallExpr(/*Scope*/ nullptr, Res.get(), Loc, None, Loc);
461 if (Res.isInvalid()) {
462 S.Diag(Loc, diag::err_malformed_std_current_exception);
463 return ExprError();
464 }
465 return Res;
466}
467
Gor Nishanov8df64e92016-10-27 16:28:31 +0000468// Find an appropriate delete for the promise.
469static FunctionDecl *findDeleteForPromise(Sema &S, SourceLocation Loc,
470 QualType PromiseType) {
471 FunctionDecl *OperatorDelete = nullptr;
472
473 DeclarationName DeleteName =
474 S.Context.DeclarationNames.getCXXOperatorName(OO_Delete);
475
476 auto *PointeeRD = PromiseType->getAsCXXRecordDecl();
477 assert(PointeeRD && "PromiseType must be a CxxRecordDecl type");
478
479 if (S.FindDeallocationFunction(Loc, PointeeRD, DeleteName, OperatorDelete))
480 return nullptr;
481
482 if (!OperatorDelete) {
483 // Look for a global declaration.
484 const bool CanProvideSize = S.isCompleteType(Loc, PromiseType);
485 const bool Overaligned = false;
486 OperatorDelete = S.FindUsualDeallocationFunction(Loc, CanProvideSize,
487 Overaligned, DeleteName);
488 }
489 S.MarkFunctionReferenced(Loc, OperatorDelete);
490 return OperatorDelete;
491}
492
493// Builds allocation and deallocation for the coroutine. Returns false on
494// failure.
495static bool buildAllocationAndDeallocation(Sema &S, SourceLocation Loc,
496 FunctionScopeInfo *Fn,
497 Expr *&Allocation,
Gor Nishanovbbe1c072017-02-13 05:05:02 +0000498 Expr *&Deallocation) {
Gor Nishanov8df64e92016-10-27 16:28:31 +0000499 TypeSourceInfo *TInfo = Fn->CoroutinePromise->getTypeSourceInfo();
500 QualType PromiseType = TInfo->getType();
501 if (PromiseType->isDependentType())
502 return true;
503
504 if (S.RequireCompleteType(Loc, PromiseType, diag::err_incomplete_type))
505 return false;
506
507 // FIXME: Add support for get_return_object_on_allocation failure.
508 // FIXME: Add support for stateful allocators.
509
510 FunctionDecl *OperatorNew = nullptr;
511 FunctionDecl *OperatorDelete = nullptr;
512 FunctionDecl *UnusedResult = nullptr;
513 bool PassAlignment = false;
514
515 S.FindAllocationFunctions(Loc, SourceRange(),
516 /*UseGlobal*/ false, PromiseType,
517 /*isArray*/ false, PassAlignment,
518 /*PlacementArgs*/ None, OperatorNew, UnusedResult);
519
520 OperatorDelete = findDeleteForPromise(S, Loc, PromiseType);
521
522 if (!OperatorDelete || !OperatorNew)
523 return false;
524
525 Expr *FramePtr =
526 buildBuiltinCall(S, Loc, Builtin::BI__builtin_coro_frame, {});
527
528 Expr *FrameSize =
529 buildBuiltinCall(S, Loc, Builtin::BI__builtin_coro_size, {});
530
531 // Make new call.
532
533 ExprResult NewRef =
534 S.BuildDeclRefExpr(OperatorNew, OperatorNew->getType(), VK_LValue, Loc);
535 if (NewRef.isInvalid())
536 return false;
537
538 ExprResult NewExpr =
539 S.ActOnCallExpr(S.getCurScope(), NewRef.get(), Loc, FrameSize, Loc);
540 if (NewExpr.isInvalid())
541 return false;
542
543 Allocation = NewExpr.get();
544
545 // Make delete call.
546
547 QualType OpDeleteQualType = OperatorDelete->getType();
548
549 ExprResult DeleteRef =
550 S.BuildDeclRefExpr(OperatorDelete, OpDeleteQualType, VK_LValue, Loc);
551 if (DeleteRef.isInvalid())
552 return false;
553
554 Expr *CoroFree =
555 buildBuiltinCall(S, Loc, Builtin::BI__builtin_coro_free, {FramePtr});
556
557 SmallVector<Expr *, 2> DeleteArgs{CoroFree};
558
559 // Check if we need to pass the size.
560 const auto *OpDeleteType =
561 OpDeleteQualType.getTypePtr()->getAs<FunctionProtoType>();
562 if (OpDeleteType->getNumParams() > 1)
563 DeleteArgs.push_back(FrameSize);
564
565 ExprResult DeleteExpr =
566 S.ActOnCallExpr(S.getCurScope(), DeleteRef.get(), Loc, DeleteArgs, Loc);
567 if (DeleteExpr.isInvalid())
568 return false;
569
570 Deallocation = DeleteExpr.get();
571
572 return true;
573}
574
Gor Nishanovbbe1c072017-02-13 05:05:02 +0000575namespace {
576class SubStmtBuilder : public CoroutineBodyStmt::CtorArgs {
577 Sema &S;
578 FunctionDecl &FD;
579 FunctionScopeInfo &Fn;
580 bool IsValid;
581 SourceLocation Loc;
582 QualType RetType;
583 SmallVector<Stmt *, 4> ParamMovesVector;
584 const bool IsPromiseDependentType;
585 CXXRecordDecl *PromiseRecordDecl = nullptr;
586
587public:
588 SubStmtBuilder(Sema &S, FunctionDecl &FD, FunctionScopeInfo &Fn, Stmt *Body)
589 : S(S), FD(FD), Fn(Fn), Loc(FD.getLocation()),
590 IsPromiseDependentType(
591 !Fn.CoroutinePromise ||
592 Fn.CoroutinePromise->getType()->isDependentType()) {
593 this->Body = Body;
594 if (!IsPromiseDependentType) {
595 PromiseRecordDecl = Fn.CoroutinePromise->getType()->getAsCXXRecordDecl();
596 assert(PromiseRecordDecl && "Type should have already been checked");
597 }
598 this->IsValid = makePromiseStmt() && makeInitialSuspend() &&
599 makeFinalSuspend() && makeOnException() &&
600 makeOnFallthrough() && makeNewAndDeleteExpr() &&
601 makeReturnObject() && makeParamMoves();
602 }
603
604 bool isInvalid() const { return !this->IsValid; }
605
606 bool makePromiseStmt();
607 bool makeInitialSuspend();
608 bool makeFinalSuspend();
609 bool makeNewAndDeleteExpr();
610 bool makeOnFallthrough();
611 bool makeOnException();
612 bool makeReturnObject();
613 bool makeParamMoves();
614};
615}
616
Richard Smith2af65c42015-11-24 02:34:39 +0000617void Sema::CheckCompletedCoroutineBody(FunctionDecl *FD, Stmt *&Body) {
Richard Smithcfd53b42015-10-22 06:13:50 +0000618 FunctionScopeInfo *Fn = getCurFunction();
619 assert(Fn && !Fn->CoroutineStmts.empty() && "not a coroutine");
620
621 // Coroutines [stmt.return]p1:
622 // A return statement shall not appear in a coroutine.
Richard Smith9f690bd2015-10-27 06:02:45 +0000623 if (Fn->FirstReturnLoc.isValid()) {
624 Diag(Fn->FirstReturnLoc, diag::err_return_in_coroutine);
Richard Smithcfd53b42015-10-22 06:13:50 +0000625 auto *First = Fn->CoroutineStmts[0];
626 Diag(First->getLocStart(), diag::note_declared_coroutine_here)
Gor Nishanov8df64e92016-10-27 16:28:31 +0000627 << (isa<CoawaitExpr>(First) ? 0 :
628 isa<CoyieldExpr>(First) ? 1 : 2);
Richard Smithcfd53b42015-10-22 06:13:50 +0000629 }
Gor Nishanovbbe1c072017-02-13 05:05:02 +0000630 SubStmtBuilder Builder(*this, *FD, *Fn, Body);
631 if (Builder.isInvalid())
632 return FD->setInvalidDecl();
Richard Smithcfd53b42015-10-22 06:13:50 +0000633
Gor Nishanovbbe1c072017-02-13 05:05:02 +0000634 // Build body for the coroutine wrapper statement.
635 Body = CoroutineBodyStmt::Create(Context, Builder);
636}
Richard Smith2af65c42015-11-24 02:34:39 +0000637
Gor Nishanovbbe1c072017-02-13 05:05:02 +0000638bool SubStmtBuilder::makePromiseStmt() {
Richard Smith2af65c42015-11-24 02:34:39 +0000639 // Form a declaration statement for the promise declaration, so that AST
640 // visitors can more easily find it.
641 StmtResult PromiseStmt =
Gor Nishanovbbe1c072017-02-13 05:05:02 +0000642 S.ActOnDeclStmt(S.ConvertDeclToDeclGroup(Fn.CoroutinePromise), Loc, Loc);
Richard Smith2af65c42015-11-24 02:34:39 +0000643 if (PromiseStmt.isInvalid())
Gor Nishanovbbe1c072017-02-13 05:05:02 +0000644 return false;
Richard Smith2af65c42015-11-24 02:34:39 +0000645
Gor Nishanovbbe1c072017-02-13 05:05:02 +0000646 this->Promise = PromiseStmt.get();
647 return true;
648}
649
650bool SubStmtBuilder::makeInitialSuspend() {
Richard Smith2af65c42015-11-24 02:34:39 +0000651 // Form and check implicit 'co_await p.initial_suspend();' statement.
652 ExprResult InitialSuspend =
Gor Nishanovbbe1c072017-02-13 05:05:02 +0000653 buildPromiseCall(S, &Fn, Loc, "initial_suspend", None);
Richard Smith2af65c42015-11-24 02:34:39 +0000654 // FIXME: Support operator co_await here.
655 if (!InitialSuspend.isInvalid())
Gor Nishanovbbe1c072017-02-13 05:05:02 +0000656 InitialSuspend = S.BuildCoawaitExpr(Loc, InitialSuspend.get());
657 InitialSuspend = S.ActOnFinishFullExpr(InitialSuspend.get());
Richard Smith2af65c42015-11-24 02:34:39 +0000658 if (InitialSuspend.isInvalid())
Gor Nishanovbbe1c072017-02-13 05:05:02 +0000659 return false;
Richard Smith2af65c42015-11-24 02:34:39 +0000660
Gor Nishanovbbe1c072017-02-13 05:05:02 +0000661 this->InitialSuspend = InitialSuspend.get();
662 return true;
663}
664
665bool SubStmtBuilder::makeFinalSuspend() {
Richard Smith2af65c42015-11-24 02:34:39 +0000666 // Form and check implicit 'co_await p.final_suspend();' statement.
667 ExprResult FinalSuspend =
Gor Nishanovbbe1c072017-02-13 05:05:02 +0000668 buildPromiseCall(S, &Fn, Loc, "final_suspend", None);
Richard Smith2af65c42015-11-24 02:34:39 +0000669 // FIXME: Support operator co_await here.
670 if (!FinalSuspend.isInvalid())
Gor Nishanovbbe1c072017-02-13 05:05:02 +0000671 FinalSuspend = S.BuildCoawaitExpr(Loc, FinalSuspend.get());
672 FinalSuspend = S.ActOnFinishFullExpr(FinalSuspend.get());
Richard Smith2af65c42015-11-24 02:34:39 +0000673 if (FinalSuspend.isInvalid())
Gor Nishanovbbe1c072017-02-13 05:05:02 +0000674 return false;
Richard Smith2af65c42015-11-24 02:34:39 +0000675
Gor Nishanovbbe1c072017-02-13 05:05:02 +0000676 this->FinalSuspend = FinalSuspend.get();
677 return true;
678}
679
680bool SubStmtBuilder::makeNewAndDeleteExpr() {
Gor Nishanov8df64e92016-10-27 16:28:31 +0000681 // Form and check allocation and deallocation calls.
Gor Nishanovbbe1c072017-02-13 05:05:02 +0000682 return buildAllocationAndDeallocation(S, Loc, &Fn, this->Allocate,
683 this->Deallocate);
684}
Gor Nishanov8df64e92016-10-27 16:28:31 +0000685
Gor Nishanovbbe1c072017-02-13 05:05:02 +0000686bool SubStmtBuilder::makeOnFallthrough() {
687 if (!PromiseRecordDecl)
688 return true;
689
690 // [dcl.fct.def.coroutine]/4
691 // The unqualified-ids 'return_void' and 'return_value' are looked up in
692 // the scope of class P. If both are found, the program is ill-formed.
693 DeclarationName RVoidDN = S.PP.getIdentifierInfo("return_void");
694 LookupResult RVoidResult(S, RVoidDN, Loc, Sema::LookupMemberName);
695 const bool HasRVoid = S.LookupQualifiedName(RVoidResult, PromiseRecordDecl);
696
697 DeclarationName RValueDN = S.PP.getIdentifierInfo("return_value");
698 LookupResult RValueResult(S, RValueDN, Loc, Sema::LookupMemberName);
699 const bool HasRValue = S.LookupQualifiedName(RValueResult, PromiseRecordDecl);
700
Eric Fiselier709d1b32016-10-27 07:30:31 +0000701 StmtResult Fallthrough;
Gor Nishanovbbe1c072017-02-13 05:05:02 +0000702 if (HasRVoid && HasRValue) {
703 // FIXME Improve this diagnostic
704 S.Diag(FD.getLocation(), diag::err_coroutine_promise_return_ill_formed)
705 << PromiseRecordDecl;
706 return false;
707 } else if (HasRVoid) {
708 // If the unqualified-id return_void is found, flowing off the end of a
709 // coroutine is equivalent to a co_return with no operand. Otherwise,
710 // flowing off the end of a coroutine results in undefined behavior.
711 Fallthrough = S.BuildCoreturnStmt(FD.getLocation(), nullptr);
712 Fallthrough = S.ActOnFinishFullStmt(Fallthrough.get());
713 if (Fallthrough.isInvalid())
714 return false;
Eric Fiselier709d1b32016-10-27 07:30:31 +0000715 }
Richard Smith2af65c42015-11-24 02:34:39 +0000716
Gor Nishanovbbe1c072017-02-13 05:05:02 +0000717 this->OnFallthrough = Fallthrough.get();
718 return true;
719}
720
721bool SubStmtBuilder::makeOnException() {
722 // Try to form 'p.set_exception(std::current_exception());' to handle
723 // uncaught exceptions.
724 // TODO: Post WG21 Issaquah 2016 renamed set_exception to unhandled_exception
725 // TODO: and dropped exception_ptr parameter. Make it so.
726
727 if (!PromiseRecordDecl)
728 return true;
729
730 // If exceptions are disabled, don't try to build OnException.
731 if (!S.getLangOpts().CXXExceptions)
732 return true;
733
734 ExprResult SetException;
735
736 // [dcl.fct.def.coroutine]/3
737 // The unqualified-id set_exception is found in the scope of P by class
738 // member access lookup (3.4.5).
739 DeclarationName SetExDN = S.PP.getIdentifierInfo("set_exception");
740 LookupResult SetExResult(S, SetExDN, Loc, Sema::LookupMemberName);
741 if (S.LookupQualifiedName(SetExResult, PromiseRecordDecl)) {
742 // Form the call 'p.set_exception(std::current_exception())'
743 SetException = buildStdCurrentExceptionCall(S, Loc);
744 if (SetException.isInvalid())
745 return false;
746 Expr *E = SetException.get();
747 SetException = buildPromiseCall(S, &Fn, Loc, "set_exception", E);
748 SetException = S.ActOnFinishFullExpr(SetException.get(), Loc);
749 if (SetException.isInvalid())
750 return false;
751 }
752
753 this->OnException = SetException.get();
754 return true;
755}
756
757bool SubStmtBuilder::makeReturnObject() {
758
Richard Smith2af65c42015-11-24 02:34:39 +0000759 // Build implicit 'p.get_return_object()' expression and form initialization
760 // of return type from it.
761 ExprResult ReturnObject =
Gor Nishanovbbe1c072017-02-13 05:05:02 +0000762 buildPromiseCall(S, &Fn, Loc, "get_return_object", None);
Richard Smith2af65c42015-11-24 02:34:39 +0000763 if (ReturnObject.isInvalid())
Gor Nishanovbbe1c072017-02-13 05:05:02 +0000764 return false;
765 QualType RetType = FD.getReturnType();
Richard Smith2af65c42015-11-24 02:34:39 +0000766 if (!RetType->isDependentType()) {
767 InitializedEntity Entity =
768 InitializedEntity::InitializeResult(Loc, RetType, false);
Gor Nishanovbbe1c072017-02-13 05:05:02 +0000769 ReturnObject = S.PerformMoveOrCopyInitialization(Entity, nullptr, RetType,
Richard Smith2af65c42015-11-24 02:34:39 +0000770 ReturnObject.get());
771 if (ReturnObject.isInvalid())
Gor Nishanovbbe1c072017-02-13 05:05:02 +0000772 return false;
Richard Smith2af65c42015-11-24 02:34:39 +0000773 }
Gor Nishanovbbe1c072017-02-13 05:05:02 +0000774 ReturnObject = S.ActOnFinishFullExpr(ReturnObject.get(), Loc);
Richard Smith2af65c42015-11-24 02:34:39 +0000775 if (ReturnObject.isInvalid())
Gor Nishanovbbe1c072017-02-13 05:05:02 +0000776 return false;
Richard Smith2af65c42015-11-24 02:34:39 +0000777
Gor Nishanovbbe1c072017-02-13 05:05:02 +0000778 this->ReturnValue = ReturnObject.get();
779 return true;
780}
781
782bool SubStmtBuilder::makeParamMoves() {
Richard Smith2af65c42015-11-24 02:34:39 +0000783 // FIXME: Perform move-initialization of parameters into frame-local copies.
Gor Nishanovbbe1c072017-02-13 05:05:02 +0000784 return true;
Richard Smithcfd53b42015-10-22 06:13:50 +0000785}