Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/clang/lib/Sema/SemaCoroutine.cpp
35234 views
1
//===-- SemaCoroutine.cpp - Semantic Analysis for Coroutines --------------===//
2
//
3
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4
// See https://llvm.org/LICENSE.txt for license information.
5
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6
//
7
//===----------------------------------------------------------------------===//
8
//
9
// This file implements semantic analysis for C++ Coroutines.
10
//
11
// This file contains references to sections of the Coroutines TS, which
12
// can be found at http://wg21.link/coroutines.
13
//
14
//===----------------------------------------------------------------------===//
15
16
#include "CoroutineStmtBuilder.h"
17
#include "clang/AST/ASTLambda.h"
18
#include "clang/AST/Decl.h"
19
#include "clang/AST/Expr.h"
20
#include "clang/AST/ExprCXX.h"
21
#include "clang/AST/StmtCXX.h"
22
#include "clang/Basic/Builtins.h"
23
#include "clang/Lex/Preprocessor.h"
24
#include "clang/Sema/EnterExpressionEvaluationContext.h"
25
#include "clang/Sema/Initialization.h"
26
#include "clang/Sema/Overload.h"
27
#include "clang/Sema/ScopeInfo.h"
28
#include "clang/Sema/SemaInternal.h"
29
#include "llvm/ADT/SmallSet.h"
30
31
using namespace clang;
32
using namespace sema;
33
34
static LookupResult lookupMember(Sema &S, const char *Name, CXXRecordDecl *RD,
35
SourceLocation Loc, bool &Res) {
36
DeclarationName DN = S.PP.getIdentifierInfo(Name);
37
LookupResult LR(S, DN, Loc, Sema::LookupMemberName);
38
// Suppress diagnostics when a private member is selected. The same warnings
39
// will be produced again when building the call.
40
LR.suppressDiagnostics();
41
Res = S.LookupQualifiedName(LR, RD);
42
return LR;
43
}
44
45
static bool lookupMember(Sema &S, const char *Name, CXXRecordDecl *RD,
46
SourceLocation Loc) {
47
bool Res;
48
lookupMember(S, Name, RD, Loc, Res);
49
return Res;
50
}
51
52
/// Look up the std::coroutine_traits<...>::promise_type for the given
53
/// function type.
54
static QualType lookupPromiseType(Sema &S, const FunctionDecl *FD,
55
SourceLocation KwLoc) {
56
const FunctionProtoType *FnType = FD->getType()->castAs<FunctionProtoType>();
57
const SourceLocation FuncLoc = FD->getLocation();
58
59
ClassTemplateDecl *CoroTraits =
60
S.lookupCoroutineTraits(KwLoc, FuncLoc);
61
if (!CoroTraits)
62
return QualType();
63
64
// Form template argument list for coroutine_traits<R, P1, P2, ...> according
65
// to [dcl.fct.def.coroutine]3
66
TemplateArgumentListInfo Args(KwLoc, KwLoc);
67
auto AddArg = [&](QualType T) {
68
Args.addArgument(TemplateArgumentLoc(
69
TemplateArgument(T), S.Context.getTrivialTypeSourceInfo(T, KwLoc)));
70
};
71
AddArg(FnType->getReturnType());
72
// If the function is a non-static member function, add the type
73
// of the implicit object parameter before the formal parameters.
74
if (auto *MD = dyn_cast<CXXMethodDecl>(FD)) {
75
if (MD->isImplicitObjectMemberFunction()) {
76
// [over.match.funcs]4
77
// For non-static member functions, the type of the implicit object
78
// parameter is
79
// -- "lvalue reference to cv X" for functions declared without a
80
// ref-qualifier or with the & ref-qualifier
81
// -- "rvalue reference to cv X" for functions declared with the &&
82
// ref-qualifier
83
QualType T = MD->getFunctionObjectParameterType();
84
T = FnType->getRefQualifier() == RQ_RValue
85
? S.Context.getRValueReferenceType(T)
86
: S.Context.getLValueReferenceType(T, /*SpelledAsLValue*/ true);
87
AddArg(T);
88
}
89
}
90
for (QualType T : FnType->getParamTypes())
91
AddArg(T);
92
93
// Build the template-id.
94
QualType CoroTrait =
95
S.CheckTemplateIdType(TemplateName(CoroTraits), KwLoc, Args);
96
if (CoroTrait.isNull())
97
return QualType();
98
if (S.RequireCompleteType(KwLoc, CoroTrait,
99
diag::err_coroutine_type_missing_specialization))
100
return QualType();
101
102
auto *RD = CoroTrait->getAsCXXRecordDecl();
103
assert(RD && "specialization of class template is not a class?");
104
105
// Look up the ::promise_type member.
106
LookupResult R(S, &S.PP.getIdentifierTable().get("promise_type"), KwLoc,
107
Sema::LookupOrdinaryName);
108
S.LookupQualifiedName(R, RD);
109
auto *Promise = R.getAsSingle<TypeDecl>();
110
if (!Promise) {
111
S.Diag(FuncLoc,
112
diag::err_implied_std_coroutine_traits_promise_type_not_found)
113
<< RD;
114
return QualType();
115
}
116
// The promise type is required to be a class type.
117
QualType PromiseType = S.Context.getTypeDeclType(Promise);
118
119
auto buildElaboratedType = [&]() {
120
auto *NNS = NestedNameSpecifier::Create(S.Context, nullptr, S.getStdNamespace());
121
NNS = NestedNameSpecifier::Create(S.Context, NNS, false,
122
CoroTrait.getTypePtr());
123
return S.Context.getElaboratedType(ElaboratedTypeKeyword::None, NNS,
124
PromiseType);
125
};
126
127
if (!PromiseType->getAsCXXRecordDecl()) {
128
S.Diag(FuncLoc,
129
diag::err_implied_std_coroutine_traits_promise_type_not_class)
130
<< buildElaboratedType();
131
return QualType();
132
}
133
if (S.RequireCompleteType(FuncLoc, buildElaboratedType(),
134
diag::err_coroutine_promise_type_incomplete))
135
return QualType();
136
137
return PromiseType;
138
}
139
140
/// Look up the std::coroutine_handle<PromiseType>.
141
static QualType lookupCoroutineHandleType(Sema &S, QualType PromiseType,
142
SourceLocation Loc) {
143
if (PromiseType.isNull())
144
return QualType();
145
146
NamespaceDecl *CoroNamespace = S.getStdNamespace();
147
assert(CoroNamespace && "Should already be diagnosed");
148
149
LookupResult Result(S, &S.PP.getIdentifierTable().get("coroutine_handle"),
150
Loc, Sema::LookupOrdinaryName);
151
if (!S.LookupQualifiedName(Result, CoroNamespace)) {
152
S.Diag(Loc, diag::err_implied_coroutine_type_not_found)
153
<< "std::coroutine_handle";
154
return QualType();
155
}
156
157
ClassTemplateDecl *CoroHandle = Result.getAsSingle<ClassTemplateDecl>();
158
if (!CoroHandle) {
159
Result.suppressDiagnostics();
160
// We found something weird. Complain about the first thing we found.
161
NamedDecl *Found = *Result.begin();
162
S.Diag(Found->getLocation(), diag::err_malformed_std_coroutine_handle);
163
return QualType();
164
}
165
166
// Form template argument list for coroutine_handle<Promise>.
167
TemplateArgumentListInfo Args(Loc, Loc);
168
Args.addArgument(TemplateArgumentLoc(
169
TemplateArgument(PromiseType),
170
S.Context.getTrivialTypeSourceInfo(PromiseType, Loc)));
171
172
// Build the template-id.
173
QualType CoroHandleType =
174
S.CheckTemplateIdType(TemplateName(CoroHandle), Loc, Args);
175
if (CoroHandleType.isNull())
176
return QualType();
177
if (S.RequireCompleteType(Loc, CoroHandleType,
178
diag::err_coroutine_type_missing_specialization))
179
return QualType();
180
181
return CoroHandleType;
182
}
183
184
static bool isValidCoroutineContext(Sema &S, SourceLocation Loc,
185
StringRef Keyword) {
186
// [expr.await]p2 dictates that 'co_await' and 'co_yield' must be used within
187
// a function body.
188
// FIXME: This also covers [expr.await]p2: "An await-expression shall not
189
// appear in a default argument." But the diagnostic QoI here could be
190
// improved to inform the user that default arguments specifically are not
191
// allowed.
192
auto *FD = dyn_cast<FunctionDecl>(S.CurContext);
193
if (!FD) {
194
S.Diag(Loc, isa<ObjCMethodDecl>(S.CurContext)
195
? diag::err_coroutine_objc_method
196
: diag::err_coroutine_outside_function) << Keyword;
197
return false;
198
}
199
200
// An enumeration for mapping the diagnostic type to the correct diagnostic
201
// selection index.
202
enum InvalidFuncDiag {
203
DiagCtor = 0,
204
DiagDtor,
205
DiagMain,
206
DiagConstexpr,
207
DiagAutoRet,
208
DiagVarargs,
209
DiagConsteval,
210
};
211
bool Diagnosed = false;
212
auto DiagInvalid = [&](InvalidFuncDiag ID) {
213
S.Diag(Loc, diag::err_coroutine_invalid_func_context) << ID << Keyword;
214
Diagnosed = true;
215
return false;
216
};
217
218
// Diagnose when a constructor, destructor
219
// or the function 'main' are declared as a coroutine.
220
auto *MD = dyn_cast<CXXMethodDecl>(FD);
221
// [class.ctor]p11: "A constructor shall not be a coroutine."
222
if (MD && isa<CXXConstructorDecl>(MD))
223
return DiagInvalid(DiagCtor);
224
// [class.dtor]p17: "A destructor shall not be a coroutine."
225
else if (MD && isa<CXXDestructorDecl>(MD))
226
return DiagInvalid(DiagDtor);
227
// [basic.start.main]p3: "The function main shall not be a coroutine."
228
else if (FD->isMain())
229
return DiagInvalid(DiagMain);
230
231
// Emit a diagnostics for each of the following conditions which is not met.
232
// [expr.const]p2: "An expression e is a core constant expression unless the
233
// evaluation of e [...] would evaluate one of the following expressions:
234
// [...] an await-expression [...] a yield-expression."
235
if (FD->isConstexpr())
236
DiagInvalid(FD->isConsteval() ? DiagConsteval : DiagConstexpr);
237
// [dcl.spec.auto]p15: "A function declared with a return type that uses a
238
// placeholder type shall not be a coroutine."
239
if (FD->getReturnType()->isUndeducedType())
240
DiagInvalid(DiagAutoRet);
241
// [dcl.fct.def.coroutine]p1
242
// The parameter-declaration-clause of the coroutine shall not terminate with
243
// an ellipsis that is not part of a parameter-declaration.
244
if (FD->isVariadic())
245
DiagInvalid(DiagVarargs);
246
247
return !Diagnosed;
248
}
249
250
/// Build a call to 'operator co_await' if there is a suitable operator for
251
/// the given expression.
252
ExprResult Sema::BuildOperatorCoawaitCall(SourceLocation Loc, Expr *E,
253
UnresolvedLookupExpr *Lookup) {
254
UnresolvedSet<16> Functions;
255
Functions.append(Lookup->decls_begin(), Lookup->decls_end());
256
return CreateOverloadedUnaryOp(Loc, UO_Coawait, Functions, E);
257
}
258
259
static ExprResult buildOperatorCoawaitCall(Sema &SemaRef, Scope *S,
260
SourceLocation Loc, Expr *E) {
261
ExprResult R = SemaRef.BuildOperatorCoawaitLookupExpr(S, Loc);
262
if (R.isInvalid())
263
return ExprError();
264
return SemaRef.BuildOperatorCoawaitCall(Loc, E,
265
cast<UnresolvedLookupExpr>(R.get()));
266
}
267
268
static ExprResult buildCoroutineHandle(Sema &S, QualType PromiseType,
269
SourceLocation Loc) {
270
QualType CoroHandleType = lookupCoroutineHandleType(S, PromiseType, Loc);
271
if (CoroHandleType.isNull())
272
return ExprError();
273
274
DeclContext *LookupCtx = S.computeDeclContext(CoroHandleType);
275
LookupResult Found(S, &S.PP.getIdentifierTable().get("from_address"), Loc,
276
Sema::LookupOrdinaryName);
277
if (!S.LookupQualifiedName(Found, LookupCtx)) {
278
S.Diag(Loc, diag::err_coroutine_handle_missing_member)
279
<< "from_address";
280
return ExprError();
281
}
282
283
Expr *FramePtr =
284
S.BuildBuiltinCallExpr(Loc, Builtin::BI__builtin_coro_frame, {});
285
286
CXXScopeSpec SS;
287
ExprResult FromAddr =
288
S.BuildDeclarationNameExpr(SS, Found, /*NeedsADL=*/false);
289
if (FromAddr.isInvalid())
290
return ExprError();
291
292
return S.BuildCallExpr(nullptr, FromAddr.get(), Loc, FramePtr, Loc);
293
}
294
295
struct ReadySuspendResumeResult {
296
enum AwaitCallType { ACT_Ready, ACT_Suspend, ACT_Resume };
297
Expr *Results[3];
298
OpaqueValueExpr *OpaqueValue;
299
bool IsInvalid;
300
};
301
302
static ExprResult buildMemberCall(Sema &S, Expr *Base, SourceLocation Loc,
303
StringRef Name, MultiExprArg Args) {
304
DeclarationNameInfo NameInfo(&S.PP.getIdentifierTable().get(Name), Loc);
305
306
// FIXME: Fix BuildMemberReferenceExpr to take a const CXXScopeSpec&.
307
CXXScopeSpec SS;
308
ExprResult Result = S.BuildMemberReferenceExpr(
309
Base, Base->getType(), Loc, /*IsPtr=*/false, SS,
310
SourceLocation(), nullptr, NameInfo, /*TemplateArgs=*/nullptr,
311
/*Scope=*/nullptr);
312
if (Result.isInvalid())
313
return ExprError();
314
315
// We meant exactly what we asked for. No need for typo correction.
316
if (auto *TE = dyn_cast<TypoExpr>(Result.get())) {
317
S.clearDelayedTypo(TE);
318
S.Diag(Loc, diag::err_no_member)
319
<< NameInfo.getName() << Base->getType()->getAsCXXRecordDecl()
320
<< Base->getSourceRange();
321
return ExprError();
322
}
323
324
auto EndLoc = Args.empty() ? Loc : Args.back()->getEndLoc();
325
return S.BuildCallExpr(nullptr, Result.get(), Loc, Args, EndLoc, nullptr);
326
}
327
328
// See if return type is coroutine-handle and if so, invoke builtin coro-resume
329
// on its address. This is to enable the support for coroutine-handle
330
// returning await_suspend that results in a guaranteed tail call to the target
331
// coroutine.
332
static Expr *maybeTailCall(Sema &S, QualType RetType, Expr *E,
333
SourceLocation Loc) {
334
if (RetType->isReferenceType())
335
return nullptr;
336
Type const *T = RetType.getTypePtr();
337
if (!T->isClassType() && !T->isStructureType())
338
return nullptr;
339
340
// FIXME: Add convertability check to coroutine_handle<>. Possibly via
341
// EvaluateBinaryTypeTrait(BTT_IsConvertible, ...) which is at the moment
342
// a private function in SemaExprCXX.cpp
343
344
ExprResult AddressExpr = buildMemberCall(S, E, Loc, "address", std::nullopt);
345
if (AddressExpr.isInvalid())
346
return nullptr;
347
348
Expr *JustAddress = AddressExpr.get();
349
350
// Check that the type of AddressExpr is void*
351
if (!JustAddress->getType().getTypePtr()->isVoidPointerType())
352
S.Diag(cast<CallExpr>(JustAddress)->getCalleeDecl()->getLocation(),
353
diag::warn_coroutine_handle_address_invalid_return_type)
354
<< JustAddress->getType();
355
356
// Clean up temporary objects, because the resulting expression
357
// will become the body of await_suspend wrapper.
358
return S.MaybeCreateExprWithCleanups(JustAddress);
359
}
360
361
/// Build calls to await_ready, await_suspend, and await_resume for a co_await
362
/// expression.
363
/// The generated AST tries to clean up temporary objects as early as
364
/// possible so that they don't live across suspension points if possible.
365
/// Having temporary objects living across suspension points unnecessarily can
366
/// lead to large frame size, and also lead to memory corruptions if the
367
/// coroutine frame is destroyed after coming back from suspension. This is done
368
/// by wrapping both the await_ready call and the await_suspend call with
369
/// ExprWithCleanups. In the end of this function, we also need to explicitly
370
/// set cleanup state so that the CoawaitExpr is also wrapped with an
371
/// ExprWithCleanups to clean up the awaiter associated with the co_await
372
/// expression.
373
static ReadySuspendResumeResult buildCoawaitCalls(Sema &S, VarDecl *CoroPromise,
374
SourceLocation Loc, Expr *E) {
375
OpaqueValueExpr *Operand = new (S.Context)
376
OpaqueValueExpr(Loc, E->getType(), VK_LValue, E->getObjectKind(), E);
377
378
// Assume valid until we see otherwise.
379
// Further operations are responsible for setting IsInalid to true.
380
ReadySuspendResumeResult Calls = {{}, Operand, /*IsInvalid=*/false};
381
382
using ACT = ReadySuspendResumeResult::AwaitCallType;
383
384
auto BuildSubExpr = [&](ACT CallType, StringRef Func,
385
MultiExprArg Arg) -> Expr * {
386
ExprResult Result = buildMemberCall(S, Operand, Loc, Func, Arg);
387
if (Result.isInvalid()) {
388
Calls.IsInvalid = true;
389
return nullptr;
390
}
391
Calls.Results[CallType] = Result.get();
392
return Result.get();
393
};
394
395
CallExpr *AwaitReady = cast_or_null<CallExpr>(
396
BuildSubExpr(ACT::ACT_Ready, "await_ready", std::nullopt));
397
if (!AwaitReady)
398
return Calls;
399
if (!AwaitReady->getType()->isDependentType()) {
400
// [expr.await]p3 [...]
401
// — await-ready is the expression e.await_ready(), contextually converted
402
// to bool.
403
ExprResult Conv = S.PerformContextuallyConvertToBool(AwaitReady);
404
if (Conv.isInvalid()) {
405
S.Diag(AwaitReady->getDirectCallee()->getBeginLoc(),
406
diag::note_await_ready_no_bool_conversion);
407
S.Diag(Loc, diag::note_coroutine_promise_call_implicitly_required)
408
<< AwaitReady->getDirectCallee() << E->getSourceRange();
409
Calls.IsInvalid = true;
410
} else
411
Calls.Results[ACT::ACT_Ready] = S.MaybeCreateExprWithCleanups(Conv.get());
412
}
413
414
ExprResult CoroHandleRes =
415
buildCoroutineHandle(S, CoroPromise->getType(), Loc);
416
if (CoroHandleRes.isInvalid()) {
417
Calls.IsInvalid = true;
418
return Calls;
419
}
420
Expr *CoroHandle = CoroHandleRes.get();
421
CallExpr *AwaitSuspend = cast_or_null<CallExpr>(
422
BuildSubExpr(ACT::ACT_Suspend, "await_suspend", CoroHandle));
423
if (!AwaitSuspend)
424
return Calls;
425
if (!AwaitSuspend->getType()->isDependentType()) {
426
// [expr.await]p3 [...]
427
// - await-suspend is the expression e.await_suspend(h), which shall be
428
// a prvalue of type void, bool, or std::coroutine_handle<Z> for some
429
// type Z.
430
QualType RetType = AwaitSuspend->getCallReturnType(S.Context);
431
432
// Support for coroutine_handle returning await_suspend.
433
if (Expr *TailCallSuspend =
434
maybeTailCall(S, RetType, AwaitSuspend, Loc))
435
// Note that we don't wrap the expression with ExprWithCleanups here
436
// because that might interfere with tailcall contract (e.g. inserting
437
// clean up instructions in-between tailcall and return). Instead
438
// ExprWithCleanups is wrapped within maybeTailCall() prior to the resume
439
// call.
440
Calls.Results[ACT::ACT_Suspend] = TailCallSuspend;
441
else {
442
// non-class prvalues always have cv-unqualified types
443
if (RetType->isReferenceType() ||
444
(!RetType->isBooleanType() && !RetType->isVoidType())) {
445
S.Diag(AwaitSuspend->getCalleeDecl()->getLocation(),
446
diag::err_await_suspend_invalid_return_type)
447
<< RetType;
448
S.Diag(Loc, diag::note_coroutine_promise_call_implicitly_required)
449
<< AwaitSuspend->getDirectCallee();
450
Calls.IsInvalid = true;
451
} else
452
Calls.Results[ACT::ACT_Suspend] =
453
S.MaybeCreateExprWithCleanups(AwaitSuspend);
454
}
455
}
456
457
BuildSubExpr(ACT::ACT_Resume, "await_resume", std::nullopt);
458
459
// Make sure the awaiter object gets a chance to be cleaned up.
460
S.Cleanup.setExprNeedsCleanups(true);
461
462
return Calls;
463
}
464
465
static ExprResult buildPromiseCall(Sema &S, VarDecl *Promise,
466
SourceLocation Loc, StringRef Name,
467
MultiExprArg Args) {
468
469
// Form a reference to the promise.
470
ExprResult PromiseRef = S.BuildDeclRefExpr(
471
Promise, Promise->getType().getNonReferenceType(), VK_LValue, Loc);
472
if (PromiseRef.isInvalid())
473
return ExprError();
474
475
return buildMemberCall(S, PromiseRef.get(), Loc, Name, Args);
476
}
477
478
VarDecl *Sema::buildCoroutinePromise(SourceLocation Loc) {
479
assert(isa<FunctionDecl>(CurContext) && "not in a function scope");
480
auto *FD = cast<FunctionDecl>(CurContext);
481
bool IsThisDependentType = [&] {
482
if (const auto *MD = dyn_cast_if_present<CXXMethodDecl>(FD))
483
return MD->isImplicitObjectMemberFunction() &&
484
MD->getThisType()->isDependentType();
485
return false;
486
}();
487
488
QualType T = FD->getType()->isDependentType() || IsThisDependentType
489
? Context.DependentTy
490
: lookupPromiseType(*this, FD, Loc);
491
if (T.isNull())
492
return nullptr;
493
494
auto *VD = VarDecl::Create(Context, FD, FD->getLocation(), FD->getLocation(),
495
&PP.getIdentifierTable().get("__promise"), T,
496
Context.getTrivialTypeSourceInfo(T, Loc), SC_None);
497
VD->setImplicit();
498
CheckVariableDeclarationType(VD);
499
if (VD->isInvalidDecl())
500
return nullptr;
501
502
auto *ScopeInfo = getCurFunction();
503
504
// Build a list of arguments, based on the coroutine function's arguments,
505
// that if present will be passed to the promise type's constructor.
506
llvm::SmallVector<Expr *, 4> CtorArgExprs;
507
508
// Add implicit object parameter.
509
if (auto *MD = dyn_cast<CXXMethodDecl>(FD)) {
510
if (MD->isImplicitObjectMemberFunction() && !isLambdaCallOperator(MD)) {
511
ExprResult ThisExpr = ActOnCXXThis(Loc);
512
if (ThisExpr.isInvalid())
513
return nullptr;
514
ThisExpr = CreateBuiltinUnaryOp(Loc, UO_Deref, ThisExpr.get());
515
if (ThisExpr.isInvalid())
516
return nullptr;
517
CtorArgExprs.push_back(ThisExpr.get());
518
}
519
}
520
521
// Add the coroutine function's parameters.
522
auto &Moves = ScopeInfo->CoroutineParameterMoves;
523
for (auto *PD : FD->parameters()) {
524
if (PD->getType()->isDependentType())
525
continue;
526
527
auto RefExpr = ExprEmpty();
528
auto Move = Moves.find(PD);
529
assert(Move != Moves.end() &&
530
"Coroutine function parameter not inserted into move map");
531
// If a reference to the function parameter exists in the coroutine
532
// frame, use that reference.
533
auto *MoveDecl =
534
cast<VarDecl>(cast<DeclStmt>(Move->second)->getSingleDecl());
535
RefExpr =
536
BuildDeclRefExpr(MoveDecl, MoveDecl->getType().getNonReferenceType(),
537
ExprValueKind::VK_LValue, FD->getLocation());
538
if (RefExpr.isInvalid())
539
return nullptr;
540
CtorArgExprs.push_back(RefExpr.get());
541
}
542
543
// If we have a non-zero number of constructor arguments, try to use them.
544
// Otherwise, fall back to the promise type's default constructor.
545
if (!CtorArgExprs.empty()) {
546
// Create an initialization sequence for the promise type using the
547
// constructor arguments, wrapped in a parenthesized list expression.
548
Expr *PLE = ParenListExpr::Create(Context, FD->getLocation(),
549
CtorArgExprs, FD->getLocation());
550
InitializedEntity Entity = InitializedEntity::InitializeVariable(VD);
551
InitializationKind Kind = InitializationKind::CreateForInit(
552
VD->getLocation(), /*DirectInit=*/true, PLE);
553
InitializationSequence InitSeq(*this, Entity, Kind, CtorArgExprs,
554
/*TopLevelOfInitList=*/false,
555
/*TreatUnavailableAsInvalid=*/false);
556
557
// [dcl.fct.def.coroutine]5.7
558
// promise-constructor-arguments is determined as follows: overload
559
// resolution is performed on a promise constructor call created by
560
// assembling an argument list q_1 ... q_n . If a viable constructor is
561
// found ([over.match.viable]), then promise-constructor-arguments is ( q_1
562
// , ..., q_n ), otherwise promise-constructor-arguments is empty.
563
if (InitSeq) {
564
ExprResult Result = InitSeq.Perform(*this, Entity, Kind, CtorArgExprs);
565
if (Result.isInvalid()) {
566
VD->setInvalidDecl();
567
} else if (Result.get()) {
568
VD->setInit(MaybeCreateExprWithCleanups(Result.get()));
569
VD->setInitStyle(VarDecl::CallInit);
570
CheckCompleteVariableDeclaration(VD);
571
}
572
} else
573
ActOnUninitializedDecl(VD);
574
} else
575
ActOnUninitializedDecl(VD);
576
577
FD->addDecl(VD);
578
return VD;
579
}
580
581
/// Check that this is a context in which a coroutine suspension can appear.
582
static FunctionScopeInfo *checkCoroutineContext(Sema &S, SourceLocation Loc,
583
StringRef Keyword,
584
bool IsImplicit = false) {
585
if (!isValidCoroutineContext(S, Loc, Keyword))
586
return nullptr;
587
588
assert(isa<FunctionDecl>(S.CurContext) && "not in a function scope");
589
590
auto *ScopeInfo = S.getCurFunction();
591
assert(ScopeInfo && "missing function scope for function");
592
593
if (ScopeInfo->FirstCoroutineStmtLoc.isInvalid() && !IsImplicit)
594
ScopeInfo->setFirstCoroutineStmt(Loc, Keyword);
595
596
if (ScopeInfo->CoroutinePromise)
597
return ScopeInfo;
598
599
if (!S.buildCoroutineParameterMoves(Loc))
600
return nullptr;
601
602
ScopeInfo->CoroutinePromise = S.buildCoroutinePromise(Loc);
603
if (!ScopeInfo->CoroutinePromise)
604
return nullptr;
605
606
return ScopeInfo;
607
}
608
609
/// Recursively check \p E and all its children to see if any call target
610
/// (including constructor call) is declared noexcept. Also any value returned
611
/// from the call has a noexcept destructor.
612
static void checkNoThrow(Sema &S, const Stmt *E,
613
llvm::SmallPtrSetImpl<const Decl *> &ThrowingDecls) {
614
auto checkDeclNoexcept = [&](const Decl *D, bool IsDtor = false) {
615
// In the case of dtor, the call to dtor is implicit and hence we should
616
// pass nullptr to canCalleeThrow.
617
if (Sema::canCalleeThrow(S, IsDtor ? nullptr : cast<Expr>(E), D)) {
618
if (const auto *FD = dyn_cast<FunctionDecl>(D)) {
619
// co_await promise.final_suspend() could end up calling
620
// __builtin_coro_resume for symmetric transfer if await_suspend()
621
// returns a handle. In that case, even __builtin_coro_resume is not
622
// declared as noexcept and may throw, it does not throw _into_ the
623
// coroutine that just suspended, but rather throws back out from
624
// whoever called coroutine_handle::resume(), hence we claim that
625
// logically it does not throw.
626
if (FD->getBuiltinID() == Builtin::BI__builtin_coro_resume)
627
return;
628
}
629
if (ThrowingDecls.empty()) {
630
// [dcl.fct.def.coroutine]p15
631
// The expression co_await promise.final_suspend() shall not be
632
// potentially-throwing ([except.spec]).
633
//
634
// First time seeing an error, emit the error message.
635
S.Diag(cast<FunctionDecl>(S.CurContext)->getLocation(),
636
diag::err_coroutine_promise_final_suspend_requires_nothrow);
637
}
638
ThrowingDecls.insert(D);
639
}
640
};
641
642
if (auto *CE = dyn_cast<CXXConstructExpr>(E)) {
643
CXXConstructorDecl *Ctor = CE->getConstructor();
644
checkDeclNoexcept(Ctor);
645
// Check the corresponding destructor of the constructor.
646
checkDeclNoexcept(Ctor->getParent()->getDestructor(), /*IsDtor=*/true);
647
} else if (auto *CE = dyn_cast<CallExpr>(E)) {
648
if (CE->isTypeDependent())
649
return;
650
651
checkDeclNoexcept(CE->getCalleeDecl());
652
QualType ReturnType = CE->getCallReturnType(S.getASTContext());
653
// Check the destructor of the call return type, if any.
654
if (ReturnType.isDestructedType() ==
655
QualType::DestructionKind::DK_cxx_destructor) {
656
const auto *T =
657
cast<RecordType>(ReturnType.getCanonicalType().getTypePtr());
658
checkDeclNoexcept(cast<CXXRecordDecl>(T->getDecl())->getDestructor(),
659
/*IsDtor=*/true);
660
}
661
} else
662
for (const auto *Child : E->children()) {
663
if (!Child)
664
continue;
665
checkNoThrow(S, Child, ThrowingDecls);
666
}
667
}
668
669
bool Sema::checkFinalSuspendNoThrow(const Stmt *FinalSuspend) {
670
llvm::SmallPtrSet<const Decl *, 4> ThrowingDecls;
671
// We first collect all declarations that should not throw but not declared
672
// with noexcept. We then sort them based on the location before printing.
673
// This is to avoid emitting the same note multiple times on the same
674
// declaration, and also provide a deterministic order for the messages.
675
checkNoThrow(*this, FinalSuspend, ThrowingDecls);
676
auto SortedDecls = llvm::SmallVector<const Decl *, 4>{ThrowingDecls.begin(),
677
ThrowingDecls.end()};
678
sort(SortedDecls, [](const Decl *A, const Decl *B) {
679
return A->getEndLoc() < B->getEndLoc();
680
});
681
for (const auto *D : SortedDecls) {
682
Diag(D->getEndLoc(), diag::note_coroutine_function_declare_noexcept);
683
}
684
return ThrowingDecls.empty();
685
}
686
687
bool Sema::ActOnCoroutineBodyStart(Scope *SC, SourceLocation KWLoc,
688
StringRef Keyword) {
689
// Ignore previous expr evaluation contexts.
690
EnterExpressionEvaluationContext PotentiallyEvaluated(
691
*this, Sema::ExpressionEvaluationContext::PotentiallyEvaluated);
692
if (!checkCoroutineContext(*this, KWLoc, Keyword))
693
return false;
694
auto *ScopeInfo = getCurFunction();
695
assert(ScopeInfo->CoroutinePromise);
696
697
// If we have existing coroutine statements then we have already built
698
// the initial and final suspend points.
699
if (!ScopeInfo->NeedsCoroutineSuspends)
700
return true;
701
702
ScopeInfo->setNeedsCoroutineSuspends(false);
703
704
auto *Fn = cast<FunctionDecl>(CurContext);
705
SourceLocation Loc = Fn->getLocation();
706
// Build the initial suspend point
707
auto buildSuspends = [&](StringRef Name) mutable -> StmtResult {
708
ExprResult Operand = buildPromiseCall(*this, ScopeInfo->CoroutinePromise,
709
Loc, Name, std::nullopt);
710
if (Operand.isInvalid())
711
return StmtError();
712
ExprResult Suspend =
713
buildOperatorCoawaitCall(*this, SC, Loc, Operand.get());
714
if (Suspend.isInvalid())
715
return StmtError();
716
Suspend = BuildResolvedCoawaitExpr(Loc, Operand.get(), Suspend.get(),
717
/*IsImplicit*/ true);
718
Suspend = ActOnFinishFullExpr(Suspend.get(), /*DiscardedValue*/ false);
719
if (Suspend.isInvalid()) {
720
Diag(Loc, diag::note_coroutine_promise_suspend_implicitly_required)
721
<< ((Name == "initial_suspend") ? 0 : 1);
722
Diag(KWLoc, diag::note_declared_coroutine_here) << Keyword;
723
return StmtError();
724
}
725
return cast<Stmt>(Suspend.get());
726
};
727
728
StmtResult InitSuspend = buildSuspends("initial_suspend");
729
if (InitSuspend.isInvalid())
730
return true;
731
732
StmtResult FinalSuspend = buildSuspends("final_suspend");
733
if (FinalSuspend.isInvalid() || !checkFinalSuspendNoThrow(FinalSuspend.get()))
734
return true;
735
736
ScopeInfo->setCoroutineSuspends(InitSuspend.get(), FinalSuspend.get());
737
738
return true;
739
}
740
741
// Recursively walks up the scope hierarchy until either a 'catch' or a function
742
// scope is found, whichever comes first.
743
static bool isWithinCatchScope(Scope *S) {
744
// 'co_await' and 'co_yield' keywords are disallowed within catch blocks, but
745
// lambdas that use 'co_await' are allowed. The loop below ends when a
746
// function scope is found in order to ensure the following behavior:
747
//
748
// void foo() { // <- function scope
749
// try { //
750
// co_await x; // <- 'co_await' is OK within a function scope
751
// } catch { // <- catch scope
752
// co_await x; // <- 'co_await' is not OK within a catch scope
753
// []() { // <- function scope
754
// co_await x; // <- 'co_await' is OK within a function scope
755
// }();
756
// }
757
// }
758
while (S && !S->isFunctionScope()) {
759
if (S->isCatchScope())
760
return true;
761
S = S->getParent();
762
}
763
return false;
764
}
765
766
// [expr.await]p2, emphasis added: "An await-expression shall appear only in
767
// a *potentially evaluated* expression within the compound-statement of a
768
// function-body *outside of a handler* [...] A context within a function
769
// where an await-expression can appear is called a suspension context of the
770
// function."
771
static bool checkSuspensionContext(Sema &S, SourceLocation Loc,
772
StringRef Keyword) {
773
// First emphasis of [expr.await]p2: must be a potentially evaluated context.
774
// That is, 'co_await' and 'co_yield' cannot appear in subexpressions of
775
// \c sizeof.
776
if (S.isUnevaluatedContext()) {
777
S.Diag(Loc, diag::err_coroutine_unevaluated_context) << Keyword;
778
return false;
779
}
780
781
// Second emphasis of [expr.await]p2: must be outside of an exception handler.
782
if (isWithinCatchScope(S.getCurScope())) {
783
S.Diag(Loc, diag::err_coroutine_within_handler) << Keyword;
784
return false;
785
}
786
787
return true;
788
}
789
790
ExprResult Sema::ActOnCoawaitExpr(Scope *S, SourceLocation Loc, Expr *E) {
791
if (!checkSuspensionContext(*this, Loc, "co_await"))
792
return ExprError();
793
794
if (!ActOnCoroutineBodyStart(S, Loc, "co_await")) {
795
CorrectDelayedTyposInExpr(E);
796
return ExprError();
797
}
798
799
if (E->hasPlaceholderType()) {
800
ExprResult R = CheckPlaceholderExpr(E);
801
if (R.isInvalid()) return ExprError();
802
E = R.get();
803
}
804
ExprResult Lookup = BuildOperatorCoawaitLookupExpr(S, Loc);
805
if (Lookup.isInvalid())
806
return ExprError();
807
return BuildUnresolvedCoawaitExpr(Loc, E,
808
cast<UnresolvedLookupExpr>(Lookup.get()));
809
}
810
811
ExprResult Sema::BuildOperatorCoawaitLookupExpr(Scope *S, SourceLocation Loc) {
812
DeclarationName OpName =
813
Context.DeclarationNames.getCXXOperatorName(OO_Coawait);
814
LookupResult Operators(*this, OpName, SourceLocation(),
815
Sema::LookupOperatorName);
816
LookupName(Operators, S);
817
818
assert(!Operators.isAmbiguous() && "Operator lookup cannot be ambiguous");
819
const auto &Functions = Operators.asUnresolvedSet();
820
Expr *CoawaitOp = UnresolvedLookupExpr::Create(
821
Context, /*NamingClass*/ nullptr, NestedNameSpecifierLoc(),
822
DeclarationNameInfo(OpName, Loc), /*RequiresADL*/ true, Functions.begin(),
823
Functions.end(), /*KnownDependent=*/false,
824
/*KnownInstantiationDependent=*/false);
825
assert(CoawaitOp);
826
return CoawaitOp;
827
}
828
829
// Attempts to resolve and build a CoawaitExpr from "raw" inputs, bailing out to
830
// DependentCoawaitExpr if needed.
831
ExprResult Sema::BuildUnresolvedCoawaitExpr(SourceLocation Loc, Expr *Operand,
832
UnresolvedLookupExpr *Lookup) {
833
auto *FSI = checkCoroutineContext(*this, Loc, "co_await");
834
if (!FSI)
835
return ExprError();
836
837
if (Operand->hasPlaceholderType()) {
838
ExprResult R = CheckPlaceholderExpr(Operand);
839
if (R.isInvalid())
840
return ExprError();
841
Operand = R.get();
842
}
843
844
auto *Promise = FSI->CoroutinePromise;
845
if (Promise->getType()->isDependentType()) {
846
Expr *Res = new (Context)
847
DependentCoawaitExpr(Loc, Context.DependentTy, Operand, Lookup);
848
return Res;
849
}
850
851
auto *RD = Promise->getType()->getAsCXXRecordDecl();
852
auto *Transformed = Operand;
853
if (lookupMember(*this, "await_transform", RD, Loc)) {
854
ExprResult R =
855
buildPromiseCall(*this, Promise, Loc, "await_transform", Operand);
856
if (R.isInvalid()) {
857
Diag(Loc,
858
diag::note_coroutine_promise_implicit_await_transform_required_here)
859
<< Operand->getSourceRange();
860
return ExprError();
861
}
862
Transformed = R.get();
863
}
864
ExprResult Awaiter = BuildOperatorCoawaitCall(Loc, Transformed, Lookup);
865
if (Awaiter.isInvalid())
866
return ExprError();
867
868
return BuildResolvedCoawaitExpr(Loc, Operand, Awaiter.get());
869
}
870
871
ExprResult Sema::BuildResolvedCoawaitExpr(SourceLocation Loc, Expr *Operand,
872
Expr *Awaiter, bool IsImplicit) {
873
auto *Coroutine = checkCoroutineContext(*this, Loc, "co_await", IsImplicit);
874
if (!Coroutine)
875
return ExprError();
876
877
if (Awaiter->hasPlaceholderType()) {
878
ExprResult R = CheckPlaceholderExpr(Awaiter);
879
if (R.isInvalid()) return ExprError();
880
Awaiter = R.get();
881
}
882
883
if (Awaiter->getType()->isDependentType()) {
884
Expr *Res = new (Context)
885
CoawaitExpr(Loc, Context.DependentTy, Operand, Awaiter, IsImplicit);
886
return Res;
887
}
888
889
// If the expression is a temporary, materialize it as an lvalue so that we
890
// can use it multiple times.
891
if (Awaiter->isPRValue())
892
Awaiter = CreateMaterializeTemporaryExpr(Awaiter->getType(), Awaiter, true);
893
894
// The location of the `co_await` token cannot be used when constructing
895
// the member call expressions since it's before the location of `Expr`, which
896
// is used as the start of the member call expression.
897
SourceLocation CallLoc = Awaiter->getExprLoc();
898
899
// Build the await_ready, await_suspend, await_resume calls.
900
ReadySuspendResumeResult RSS =
901
buildCoawaitCalls(*this, Coroutine->CoroutinePromise, CallLoc, Awaiter);
902
if (RSS.IsInvalid)
903
return ExprError();
904
905
Expr *Res = new (Context)
906
CoawaitExpr(Loc, Operand, Awaiter, RSS.Results[0], RSS.Results[1],
907
RSS.Results[2], RSS.OpaqueValue, IsImplicit);
908
909
return Res;
910
}
911
912
ExprResult Sema::ActOnCoyieldExpr(Scope *S, SourceLocation Loc, Expr *E) {
913
if (!checkSuspensionContext(*this, Loc, "co_yield"))
914
return ExprError();
915
916
if (!ActOnCoroutineBodyStart(S, Loc, "co_yield")) {
917
CorrectDelayedTyposInExpr(E);
918
return ExprError();
919
}
920
921
// Build yield_value call.
922
ExprResult Awaitable = buildPromiseCall(
923
*this, getCurFunction()->CoroutinePromise, Loc, "yield_value", E);
924
if (Awaitable.isInvalid())
925
return ExprError();
926
927
// Build 'operator co_await' call.
928
Awaitable = buildOperatorCoawaitCall(*this, S, Loc, Awaitable.get());
929
if (Awaitable.isInvalid())
930
return ExprError();
931
932
return BuildCoyieldExpr(Loc, Awaitable.get());
933
}
934
ExprResult Sema::BuildCoyieldExpr(SourceLocation Loc, Expr *E) {
935
auto *Coroutine = checkCoroutineContext(*this, Loc, "co_yield");
936
if (!Coroutine)
937
return ExprError();
938
939
if (E->hasPlaceholderType()) {
940
ExprResult R = CheckPlaceholderExpr(E);
941
if (R.isInvalid()) return ExprError();
942
E = R.get();
943
}
944
945
Expr *Operand = E;
946
947
if (E->getType()->isDependentType()) {
948
Expr *Res = new (Context) CoyieldExpr(Loc, Context.DependentTy, Operand, E);
949
return Res;
950
}
951
952
// If the expression is a temporary, materialize it as an lvalue so that we
953
// can use it multiple times.
954
if (E->isPRValue())
955
E = CreateMaterializeTemporaryExpr(E->getType(), E, true);
956
957
// Build the await_ready, await_suspend, await_resume calls.
958
ReadySuspendResumeResult RSS = buildCoawaitCalls(
959
*this, Coroutine->CoroutinePromise, Loc, E);
960
if (RSS.IsInvalid)
961
return ExprError();
962
963
Expr *Res =
964
new (Context) CoyieldExpr(Loc, Operand, E, RSS.Results[0], RSS.Results[1],
965
RSS.Results[2], RSS.OpaqueValue);
966
967
return Res;
968
}
969
970
StmtResult Sema::ActOnCoreturnStmt(Scope *S, SourceLocation Loc, Expr *E) {
971
if (!ActOnCoroutineBodyStart(S, Loc, "co_return")) {
972
CorrectDelayedTyposInExpr(E);
973
return StmtError();
974
}
975
return BuildCoreturnStmt(Loc, E);
976
}
977
978
StmtResult Sema::BuildCoreturnStmt(SourceLocation Loc, Expr *E,
979
bool IsImplicit) {
980
auto *FSI = checkCoroutineContext(*this, Loc, "co_return", IsImplicit);
981
if (!FSI)
982
return StmtError();
983
984
if (E && E->hasPlaceholderType() &&
985
!E->hasPlaceholderType(BuiltinType::Overload)) {
986
ExprResult R = CheckPlaceholderExpr(E);
987
if (R.isInvalid()) return StmtError();
988
E = R.get();
989
}
990
991
VarDecl *Promise = FSI->CoroutinePromise;
992
ExprResult PC;
993
if (E && (isa<InitListExpr>(E) || !E->getType()->isVoidType())) {
994
getNamedReturnInfo(E, SimplerImplicitMoveMode::ForceOn);
995
PC = buildPromiseCall(*this, Promise, Loc, "return_value", E);
996
} else {
997
E = MakeFullDiscardedValueExpr(E).get();
998
PC = buildPromiseCall(*this, Promise, Loc, "return_void", std::nullopt);
999
}
1000
if (PC.isInvalid())
1001
return StmtError();
1002
1003
Expr *PCE = ActOnFinishFullExpr(PC.get(), /*DiscardedValue*/ false).get();
1004
1005
Stmt *Res = new (Context) CoreturnStmt(Loc, E, PCE, IsImplicit);
1006
return Res;
1007
}
1008
1009
/// Look up the std::nothrow object.
1010
static Expr *buildStdNoThrowDeclRef(Sema &S, SourceLocation Loc) {
1011
NamespaceDecl *Std = S.getStdNamespace();
1012
assert(Std && "Should already be diagnosed");
1013
1014
LookupResult Result(S, &S.PP.getIdentifierTable().get("nothrow"), Loc,
1015
Sema::LookupOrdinaryName);
1016
if (!S.LookupQualifiedName(Result, Std)) {
1017
// <coroutine> is not requred to include <new>, so we couldn't omit
1018
// the check here.
1019
S.Diag(Loc, diag::err_implicit_coroutine_std_nothrow_type_not_found);
1020
return nullptr;
1021
}
1022
1023
auto *VD = Result.getAsSingle<VarDecl>();
1024
if (!VD) {
1025
Result.suppressDiagnostics();
1026
// We found something weird. Complain about the first thing we found.
1027
NamedDecl *Found = *Result.begin();
1028
S.Diag(Found->getLocation(), diag::err_malformed_std_nothrow);
1029
return nullptr;
1030
}
1031
1032
ExprResult DR = S.BuildDeclRefExpr(VD, VD->getType(), VK_LValue, Loc);
1033
if (DR.isInvalid())
1034
return nullptr;
1035
1036
return DR.get();
1037
}
1038
1039
static TypeSourceInfo *getTypeSourceInfoForStdAlignValT(Sema &S,
1040
SourceLocation Loc) {
1041
EnumDecl *StdAlignValT = S.getStdAlignValT();
1042
QualType StdAlignValDecl = S.Context.getTypeDeclType(StdAlignValT);
1043
return S.Context.getTrivialTypeSourceInfo(StdAlignValDecl);
1044
}
1045
1046
// Find an appropriate delete for the promise.
1047
static bool findDeleteForPromise(Sema &S, SourceLocation Loc, QualType PromiseType,
1048
FunctionDecl *&OperatorDelete) {
1049
DeclarationName DeleteName =
1050
S.Context.DeclarationNames.getCXXOperatorName(OO_Delete);
1051
1052
auto *PointeeRD = PromiseType->getAsCXXRecordDecl();
1053
assert(PointeeRD && "PromiseType must be a CxxRecordDecl type");
1054
1055
const bool Overaligned = S.getLangOpts().CoroAlignedAllocation;
1056
1057
// [dcl.fct.def.coroutine]p12
1058
// The deallocation function's name is looked up by searching for it in the
1059
// scope of the promise type. If nothing is found, a search is performed in
1060
// the global scope.
1061
if (S.FindDeallocationFunction(Loc, PointeeRD, DeleteName, OperatorDelete,
1062
/*Diagnose*/ true, /*WantSize*/ true,
1063
/*WantAligned*/ Overaligned))
1064
return false;
1065
1066
// [dcl.fct.def.coroutine]p12
1067
// If both a usual deallocation function with only a pointer parameter and a
1068
// usual deallocation function with both a pointer parameter and a size
1069
// parameter are found, then the selected deallocation function shall be the
1070
// one with two parameters. Otherwise, the selected deallocation function
1071
// shall be the function with one parameter.
1072
if (!OperatorDelete) {
1073
// Look for a global declaration.
1074
// Coroutines can always provide their required size.
1075
const bool CanProvideSize = true;
1076
// Sema::FindUsualDeallocationFunction will try to find the one with two
1077
// parameters first. It will return the deallocation function with one
1078
// parameter if failed.
1079
OperatorDelete = S.FindUsualDeallocationFunction(Loc, CanProvideSize,
1080
Overaligned, DeleteName);
1081
1082
if (!OperatorDelete)
1083
return false;
1084
}
1085
1086
S.MarkFunctionReferenced(Loc, OperatorDelete);
1087
return true;
1088
}
1089
1090
1091
void Sema::CheckCompletedCoroutineBody(FunctionDecl *FD, Stmt *&Body) {
1092
FunctionScopeInfo *Fn = getCurFunction();
1093
assert(Fn && Fn->isCoroutine() && "not a coroutine");
1094
if (!Body) {
1095
assert(FD->isInvalidDecl() &&
1096
"a null body is only allowed for invalid declarations");
1097
return;
1098
}
1099
// We have a function that uses coroutine keywords, but we failed to build
1100
// the promise type.
1101
if (!Fn->CoroutinePromise)
1102
return FD->setInvalidDecl();
1103
1104
if (isa<CoroutineBodyStmt>(Body)) {
1105
// Nothing todo. the body is already a transformed coroutine body statement.
1106
return;
1107
}
1108
1109
// The always_inline attribute doesn't reliably apply to a coroutine,
1110
// because the coroutine will be split into pieces and some pieces
1111
// might be called indirectly, as in a virtual call. Even the ramp
1112
// function cannot be inlined at -O0, due to pipeline ordering
1113
// problems (see https://llvm.org/PR53413). Tell the user about it.
1114
if (FD->hasAttr<AlwaysInlineAttr>())
1115
Diag(FD->getLocation(), diag::warn_always_inline_coroutine);
1116
1117
// The design of coroutines means we cannot allow use of VLAs within one, so
1118
// diagnose if we've seen a VLA in the body of this function.
1119
if (Fn->FirstVLALoc.isValid())
1120
Diag(Fn->FirstVLALoc, diag::err_vla_in_coroutine_unsupported);
1121
1122
// [stmt.return.coroutine]p1:
1123
// A coroutine shall not enclose a return statement ([stmt.return]).
1124
if (Fn->FirstReturnLoc.isValid()) {
1125
assert(Fn->FirstCoroutineStmtLoc.isValid() &&
1126
"first coroutine location not set");
1127
Diag(Fn->FirstReturnLoc, diag::err_return_in_coroutine);
1128
Diag(Fn->FirstCoroutineStmtLoc, diag::note_declared_coroutine_here)
1129
<< Fn->getFirstCoroutineStmtKeyword();
1130
}
1131
1132
// Coroutines will get splitted into pieces. The GNU address of label
1133
// extension wouldn't be meaningful in coroutines.
1134
for (AddrLabelExpr *ALE : Fn->AddrLabels)
1135
Diag(ALE->getBeginLoc(), diag::err_coro_invalid_addr_of_label);
1136
1137
CoroutineStmtBuilder Builder(*this, *FD, *Fn, Body);
1138
if (Builder.isInvalid() || !Builder.buildStatements())
1139
return FD->setInvalidDecl();
1140
1141
// Build body for the coroutine wrapper statement.
1142
Body = CoroutineBodyStmt::Create(Context, Builder);
1143
}
1144
1145
static CompoundStmt *buildCoroutineBody(Stmt *Body, ASTContext &Context) {
1146
if (auto *CS = dyn_cast<CompoundStmt>(Body))
1147
return CS;
1148
1149
// The body of the coroutine may be a try statement if it is in
1150
// 'function-try-block' syntax. Here we wrap it into a compound
1151
// statement for consistency.
1152
assert(isa<CXXTryStmt>(Body) && "Unimaged coroutine body type");
1153
return CompoundStmt::Create(Context, {Body}, FPOptionsOverride(),
1154
SourceLocation(), SourceLocation());
1155
}
1156
1157
CoroutineStmtBuilder::CoroutineStmtBuilder(Sema &S, FunctionDecl &FD,
1158
sema::FunctionScopeInfo &Fn,
1159
Stmt *Body)
1160
: S(S), FD(FD), Fn(Fn), Loc(FD.getLocation()),
1161
IsPromiseDependentType(
1162
!Fn.CoroutinePromise ||
1163
Fn.CoroutinePromise->getType()->isDependentType()) {
1164
this->Body = buildCoroutineBody(Body, S.getASTContext());
1165
1166
for (auto KV : Fn.CoroutineParameterMoves)
1167
this->ParamMovesVector.push_back(KV.second);
1168
this->ParamMoves = this->ParamMovesVector;
1169
1170
if (!IsPromiseDependentType) {
1171
PromiseRecordDecl = Fn.CoroutinePromise->getType()->getAsCXXRecordDecl();
1172
assert(PromiseRecordDecl && "Type should have already been checked");
1173
}
1174
this->IsValid = makePromiseStmt() && makeInitialAndFinalSuspend();
1175
}
1176
1177
bool CoroutineStmtBuilder::buildStatements() {
1178
assert(this->IsValid && "coroutine already invalid");
1179
this->IsValid = makeReturnObject();
1180
if (this->IsValid && !IsPromiseDependentType)
1181
buildDependentStatements();
1182
return this->IsValid;
1183
}
1184
1185
bool CoroutineStmtBuilder::buildDependentStatements() {
1186
assert(this->IsValid && "coroutine already invalid");
1187
assert(!this->IsPromiseDependentType &&
1188
"coroutine cannot have a dependent promise type");
1189
this->IsValid = makeOnException() && makeOnFallthrough() &&
1190
makeGroDeclAndReturnStmt() && makeReturnOnAllocFailure() &&
1191
makeNewAndDeleteExpr();
1192
return this->IsValid;
1193
}
1194
1195
bool CoroutineStmtBuilder::makePromiseStmt() {
1196
// Form a declaration statement for the promise declaration, so that AST
1197
// visitors can more easily find it.
1198
StmtResult PromiseStmt =
1199
S.ActOnDeclStmt(S.ConvertDeclToDeclGroup(Fn.CoroutinePromise), Loc, Loc);
1200
if (PromiseStmt.isInvalid())
1201
return false;
1202
1203
this->Promise = PromiseStmt.get();
1204
return true;
1205
}
1206
1207
bool CoroutineStmtBuilder::makeInitialAndFinalSuspend() {
1208
if (Fn.hasInvalidCoroutineSuspends())
1209
return false;
1210
this->InitialSuspend = cast<Expr>(Fn.CoroutineSuspends.first);
1211
this->FinalSuspend = cast<Expr>(Fn.CoroutineSuspends.second);
1212
return true;
1213
}
1214
1215
static bool diagReturnOnAllocFailure(Sema &S, Expr *E,
1216
CXXRecordDecl *PromiseRecordDecl,
1217
FunctionScopeInfo &Fn) {
1218
auto Loc = E->getExprLoc();
1219
if (auto *DeclRef = dyn_cast_or_null<DeclRefExpr>(E)) {
1220
auto *Decl = DeclRef->getDecl();
1221
if (CXXMethodDecl *Method = dyn_cast_or_null<CXXMethodDecl>(Decl)) {
1222
if (Method->isStatic())
1223
return true;
1224
else
1225
Loc = Decl->getLocation();
1226
}
1227
}
1228
1229
S.Diag(
1230
Loc,
1231
diag::err_coroutine_promise_get_return_object_on_allocation_failure)
1232
<< PromiseRecordDecl;
1233
S.Diag(Fn.FirstCoroutineStmtLoc, diag::note_declared_coroutine_here)
1234
<< Fn.getFirstCoroutineStmtKeyword();
1235
return false;
1236
}
1237
1238
bool CoroutineStmtBuilder::makeReturnOnAllocFailure() {
1239
assert(!IsPromiseDependentType &&
1240
"cannot make statement while the promise type is dependent");
1241
1242
// [dcl.fct.def.coroutine]p10
1243
// If a search for the name get_return_object_on_allocation_failure in
1244
// the scope of the promise type ([class.member.lookup]) finds any
1245
// declarations, then the result of a call to an allocation function used to
1246
// obtain storage for the coroutine state is assumed to return nullptr if it
1247
// fails to obtain storage, ... If the allocation function returns nullptr,
1248
// ... and the return value is obtained by a call to
1249
// T::get_return_object_on_allocation_failure(), where T is the
1250
// promise type.
1251
DeclarationName DN =
1252
S.PP.getIdentifierInfo("get_return_object_on_allocation_failure");
1253
LookupResult Found(S, DN, Loc, Sema::LookupMemberName);
1254
if (!S.LookupQualifiedName(Found, PromiseRecordDecl))
1255
return true;
1256
1257
CXXScopeSpec SS;
1258
ExprResult DeclNameExpr =
1259
S.BuildDeclarationNameExpr(SS, Found, /*NeedsADL=*/false);
1260
if (DeclNameExpr.isInvalid())
1261
return false;
1262
1263
if (!diagReturnOnAllocFailure(S, DeclNameExpr.get(), PromiseRecordDecl, Fn))
1264
return false;
1265
1266
ExprResult ReturnObjectOnAllocationFailure =
1267
S.BuildCallExpr(nullptr, DeclNameExpr.get(), Loc, {}, Loc);
1268
if (ReturnObjectOnAllocationFailure.isInvalid())
1269
return false;
1270
1271
StmtResult ReturnStmt =
1272
S.BuildReturnStmt(Loc, ReturnObjectOnAllocationFailure.get());
1273
if (ReturnStmt.isInvalid()) {
1274
S.Diag(Found.getFoundDecl()->getLocation(), diag::note_member_declared_here)
1275
<< DN;
1276
S.Diag(Fn.FirstCoroutineStmtLoc, diag::note_declared_coroutine_here)
1277
<< Fn.getFirstCoroutineStmtKeyword();
1278
return false;
1279
}
1280
1281
this->ReturnStmtOnAllocFailure = ReturnStmt.get();
1282
return true;
1283
}
1284
1285
// Collect placement arguments for allocation function of coroutine FD.
1286
// Return true if we collect placement arguments succesfully. Return false,
1287
// otherwise.
1288
static bool collectPlacementArgs(Sema &S, FunctionDecl &FD, SourceLocation Loc,
1289
SmallVectorImpl<Expr *> &PlacementArgs) {
1290
if (auto *MD = dyn_cast<CXXMethodDecl>(&FD)) {
1291
if (MD->isImplicitObjectMemberFunction() && !isLambdaCallOperator(MD)) {
1292
ExprResult ThisExpr = S.ActOnCXXThis(Loc);
1293
if (ThisExpr.isInvalid())
1294
return false;
1295
ThisExpr = S.CreateBuiltinUnaryOp(Loc, UO_Deref, ThisExpr.get());
1296
if (ThisExpr.isInvalid())
1297
return false;
1298
PlacementArgs.push_back(ThisExpr.get());
1299
}
1300
}
1301
1302
for (auto *PD : FD.parameters()) {
1303
if (PD->getType()->isDependentType())
1304
continue;
1305
1306
// Build a reference to the parameter.
1307
auto PDLoc = PD->getLocation();
1308
ExprResult PDRefExpr =
1309
S.BuildDeclRefExpr(PD, PD->getOriginalType().getNonReferenceType(),
1310
ExprValueKind::VK_LValue, PDLoc);
1311
if (PDRefExpr.isInvalid())
1312
return false;
1313
1314
PlacementArgs.push_back(PDRefExpr.get());
1315
}
1316
1317
return true;
1318
}
1319
1320
bool CoroutineStmtBuilder::makeNewAndDeleteExpr() {
1321
// Form and check allocation and deallocation calls.
1322
assert(!IsPromiseDependentType &&
1323
"cannot make statement while the promise type is dependent");
1324
QualType PromiseType = Fn.CoroutinePromise->getType();
1325
1326
if (S.RequireCompleteType(Loc, PromiseType, diag::err_incomplete_type))
1327
return false;
1328
1329
const bool RequiresNoThrowAlloc = ReturnStmtOnAllocFailure != nullptr;
1330
1331
// According to [dcl.fct.def.coroutine]p9, Lookup allocation functions using a
1332
// parameter list composed of the requested size of the coroutine state being
1333
// allocated, followed by the coroutine function's arguments. If a matching
1334
// allocation function exists, use it. Otherwise, use an allocation function
1335
// that just takes the requested size.
1336
//
1337
// [dcl.fct.def.coroutine]p9
1338
// An implementation may need to allocate additional storage for a
1339
// coroutine.
1340
// This storage is known as the coroutine state and is obtained by calling a
1341
// non-array allocation function ([basic.stc.dynamic.allocation]). The
1342
// allocation function's name is looked up by searching for it in the scope of
1343
// the promise type.
1344
// - If any declarations are found, overload resolution is performed on a
1345
// function call created by assembling an argument list. The first argument is
1346
// the amount of space requested, and has type std::size_t. The
1347
// lvalues p1 ... pn are the succeeding arguments.
1348
//
1349
// ...where "p1 ... pn" are defined earlier as:
1350
//
1351
// [dcl.fct.def.coroutine]p3
1352
// The promise type of a coroutine is `std::coroutine_traits<R, P1, ...,
1353
// Pn>`
1354
// , where R is the return type of the function, and `P1, ..., Pn` are the
1355
// sequence of types of the non-object function parameters, preceded by the
1356
// type of the object parameter ([dcl.fct]) if the coroutine is a non-static
1357
// member function. [dcl.fct.def.coroutine]p4 In the following, p_i is an
1358
// lvalue of type P_i, where p1 denotes the object parameter and p_i+1 denotes
1359
// the i-th non-object function parameter for a non-static member function,
1360
// and p_i denotes the i-th function parameter otherwise. For a non-static
1361
// member function, q_1 is an lvalue that denotes *this; any other q_i is an
1362
// lvalue that denotes the parameter copy corresponding to p_i.
1363
1364
FunctionDecl *OperatorNew = nullptr;
1365
SmallVector<Expr *, 1> PlacementArgs;
1366
1367
const bool PromiseContainsNew = [this, &PromiseType]() -> bool {
1368
DeclarationName NewName =
1369
S.getASTContext().DeclarationNames.getCXXOperatorName(OO_New);
1370
LookupResult R(S, NewName, Loc, Sema::LookupOrdinaryName);
1371
1372
if (PromiseType->isRecordType())
1373
S.LookupQualifiedName(R, PromiseType->getAsCXXRecordDecl());
1374
1375
return !R.empty() && !R.isAmbiguous();
1376
}();
1377
1378
// Helper function to indicate whether the last lookup found the aligned
1379
// allocation function.
1380
bool PassAlignment = S.getLangOpts().CoroAlignedAllocation;
1381
auto LookupAllocationFunction = [&](Sema::AllocationFunctionScope NewScope =
1382
Sema::AFS_Both,
1383
bool WithoutPlacementArgs = false,
1384
bool ForceNonAligned = false) {
1385
// [dcl.fct.def.coroutine]p9
1386
// The allocation function's name is looked up by searching for it in the
1387
// scope of the promise type.
1388
// - If any declarations are found, ...
1389
// - If no declarations are found in the scope of the promise type, a search
1390
// is performed in the global scope.
1391
if (NewScope == Sema::AFS_Both)
1392
NewScope = PromiseContainsNew ? Sema::AFS_Class : Sema::AFS_Global;
1393
1394
PassAlignment = !ForceNonAligned && S.getLangOpts().CoroAlignedAllocation;
1395
FunctionDecl *UnusedResult = nullptr;
1396
S.FindAllocationFunctions(Loc, SourceRange(), NewScope,
1397
/*DeleteScope*/ Sema::AFS_Both, PromiseType,
1398
/*isArray*/ false, PassAlignment,
1399
WithoutPlacementArgs ? MultiExprArg{}
1400
: PlacementArgs,
1401
OperatorNew, UnusedResult, /*Diagnose*/ false);
1402
};
1403
1404
// We don't expect to call to global operator new with (size, p0, …, pn).
1405
// So if we choose to lookup the allocation function in global scope, we
1406
// shouldn't lookup placement arguments.
1407
if (PromiseContainsNew && !collectPlacementArgs(S, FD, Loc, PlacementArgs))
1408
return false;
1409
1410
LookupAllocationFunction();
1411
1412
if (PromiseContainsNew && !PlacementArgs.empty()) {
1413
// [dcl.fct.def.coroutine]p9
1414
// If no viable function is found ([over.match.viable]), overload
1415
// resolution
1416
// is performed again on a function call created by passing just the amount
1417
// of space required as an argument of type std::size_t.
1418
//
1419
// Proposed Change of [dcl.fct.def.coroutine]p9 in P2014R0:
1420
// Otherwise, overload resolution is performed again on a function call
1421
// created
1422
// by passing the amount of space requested as an argument of type
1423
// std::size_t as the first argument, and the requested alignment as
1424
// an argument of type std:align_val_t as the second argument.
1425
if (!OperatorNew ||
1426
(S.getLangOpts().CoroAlignedAllocation && !PassAlignment))
1427
LookupAllocationFunction(/*NewScope*/ Sema::AFS_Class,
1428
/*WithoutPlacementArgs*/ true);
1429
}
1430
1431
// Proposed Change of [dcl.fct.def.coroutine]p12 in P2014R0:
1432
// Otherwise, overload resolution is performed again on a function call
1433
// created
1434
// by passing the amount of space requested as an argument of type
1435
// std::size_t as the first argument, and the lvalues p1 ... pn as the
1436
// succeeding arguments. Otherwise, overload resolution is performed again
1437
// on a function call created by passing just the amount of space required as
1438
// an argument of type std::size_t.
1439
//
1440
// So within the proposed change in P2014RO, the priority order of aligned
1441
// allocation functions wiht promise_type is:
1442
//
1443
// void* operator new( std::size_t, std::align_val_t, placement_args... );
1444
// void* operator new( std::size_t, std::align_val_t);
1445
// void* operator new( std::size_t, placement_args... );
1446
// void* operator new( std::size_t);
1447
1448
// Helper variable to emit warnings.
1449
bool FoundNonAlignedInPromise = false;
1450
if (PromiseContainsNew && S.getLangOpts().CoroAlignedAllocation)
1451
if (!OperatorNew || !PassAlignment) {
1452
FoundNonAlignedInPromise = OperatorNew;
1453
1454
LookupAllocationFunction(/*NewScope*/ Sema::AFS_Class,
1455
/*WithoutPlacementArgs*/ false,
1456
/*ForceNonAligned*/ true);
1457
1458
if (!OperatorNew && !PlacementArgs.empty())
1459
LookupAllocationFunction(/*NewScope*/ Sema::AFS_Class,
1460
/*WithoutPlacementArgs*/ true,
1461
/*ForceNonAligned*/ true);
1462
}
1463
1464
bool IsGlobalOverload =
1465
OperatorNew && !isa<CXXRecordDecl>(OperatorNew->getDeclContext());
1466
// If we didn't find a class-local new declaration and non-throwing new
1467
// was is required then we need to lookup the non-throwing global operator
1468
// instead.
1469
if (RequiresNoThrowAlloc && (!OperatorNew || IsGlobalOverload)) {
1470
auto *StdNoThrow = buildStdNoThrowDeclRef(S, Loc);
1471
if (!StdNoThrow)
1472
return false;
1473
PlacementArgs = {StdNoThrow};
1474
OperatorNew = nullptr;
1475
LookupAllocationFunction(Sema::AFS_Global);
1476
}
1477
1478
// If we found a non-aligned allocation function in the promise_type,
1479
// it indicates the user forgot to update the allocation function. Let's emit
1480
// a warning here.
1481
if (FoundNonAlignedInPromise) {
1482
S.Diag(OperatorNew->getLocation(),
1483
diag::warn_non_aligned_allocation_function)
1484
<< &FD;
1485
}
1486
1487
if (!OperatorNew) {
1488
if (PromiseContainsNew)
1489
S.Diag(Loc, diag::err_coroutine_unusable_new) << PromiseType << &FD;
1490
else if (RequiresNoThrowAlloc)
1491
S.Diag(Loc, diag::err_coroutine_unfound_nothrow_new)
1492
<< &FD << S.getLangOpts().CoroAlignedAllocation;
1493
1494
return false;
1495
}
1496
1497
if (RequiresNoThrowAlloc) {
1498
const auto *FT = OperatorNew->getType()->castAs<FunctionProtoType>();
1499
if (!FT->isNothrow(/*ResultIfDependent*/ false)) {
1500
S.Diag(OperatorNew->getLocation(),
1501
diag::err_coroutine_promise_new_requires_nothrow)
1502
<< OperatorNew;
1503
S.Diag(Loc, diag::note_coroutine_promise_call_implicitly_required)
1504
<< OperatorNew;
1505
return false;
1506
}
1507
}
1508
1509
FunctionDecl *OperatorDelete = nullptr;
1510
if (!findDeleteForPromise(S, Loc, PromiseType, OperatorDelete)) {
1511
// FIXME: We should add an error here. According to:
1512
// [dcl.fct.def.coroutine]p12
1513
// If no usual deallocation function is found, the program is ill-formed.
1514
return false;
1515
}
1516
1517
Expr *FramePtr =
1518
S.BuildBuiltinCallExpr(Loc, Builtin::BI__builtin_coro_frame, {});
1519
1520
Expr *FrameSize =
1521
S.BuildBuiltinCallExpr(Loc, Builtin::BI__builtin_coro_size, {});
1522
1523
Expr *FrameAlignment = nullptr;
1524
1525
if (S.getLangOpts().CoroAlignedAllocation) {
1526
FrameAlignment =
1527
S.BuildBuiltinCallExpr(Loc, Builtin::BI__builtin_coro_align, {});
1528
1529
TypeSourceInfo *AlignValTy = getTypeSourceInfoForStdAlignValT(S, Loc);
1530
if (!AlignValTy)
1531
return false;
1532
1533
FrameAlignment = S.BuildCXXNamedCast(Loc, tok::kw_static_cast, AlignValTy,
1534
FrameAlignment, SourceRange(Loc, Loc),
1535
SourceRange(Loc, Loc))
1536
.get();
1537
}
1538
1539
// Make new call.
1540
ExprResult NewRef =
1541
S.BuildDeclRefExpr(OperatorNew, OperatorNew->getType(), VK_LValue, Loc);
1542
if (NewRef.isInvalid())
1543
return false;
1544
1545
SmallVector<Expr *, 2> NewArgs(1, FrameSize);
1546
if (S.getLangOpts().CoroAlignedAllocation && PassAlignment)
1547
NewArgs.push_back(FrameAlignment);
1548
1549
if (OperatorNew->getNumParams() > NewArgs.size())
1550
llvm::append_range(NewArgs, PlacementArgs);
1551
1552
ExprResult NewExpr =
1553
S.BuildCallExpr(S.getCurScope(), NewRef.get(), Loc, NewArgs, Loc);
1554
NewExpr = S.ActOnFinishFullExpr(NewExpr.get(), /*DiscardedValue*/ false);
1555
if (NewExpr.isInvalid())
1556
return false;
1557
1558
// Make delete call.
1559
1560
QualType OpDeleteQualType = OperatorDelete->getType();
1561
1562
ExprResult DeleteRef =
1563
S.BuildDeclRefExpr(OperatorDelete, OpDeleteQualType, VK_LValue, Loc);
1564
if (DeleteRef.isInvalid())
1565
return false;
1566
1567
Expr *CoroFree =
1568
S.BuildBuiltinCallExpr(Loc, Builtin::BI__builtin_coro_free, {FramePtr});
1569
1570
SmallVector<Expr *, 2> DeleteArgs{CoroFree};
1571
1572
// [dcl.fct.def.coroutine]p12
1573
// The selected deallocation function shall be called with the address of
1574
// the block of storage to be reclaimed as its first argument. If a
1575
// deallocation function with a parameter of type std::size_t is
1576
// used, the size of the block is passed as the corresponding argument.
1577
const auto *OpDeleteType =
1578
OpDeleteQualType.getTypePtr()->castAs<FunctionProtoType>();
1579
if (OpDeleteType->getNumParams() > DeleteArgs.size() &&
1580
S.getASTContext().hasSameUnqualifiedType(
1581
OpDeleteType->getParamType(DeleteArgs.size()), FrameSize->getType()))
1582
DeleteArgs.push_back(FrameSize);
1583
1584
// Proposed Change of [dcl.fct.def.coroutine]p12 in P2014R0:
1585
// If deallocation function lookup finds a usual deallocation function with
1586
// a pointer parameter, size parameter and alignment parameter then this
1587
// will be the selected deallocation function, otherwise if lookup finds a
1588
// usual deallocation function with both a pointer parameter and a size
1589
// parameter, then this will be the selected deallocation function.
1590
// Otherwise, if lookup finds a usual deallocation function with only a
1591
// pointer parameter, then this will be the selected deallocation
1592
// function.
1593
//
1594
// So we are not forced to pass alignment to the deallocation function.
1595
if (S.getLangOpts().CoroAlignedAllocation &&
1596
OpDeleteType->getNumParams() > DeleteArgs.size() &&
1597
S.getASTContext().hasSameUnqualifiedType(
1598
OpDeleteType->getParamType(DeleteArgs.size()),
1599
FrameAlignment->getType()))
1600
DeleteArgs.push_back(FrameAlignment);
1601
1602
ExprResult DeleteExpr =
1603
S.BuildCallExpr(S.getCurScope(), DeleteRef.get(), Loc, DeleteArgs, Loc);
1604
DeleteExpr =
1605
S.ActOnFinishFullExpr(DeleteExpr.get(), /*DiscardedValue*/ false);
1606
if (DeleteExpr.isInvalid())
1607
return false;
1608
1609
this->Allocate = NewExpr.get();
1610
this->Deallocate = DeleteExpr.get();
1611
1612
return true;
1613
}
1614
1615
bool CoroutineStmtBuilder::makeOnFallthrough() {
1616
assert(!IsPromiseDependentType &&
1617
"cannot make statement while the promise type is dependent");
1618
1619
// [dcl.fct.def.coroutine]/p6
1620
// If searches for the names return_void and return_value in the scope of
1621
// the promise type each find any declarations, the program is ill-formed.
1622
// [Note 1: If return_void is found, flowing off the end of a coroutine is
1623
// equivalent to a co_return with no operand. Otherwise, flowing off the end
1624
// of a coroutine results in undefined behavior ([stmt.return.coroutine]). —
1625
// end note]
1626
bool HasRVoid, HasRValue;
1627
LookupResult LRVoid =
1628
lookupMember(S, "return_void", PromiseRecordDecl, Loc, HasRVoid);
1629
LookupResult LRValue =
1630
lookupMember(S, "return_value", PromiseRecordDecl, Loc, HasRValue);
1631
1632
StmtResult Fallthrough;
1633
if (HasRVoid && HasRValue) {
1634
// FIXME Improve this diagnostic
1635
S.Diag(FD.getLocation(),
1636
diag::err_coroutine_promise_incompatible_return_functions)
1637
<< PromiseRecordDecl;
1638
S.Diag(LRVoid.getRepresentativeDecl()->getLocation(),
1639
diag::note_member_first_declared_here)
1640
<< LRVoid.getLookupName();
1641
S.Diag(LRValue.getRepresentativeDecl()->getLocation(),
1642
diag::note_member_first_declared_here)
1643
<< LRValue.getLookupName();
1644
return false;
1645
} else if (!HasRVoid && !HasRValue) {
1646
// We need to set 'Fallthrough'. Otherwise the other analysis part might
1647
// think the coroutine has defined a return_value method. So it might emit
1648
// **false** positive warning. e.g.,
1649
//
1650
// promise_without_return_func foo() {
1651
// co_await something();
1652
// }
1653
//
1654
// Then AnalysisBasedWarning would emit a warning about `foo()` lacking a
1655
// co_return statements, which isn't correct.
1656
Fallthrough = S.ActOnNullStmt(PromiseRecordDecl->getLocation());
1657
if (Fallthrough.isInvalid())
1658
return false;
1659
} else if (HasRVoid) {
1660
Fallthrough = S.BuildCoreturnStmt(FD.getLocation(), nullptr,
1661
/*IsImplicit=*/true);
1662
Fallthrough = S.ActOnFinishFullStmt(Fallthrough.get());
1663
if (Fallthrough.isInvalid())
1664
return false;
1665
}
1666
1667
this->OnFallthrough = Fallthrough.get();
1668
return true;
1669
}
1670
1671
bool CoroutineStmtBuilder::makeOnException() {
1672
// Try to form 'p.unhandled_exception();'
1673
assert(!IsPromiseDependentType &&
1674
"cannot make statement while the promise type is dependent");
1675
1676
const bool RequireUnhandledException = S.getLangOpts().CXXExceptions;
1677
1678
if (!lookupMember(S, "unhandled_exception", PromiseRecordDecl, Loc)) {
1679
auto DiagID =
1680
RequireUnhandledException
1681
? diag::err_coroutine_promise_unhandled_exception_required
1682
: diag::
1683
warn_coroutine_promise_unhandled_exception_required_with_exceptions;
1684
S.Diag(Loc, DiagID) << PromiseRecordDecl;
1685
S.Diag(PromiseRecordDecl->getLocation(), diag::note_defined_here)
1686
<< PromiseRecordDecl;
1687
return !RequireUnhandledException;
1688
}
1689
1690
// If exceptions are disabled, don't try to build OnException.
1691
if (!S.getLangOpts().CXXExceptions)
1692
return true;
1693
1694
ExprResult UnhandledException = buildPromiseCall(
1695
S, Fn.CoroutinePromise, Loc, "unhandled_exception", std::nullopt);
1696
UnhandledException = S.ActOnFinishFullExpr(UnhandledException.get(), Loc,
1697
/*DiscardedValue*/ false);
1698
if (UnhandledException.isInvalid())
1699
return false;
1700
1701
// Since the body of the coroutine will be wrapped in try-catch, it will
1702
// be incompatible with SEH __try if present in a function.
1703
if (!S.getLangOpts().Borland && Fn.FirstSEHTryLoc.isValid()) {
1704
S.Diag(Fn.FirstSEHTryLoc, diag::err_seh_in_a_coroutine_with_cxx_exceptions);
1705
S.Diag(Fn.FirstCoroutineStmtLoc, diag::note_declared_coroutine_here)
1706
<< Fn.getFirstCoroutineStmtKeyword();
1707
return false;
1708
}
1709
1710
this->OnException = UnhandledException.get();
1711
return true;
1712
}
1713
1714
bool CoroutineStmtBuilder::makeReturnObject() {
1715
// [dcl.fct.def.coroutine]p7
1716
// The expression promise.get_return_object() is used to initialize the
1717
// returned reference or prvalue result object of a call to a coroutine.
1718
ExprResult ReturnObject = buildPromiseCall(S, Fn.CoroutinePromise, Loc,
1719
"get_return_object", std::nullopt);
1720
if (ReturnObject.isInvalid())
1721
return false;
1722
1723
this->ReturnValue = ReturnObject.get();
1724
return true;
1725
}
1726
1727
static void noteMemberDeclaredHere(Sema &S, Expr *E, FunctionScopeInfo &Fn) {
1728
if (auto *MbrRef = dyn_cast<CXXMemberCallExpr>(E)) {
1729
auto *MethodDecl = MbrRef->getMethodDecl();
1730
S.Diag(MethodDecl->getLocation(), diag::note_member_declared_here)
1731
<< MethodDecl;
1732
}
1733
S.Diag(Fn.FirstCoroutineStmtLoc, diag::note_declared_coroutine_here)
1734
<< Fn.getFirstCoroutineStmtKeyword();
1735
}
1736
1737
bool CoroutineStmtBuilder::makeGroDeclAndReturnStmt() {
1738
assert(!IsPromiseDependentType &&
1739
"cannot make statement while the promise type is dependent");
1740
assert(this->ReturnValue && "ReturnValue must be already formed");
1741
1742
QualType const GroType = this->ReturnValue->getType();
1743
assert(!GroType->isDependentType() &&
1744
"get_return_object type must no longer be dependent");
1745
1746
QualType const FnRetType = FD.getReturnType();
1747
assert(!FnRetType->isDependentType() &&
1748
"get_return_object type must no longer be dependent");
1749
1750
// The call to get_­return_­object is sequenced before the call to
1751
// initial_­suspend and is invoked at most once, but there are caveats
1752
// regarding on whether the prvalue result object may be initialized
1753
// directly/eager or delayed, depending on the types involved.
1754
//
1755
// More info at https://github.com/cplusplus/papers/issues/1414
1756
bool GroMatchesRetType = S.getASTContext().hasSameType(GroType, FnRetType);
1757
1758
if (FnRetType->isVoidType()) {
1759
ExprResult Res =
1760
S.ActOnFinishFullExpr(this->ReturnValue, Loc, /*DiscardedValue*/ false);
1761
if (Res.isInvalid())
1762
return false;
1763
1764
if (!GroMatchesRetType)
1765
this->ResultDecl = Res.get();
1766
return true;
1767
}
1768
1769
if (GroType->isVoidType()) {
1770
// Trigger a nice error message.
1771
InitializedEntity Entity =
1772
InitializedEntity::InitializeResult(Loc, FnRetType);
1773
S.PerformCopyInitialization(Entity, SourceLocation(), ReturnValue);
1774
noteMemberDeclaredHere(S, ReturnValue, Fn);
1775
return false;
1776
}
1777
1778
StmtResult ReturnStmt;
1779
clang::VarDecl *GroDecl = nullptr;
1780
if (GroMatchesRetType) {
1781
ReturnStmt = S.BuildReturnStmt(Loc, ReturnValue);
1782
} else {
1783
GroDecl = VarDecl::Create(
1784
S.Context, &FD, FD.getLocation(), FD.getLocation(),
1785
&S.PP.getIdentifierTable().get("__coro_gro"), GroType,
1786
S.Context.getTrivialTypeSourceInfo(GroType, Loc), SC_None);
1787
GroDecl->setImplicit();
1788
1789
S.CheckVariableDeclarationType(GroDecl);
1790
if (GroDecl->isInvalidDecl())
1791
return false;
1792
1793
InitializedEntity Entity = InitializedEntity::InitializeVariable(GroDecl);
1794
ExprResult Res =
1795
S.PerformCopyInitialization(Entity, SourceLocation(), ReturnValue);
1796
if (Res.isInvalid())
1797
return false;
1798
1799
Res = S.ActOnFinishFullExpr(Res.get(), /*DiscardedValue*/ false);
1800
if (Res.isInvalid())
1801
return false;
1802
1803
S.AddInitializerToDecl(GroDecl, Res.get(),
1804
/*DirectInit=*/false);
1805
1806
S.FinalizeDeclaration(GroDecl);
1807
1808
// Form a declaration statement for the return declaration, so that AST
1809
// visitors can more easily find it.
1810
StmtResult GroDeclStmt =
1811
S.ActOnDeclStmt(S.ConvertDeclToDeclGroup(GroDecl), Loc, Loc);
1812
if (GroDeclStmt.isInvalid())
1813
return false;
1814
1815
this->ResultDecl = GroDeclStmt.get();
1816
1817
ExprResult declRef = S.BuildDeclRefExpr(GroDecl, GroType, VK_LValue, Loc);
1818
if (declRef.isInvalid())
1819
return false;
1820
1821
ReturnStmt = S.BuildReturnStmt(Loc, declRef.get());
1822
}
1823
1824
if (ReturnStmt.isInvalid()) {
1825
noteMemberDeclaredHere(S, ReturnValue, Fn);
1826
return false;
1827
}
1828
1829
if (!GroMatchesRetType &&
1830
cast<clang::ReturnStmt>(ReturnStmt.get())->getNRVOCandidate() == GroDecl)
1831
GroDecl->setNRVOVariable(true);
1832
1833
this->ReturnStmt = ReturnStmt.get();
1834
return true;
1835
}
1836
1837
// Create a static_cast\<T&&>(expr).
1838
static Expr *castForMoving(Sema &S, Expr *E, QualType T = QualType()) {
1839
if (T.isNull())
1840
T = E->getType();
1841
QualType TargetType = S.BuildReferenceType(
1842
T, /*SpelledAsLValue*/ false, SourceLocation(), DeclarationName());
1843
SourceLocation ExprLoc = E->getBeginLoc();
1844
TypeSourceInfo *TargetLoc =
1845
S.Context.getTrivialTypeSourceInfo(TargetType, ExprLoc);
1846
1847
return S
1848
.BuildCXXNamedCast(ExprLoc, tok::kw_static_cast, TargetLoc, E,
1849
SourceRange(ExprLoc, ExprLoc), E->getSourceRange())
1850
.get();
1851
}
1852
1853
/// Build a variable declaration for move parameter.
1854
static VarDecl *buildVarDecl(Sema &S, SourceLocation Loc, QualType Type,
1855
IdentifierInfo *II) {
1856
TypeSourceInfo *TInfo = S.Context.getTrivialTypeSourceInfo(Type, Loc);
1857
VarDecl *Decl = VarDecl::Create(S.Context, S.CurContext, Loc, Loc, II, Type,
1858
TInfo, SC_None);
1859
Decl->setImplicit();
1860
return Decl;
1861
}
1862
1863
// Build statements that move coroutine function parameters to the coroutine
1864
// frame, and store them on the function scope info.
1865
bool Sema::buildCoroutineParameterMoves(SourceLocation Loc) {
1866
assert(isa<FunctionDecl>(CurContext) && "not in a function scope");
1867
auto *FD = cast<FunctionDecl>(CurContext);
1868
1869
auto *ScopeInfo = getCurFunction();
1870
if (!ScopeInfo->CoroutineParameterMoves.empty())
1871
return false;
1872
1873
// [dcl.fct.def.coroutine]p13
1874
// When a coroutine is invoked, after initializing its parameters
1875
// ([expr.call]), a copy is created for each coroutine parameter. For a
1876
// parameter of type cv T, the copy is a variable of type cv T with
1877
// automatic storage duration that is direct-initialized from an xvalue of
1878
// type T referring to the parameter.
1879
for (auto *PD : FD->parameters()) {
1880
if (PD->getType()->isDependentType())
1881
continue;
1882
1883
// Preserve the referenced state for unused parameter diagnostics.
1884
bool DeclReferenced = PD->isReferenced();
1885
1886
ExprResult PDRefExpr =
1887
BuildDeclRefExpr(PD, PD->getType().getNonReferenceType(),
1888
ExprValueKind::VK_LValue, Loc); // FIXME: scope?
1889
1890
PD->setReferenced(DeclReferenced);
1891
1892
if (PDRefExpr.isInvalid())
1893
return false;
1894
1895
Expr *CExpr = nullptr;
1896
if (PD->getType()->getAsCXXRecordDecl() ||
1897
PD->getType()->isRValueReferenceType())
1898
CExpr = castForMoving(*this, PDRefExpr.get());
1899
else
1900
CExpr = PDRefExpr.get();
1901
// [dcl.fct.def.coroutine]p13
1902
// The initialization and destruction of each parameter copy occurs in the
1903
// context of the called coroutine.
1904
auto *D = buildVarDecl(*this, Loc, PD->getType(), PD->getIdentifier());
1905
AddInitializerToDecl(D, CExpr, /*DirectInit=*/true);
1906
1907
// Convert decl to a statement.
1908
StmtResult Stmt = ActOnDeclStmt(ConvertDeclToDeclGroup(D), Loc, Loc);
1909
if (Stmt.isInvalid())
1910
return false;
1911
1912
ScopeInfo->CoroutineParameterMoves.insert(std::make_pair(PD, Stmt.get()));
1913
}
1914
return true;
1915
}
1916
1917
StmtResult Sema::BuildCoroutineBodyStmt(CoroutineBodyStmt::CtorArgs Args) {
1918
CoroutineBodyStmt *Res = CoroutineBodyStmt::Create(Context, Args);
1919
if (!Res)
1920
return StmtError();
1921
return Res;
1922
}
1923
1924
ClassTemplateDecl *Sema::lookupCoroutineTraits(SourceLocation KwLoc,
1925
SourceLocation FuncLoc) {
1926
if (StdCoroutineTraitsCache)
1927
return StdCoroutineTraitsCache;
1928
1929
IdentifierInfo const &TraitIdent =
1930
PP.getIdentifierTable().get("coroutine_traits");
1931
1932
NamespaceDecl *StdSpace = getStdNamespace();
1933
LookupResult Result(*this, &TraitIdent, FuncLoc, LookupOrdinaryName);
1934
bool Found = StdSpace && LookupQualifiedName(Result, StdSpace);
1935
1936
if (!Found) {
1937
// The goggles, we found nothing!
1938
Diag(KwLoc, diag::err_implied_coroutine_type_not_found)
1939
<< "std::coroutine_traits";
1940
return nullptr;
1941
}
1942
1943
// coroutine_traits is required to be a class template.
1944
StdCoroutineTraitsCache = Result.getAsSingle<ClassTemplateDecl>();
1945
if (!StdCoroutineTraitsCache) {
1946
Result.suppressDiagnostics();
1947
NamedDecl *Found = *Result.begin();
1948
Diag(Found->getLocation(), diag::err_malformed_std_coroutine_traits);
1949
return nullptr;
1950
}
1951
1952
return StdCoroutineTraitsCache;
1953
}
1954
1955