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