static bool actOnCoroutineBodyStart(Sema &S, Scope *SC, SourceLocation KWLoc, StringRef Keyword) { if (!checkCoroutineContext(S, KWLoc, Keyword)) return false; auto *ScopeInfo = S.getCurFunction(); assert(ScopeInfo->CoroutinePromise); // If we have existing coroutine statements then we have already built // the initial and final suspend points. if (!ScopeInfo->NeedsCoroutineSuspends) return true; ScopeInfo->setNeedsCoroutineSuspends(false); auto *Fn = cast<FunctionDecl>(S.CurContext); SourceLocation Loc = Fn->getLocation(); // Build the initial suspend point auto buildSuspends = [&](StringRef Name) mutable -> StmtResult { ExprResult Suspend = buildPromiseCall(S, ScopeInfo->CoroutinePromise, Loc, Name, None); if (Suspend.isInvalid()) return StmtError(); Suspend = buildOperatorCoawaitCall(S, SC, Loc, Suspend.get()); if (Suspend.isInvalid()) return StmtError(); Suspend = S.BuildResolvedCoawaitExpr(Loc, Suspend.get(), /*IsImplicit*/ true); Suspend = S.ActOnFinishFullExpr(Suspend.get()); if (Suspend.isInvalid()) { S.Diag(Loc, diag::note_coroutine_promise_suspend_implicitly_required) << ((Name == "initial_suspend") ? 0 : 1); S.Diag(KWLoc, diag::note_declared_coroutine_here) << Keyword; return StmtError(); } return cast<Stmt>(Suspend.get()); }; StmtResult InitSuspend = buildSuspends("initial_suspend"); if (InitSuspend.isInvalid()) return true; StmtResult FinalSuspend = buildSuspends("final_suspend"); if (FinalSuspend.isInvalid()) return true; ScopeInfo->setCoroutineSuspends(InitSuspend.get(), FinalSuspend.get()); return true; }
StmtResult Parser::HandlePragmaCaptured() { assert(Tok.is(tok::annot_pragma_captured)); ConsumeToken(); if (Tok.isNot(tok::l_brace)) { PP.Diag(Tok, diag::err_expected_lbrace); return StmtError(); } SourceLocation Loc = Tok.getLocation(); ParseScope CapturedRegionScope(this, Scope::FnScope | Scope::DeclScope); Actions.ActOnCapturedRegionStart(Loc, getCurScope(), CR_Default); StmtResult R = ParseCompoundStatement(); CapturedRegionScope.Exit(); if (R.isInvalid()) { Actions.ActOnCapturedRegionError(); return StmtError(); } return Actions.ActOnCapturedRegionEnd(R.get()); }
bool VisitCompoundStmt(CompoundStmt* CS) { for(CompoundStmt::body_iterator I = CS->body_begin(), E = CS->body_end(); I != E; ++I) { if (!isa<BinaryOperator>(*I)) continue; const BinaryOperator* BinOp = cast<BinaryOperator>(*I); if (isAutoCandidate(BinOp)) { ASTContext& C = m_Sema->getASTContext(); VarDecl* VD = cast<VarDecl>(cast<DeclRefExpr>(BinOp->getLHS())->getDecl()); TypeSourceInfo* ResTSI = 0; TypeSourceInfo* TrivialTSI = C.getTrivialTypeSourceInfo(VD->getType()); Expr* RHS = BinOp->getRHS(); m_Sema->DeduceAutoType(TrivialTSI, RHS, ResTSI); VD->setTypeSourceInfo(ResTSI); VD->setType(ResTSI->getType()); VD->setInit(RHS); Sema::DeclGroupPtrTy VDPtrTy = m_Sema->ConvertDeclToDeclGroup(VD); // Transform the AST into a "sane" state. Replace the binary operator // with decl stmt, because the binop semantically is a decl with init. StmtResult DS = m_Sema->ActOnDeclStmt(VDPtrTy, BinOp->getLocStart(), BinOp->getLocEnd()); assert(!DS.isInvalid() && "Invalid DeclStmt."); *I = DS.take(); } } return true; // returning false will abort the in-depth traversal. }
StmtResult Sema::ActOnCoreturnStmt(SourceLocation Loc, Expr *E) { auto *Context = checkCoroutineContext(*this, Loc, "co_return"); StmtResult Res = StmtError(); if (Context && !Res.isInvalid()) Context->CoroutineStmts.push_back(Res.get()); return Res; }
/// ParseMainProgram - Parse the main program. /// /// [R1101]: /// main-program := /// [program-stmt] /// [specification-part] /// [execution-part] /// [internal-subprogram-part] /// end-program-stmt bool Parser::ParseMainProgram(std::vector<StmtResult> &Body) { // If the PROGRAM statement didn't have an identifier, pretend like it did for // the time being. StmtResult ProgStmt; if (Tok.is(tok::kw_PROGRAM)) { ProgStmt = ParsePROGRAMStmt(); Body.push_back(ProgStmt); } // If the PROGRAM statement has an identifier, pass it on to the main program // action. const IdentifierInfo *IDInfo = 0; SMLoc NameLoc; if (ProgStmt.isUsable()) { ProgramStmt *PS = ProgStmt.takeAs<ProgramStmt>(); IDInfo = PS->getProgramName(); NameLoc = PS->getNameLocation(); // FIXME: Debugging dump(PS); } Actions.ActOnMainProgram(IDInfo, NameLoc); // FIXME: Check for the specific keywords and not just absence of END or // ENDPROGRAM. ParseStatementLabel(); if (Tok.isNot(tok::kw_END) && Tok.isNot(tok::kw_ENDPROGRAM)) ParseSpecificationPart(Body); // FIXME: Check for the specific keywords and not just absence of END or // ENDPROGRAM. ParseStatementLabel(); if (Tok.isNot(tok::kw_END) && Tok.isNot(tok::kw_ENDPROGRAM)) ParseExecutionPart(Body); // FIXME: Debugging support. dump(Body); ParseStatementLabel(); StmtResult EndProgStmt = ParseEND_PROGRAMStmt(); Body.push_back(EndProgStmt); IDInfo = 0; NameLoc = SMLoc(); if (EndProgStmt.isUsable()) { EndProgramStmt *EPS = EndProgStmt.takeAs<EndProgramStmt>(); IDInfo = EPS->getProgramName(); NameLoc = EPS->getNameLocation(); } Actions.ActOnEndMainProgram(IDInfo, NameLoc); return EndProgStmt.isInvalid(); }
bool CoroutineStmtBuilder::makePromiseStmt() { // Form a declaration statement for the promise declaration, so that AST // visitors can more easily find it. StmtResult PromiseStmt = S.ActOnDeclStmt(S.ConvertDeclToDeclGroup(Fn.CoroutinePromise), Loc, Loc); if (PromiseStmt.isInvalid()) return false; this->Promise = PromiseStmt.get(); return true; }
/// ParseSpecificationPart - Parse the specification part. /// /// [R204]: /// specification-part := /// [use-stmt] ... /// [import-stmt] ... /// [implicit-part] ... /// [declaration-construct] ... bool Parser::ParseSpecificationPart(std::vector<StmtResult> &Body) { bool HasErrors = false; while (Tok.is(tok::kw_USE)) { StmtResult S = ParseUSEStmt(); if (S.isUsable()) { Body.push_back(S); } else if (S.isInvalid()) { LexToEndOfStatement(); HasErrors = true; } else { break; } ParseStatementLabel(); } while (Tok.is(tok::kw_IMPORT)) { StmtResult S = ParseIMPORTStmt(); if (S.isUsable()) { Body.push_back(S); } else if (S.isInvalid()) { LexToEndOfStatement(); HasErrors = true; } else { break; } ParseStatementLabel(); } if (ParseImplicitPartList(Body)) HasErrors = true; if (ParseDeclarationConstructList()) { LexToEndOfStatement(); HasErrors = true; } return HasErrors; }
/// ParseExecutableConstruct - Parse the executable construct. /// /// [R213]: /// executable-construct := /// action-stmt /// or associate-construct /// or block-construct /// or case-construct /// or critical-construct /// or do-construct /// or forall-construct /// or if-construct /// or select-type-construct /// or where-construct StmtResult Parser::ParseExecutableConstruct() { ParseStatementLabel(); ParseConstructNameLabel(); LookForExecutableStmtKeyword(StmtLabel || StmtConstructName.isUsable()? false : true); auto Loc = Tok.getLocation(); StmtResult SR = ParseActionStmt(); CheckStmtOrder(Loc, SR); if (SR.isInvalid()) return StmtError(); if (!SR.isUsable()) return StmtResult(); return SR; }
bool CoroutineStmtBuilder::makeOnFallthrough() { assert(!IsPromiseDependentType && "cannot make statement while the promise type is dependent"); // [dcl.fct.def.coroutine]/4 // The unqualified-ids 'return_void' and 'return_value' are looked up in // the scope of class P. If both are found, the program is ill-formed. bool HasRVoid, HasRValue; LookupResult LRVoid = lookupMember(S, "return_void", PromiseRecordDecl, Loc, HasRVoid); LookupResult LRValue = lookupMember(S, "return_value", PromiseRecordDecl, Loc, HasRValue); StmtResult Fallthrough; if (HasRVoid && HasRValue) { // FIXME Improve this diagnostic S.Diag(FD.getLocation(), diag::err_coroutine_promise_incompatible_return_functions) << PromiseRecordDecl; S.Diag(LRVoid.getRepresentativeDecl()->getLocation(), diag::note_member_first_declared_here) << LRVoid.getLookupName(); S.Diag(LRValue.getRepresentativeDecl()->getLocation(), diag::note_member_first_declared_here) << LRValue.getLookupName(); return false; } else if (!HasRVoid && !HasRValue) { // FIXME: The PDTS currently specifies this case as UB, not ill-formed. // However we still diagnose this as an error since until the PDTS is fixed. S.Diag(FD.getLocation(), diag::err_coroutine_promise_requires_return_function) << PromiseRecordDecl; S.Diag(PromiseRecordDecl->getLocation(), diag::note_defined_here) << PromiseRecordDecl; return false; } else if (HasRVoid) { // If the unqualified-id return_void is found, flowing off the end of a // coroutine is equivalent to a co_return with no operand. Otherwise, // flowing off the end of a coroutine results in undefined behavior. Fallthrough = S.BuildCoreturnStmt(FD.getLocation(), nullptr, /*IsImplicit*/false); Fallthrough = S.ActOnFinishFullStmt(Fallthrough.get()); if (Fallthrough.isInvalid()) return false; } this->OnFallthrough = Fallthrough.get(); return true; }
/// ParseExecutionPart - Parse the execution part. /// /// [R208]: /// execution-part := /// executable-construct /// [ execution-part-construct ] ... bool Parser::ParseExecutionPart(std::vector<StmtResult> &Body) { bool HadError = false; while (true) { StmtResult SR = ParseExecutableConstruct(); if (SR.isInvalid()) { LexToEndOfStatement(); HadError = true; } else if (!SR.isUsable()) { break; } Body.push_back(SR); } return HadError; }
/// ParseImplicitPartList - Parse a (possibly empty) list of implicit part /// statements. bool Parser::ParseImplicitPartList(std::vector<StmtResult> &Body) { bool HasErrors = false; while (true) { StmtResult S = ParseImplicitPart(); if (S.isUsable()) { Body.push_back(S); } else if (S.isInvalid()) { LexToEndOfStatement(); HasErrors = true; } else { break; } } return HasErrors; }
bool CoroutineStmtBuilder::makeReturnOnAllocFailure() { assert(!IsPromiseDependentType && "cannot make statement while the promise type is dependent"); // [dcl.fct.def.coroutine]/8 // The unqualified-id get_return_object_on_allocation_failure is looked up in // the scope of class P by class member access lookup (3.4.5). ... // If an allocation function returns nullptr, ... the coroutine return value // is obtained by a call to ... get_return_object_on_allocation_failure(). DeclarationName DN = S.PP.getIdentifierInfo("get_return_object_on_allocation_failure"); LookupResult Found(S, DN, Loc, Sema::LookupMemberName); if (!S.LookupQualifiedName(Found, PromiseRecordDecl)) return true; CXXScopeSpec SS; ExprResult DeclNameExpr = S.BuildDeclarationNameExpr(SS, Found, /*NeedsADL=*/false); if (DeclNameExpr.isInvalid()) return false; if (!diagReturnOnAllocFailure(S, DeclNameExpr.get(), PromiseRecordDecl, Fn)) return false; ExprResult ReturnObjectOnAllocationFailure = S.ActOnCallExpr(nullptr, DeclNameExpr.get(), Loc, {}, Loc); if (ReturnObjectOnAllocationFailure.isInvalid()) return false; StmtResult ReturnStmt = S.BuildReturnStmt(Loc, ReturnObjectOnAllocationFailure.get()); if (ReturnStmt.isInvalid()) { S.Diag(Found.getFoundDecl()->getLocation(), diag::note_member_declared_here) << DN; S.Diag(Fn.FirstCoroutineStmtLoc, diag::note_declared_coroutine_here) << Fn.getFirstCoroutineStmtKeyword(); return false; } this->ReturnStmtOnAllocFailure = ReturnStmt.get(); return true; }
void Fix(CompoundStmt* CS) { if (!CS->size()) return; typedef llvm::SmallVector<Stmt*, 32> Statements; Statements Stmts; Stmts.append(CS->body_begin(), CS->body_end()); for (Statements::iterator I = Stmts.begin(); I != Stmts.end(); ++I) { if (!TraverseStmt(*I) && !m_HandledDecls.count(m_FoundDRE->getDecl())) { Sema::DeclGroupPtrTy VDPtrTy = m_Sema->ConvertDeclToDeclGroup(m_FoundDRE->getDecl()); StmtResult DS = m_Sema->ActOnDeclStmt(VDPtrTy, m_FoundDRE->getLocStart(), m_FoundDRE->getLocEnd()); assert(!DS.isInvalid() && "Invalid DeclStmt."); I = Stmts.insert(I, DS.take()); m_HandledDecls.insert(m_FoundDRE->getDecl()); } } CS->setStmts(m_Sema->getASTContext(), Stmts.data(), Stmts.size()); }
bool CoroutineStmtBuilder::makeParamMoves() { for (auto *paramDecl : FD.parameters()) { auto Ty = paramDecl->getType(); if (Ty->isDependentType()) continue; // No need to copy scalars, llvm will take care of them. if (Ty->getAsCXXRecordDecl()) { if (!paramDecl->getIdentifier()) continue; ExprResult ParamRef = S.BuildDeclRefExpr(paramDecl, paramDecl->getType(), ExprValueKind::VK_LValue, Loc); // FIXME: scope? if (ParamRef.isInvalid()) return false; Expr *RCast = castForMoving(S, ParamRef.get()); auto D = buildVarDecl(S, Loc, Ty, paramDecl->getIdentifier()->getName()); S.AddInitializerToDecl(D, RCast, /*DirectInit=*/true); // Convert decl to a statement. StmtResult Stmt = S.ActOnDeclStmt(S.ConvertDeclToDeclGroup(D), Loc, Loc); if (Stmt.isInvalid()) return false; ParamMovesVector.push_back(Stmt.get()); } } // Convert to ArrayRef in CtorArgs structure that builder inherits from. ParamMoves = ParamMovesVector; return true; }
bool CoroutineStmtBuilder::makeGroDeclAndReturnStmt() { assert(!IsPromiseDependentType && "cannot make statement while the promise type is dependent"); assert(this->ReturnValue && "ReturnValue must be already formed"); QualType const GroType = this->ReturnValue->getType(); assert(!GroType->isDependentType() && "get_return_object type must no longer be dependent"); QualType const FnRetType = FD.getReturnType(); assert(!FnRetType->isDependentType() && "get_return_object type must no longer be dependent"); if (FnRetType->isVoidType()) { ExprResult Res = S.ActOnFinishFullExpr(this->ReturnValue, Loc); if (Res.isInvalid()) return false; this->ResultDecl = Res.get(); return true; } if (GroType->isVoidType()) { // Trigger a nice error message. InitializedEntity Entity = InitializedEntity::InitializeResult(Loc, FnRetType, false); S.PerformMoveOrCopyInitialization(Entity, nullptr, FnRetType, ReturnValue); noteMemberDeclaredHere(S, ReturnValue, Fn); return false; } auto *GroDecl = VarDecl::Create( S.Context, &FD, FD.getLocation(), FD.getLocation(), &S.PP.getIdentifierTable().get("__coro_gro"), GroType, S.Context.getTrivialTypeSourceInfo(GroType, Loc), SC_None); S.CheckVariableDeclarationType(GroDecl); if (GroDecl->isInvalidDecl()) return false; InitializedEntity Entity = InitializedEntity::InitializeVariable(GroDecl); ExprResult Res = S.PerformMoveOrCopyInitialization(Entity, nullptr, GroType, this->ReturnValue); if (Res.isInvalid()) return false; Res = S.ActOnFinishFullExpr(Res.get()); if (Res.isInvalid()) return false; if (GroType == FnRetType) { GroDecl->setNRVOVariable(true); } S.AddInitializerToDecl(GroDecl, Res.get(), /*DirectInit=*/false); S.FinalizeDeclaration(GroDecl); // Form a declaration statement for the return declaration, so that AST // visitors can more easily find it. StmtResult GroDeclStmt = S.ActOnDeclStmt(S.ConvertDeclToDeclGroup(GroDecl), Loc, Loc); if (GroDeclStmt.isInvalid()) return false; this->ResultDecl = GroDeclStmt.get(); ExprResult declRef = S.BuildDeclRefExpr(GroDecl, GroType, VK_LValue, Loc); if (declRef.isInvalid()) return false; StmtResult ReturnStmt = S.BuildReturnStmt(Loc, declRef.get()); if (ReturnStmt.isInvalid()) { noteMemberDeclaredHere(S, ReturnValue, Fn); return false; } this->ReturnStmt = ReturnStmt.get(); return true; }