diff options
| author | Richard Smith <richard-llvm@metafoo.co.uk> | 2015-10-27 06:02:45 +0000 |
|---|---|---|
| committer | Richard Smith <richard-llvm@metafoo.co.uk> | 2015-10-27 06:02:45 +0000 |
| commit | 9f690bd80bb67d483df2b9e15261e548f8b3a474 (patch) | |
| tree | c4d74a57ede2212275c7594e815508082249bb93 /clang/lib | |
| parent | d5510d1e5c2d0e4d18389f1f0c1f649cecea5d3a (diff) | |
| download | bcm5719-llvm-9f690bd80bb67d483df2b9e15261e548f8b3a474.tar.gz bcm5719-llvm-9f690bd80bb67d483df2b9e15261e548f8b3a474.zip | |
[coroutines] Creation of promise object, lookup of operator co_await, building
of await_* calls, and AST representation for same.
llvm-svn: 251387
Diffstat (limited to 'clang/lib')
23 files changed, 487 insertions, 81 deletions
diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp index 6816dd11d9b..ccc6931a5ff 100644 --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/lib/AST/ASTImporter.cpp @@ -4915,13 +4915,14 @@ Stmt *ASTNodeImporter::VisitCXXForRangeStmt(CXXForRangeStmt *S) { if (!ToBody && S->getBody()) return nullptr; SourceLocation ToForLoc = Importer.Import(S->getForLoc()); + SourceLocation ToCoawaitLoc = Importer.Import(S->getCoawaitLoc()); SourceLocation ToColonLoc = Importer.Import(S->getColonLoc()); SourceLocation ToRParenLoc = Importer.Import(S->getRParenLoc()); return new (Importer.getToContext()) CXXForRangeStmt(ToRange, ToBeginEnd, ToCond, ToInc, ToLoopVar, ToBody, - ToForLoc, ToColonLoc, - ToRParenLoc); + ToForLoc, ToCoawaitLoc, + ToColonLoc, ToRParenLoc); } Stmt *ASTNodeImporter::VisitObjCForCollectionStmt(ObjCForCollectionStmt *S) { diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp index 1dd54d293d9..dbc890d292d 100644 --- a/clang/lib/AST/Expr.cpp +++ b/clang/lib/AST/Expr.cpp @@ -1079,6 +1079,7 @@ StringRef UnaryOperator::getOpcodeStr(Opcode Op) { case UO_Real: return "__real"; case UO_Imag: return "__imag"; case UO_Extension: return "__extension__"; + case UO_Coawait: return "co_await"; } llvm_unreachable("Unknown unary operator"); } @@ -1095,6 +1096,7 @@ UnaryOperator::getOverloadedOpcode(OverloadedOperatorKind OO, bool Postfix) { case OO_Minus: return UO_Minus; case OO_Tilde: return UO_Not; case OO_Exclaim: return UO_LNot; + case OO_Coawait: return UO_Coawait; } } @@ -1108,6 +1110,7 @@ OverloadedOperatorKind UnaryOperator::getOverloadedOperator(Opcode Opc) { case UO_Minus: return OO_Minus; case UO_Not: return OO_Tilde; case UO_LNot: return OO_Exclaim; + case UO_Coawait: return OO_Coawait; default: return OO_None; } } @@ -2050,6 +2053,9 @@ bool Expr::isUnusedResultAWarning(const Expr *&WarnE, SourceLocation &Loc, case UO_LNot: case UO_Deref: break; + case UO_Coawait: + // This is just the 'operator co_await' call inside the guts of a + // dependent co_await call. case UO_PostInc: case UO_PostDec: case UO_PreInc: @@ -3005,6 +3011,8 @@ bool Expr::HasSideEffects(const ASTContext &Ctx, case CXXNewExprClass: case CXXDeleteExprClass: case ExprWithCleanupsClass: + case CoawaitExprClass: + case CoyieldExprClass: // These always have a side-effect. return true; diff --git a/clang/lib/AST/ExprClassification.cpp b/clang/lib/AST/ExprClassification.cpp index 882c786c357..a5a44353a29 100644 --- a/clang/lib/AST/ExprClassification.cpp +++ b/clang/lib/AST/ExprClassification.cpp @@ -186,6 +186,7 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) { case Expr::CXXFoldExprClass: case Expr::NoInitExprClass: case Expr::DesignatedInitUpdateExprClass: + case Expr::CoyieldExprClass: return Cl::CL_PRValue; // Next come the complicated cases. @@ -397,6 +398,9 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) { assert(cast<InitListExpr>(E)->getNumInits() == 1 && "Only 1-element init lists can be glvalues."); return ClassifyInternal(Ctx, cast<InitListExpr>(E)->getInit(0)); + + case Expr::CoawaitExprClass: + return ClassifyInternal(Ctx, cast<CoawaitExpr>(E)->getResumeExpr()); } llvm_unreachable("unhandled expression kind in classification"); diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index 08fcd260a3b..e59902ddd8b 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -9017,6 +9017,8 @@ static ICEDiag CheckICE(const Expr* E, const ASTContext &Ctx) { case Expr::AtomicExprClass: case Expr::LambdaExprClass: case Expr::CXXFoldExprClass: + case Expr::CoawaitExprClass: + case Expr::CoyieldExprClass: return ICEDiag(IK_NotICE, E->getLocStart()); case Expr::InitListExprClass: { @@ -9102,6 +9104,7 @@ static ICEDiag CheckICE(const Expr* E, const ASTContext &Ctx) { case UO_PreDec: case UO_AddrOf: case UO_Deref: + case UO_Coawait: // C99 6.6/3 allows increment and decrement within unevaluated // subexpressions of constant expressions, but they can never be ICEs // because an ICE cannot contain an lvalue operand. diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp index 86bc8e67756..c3432839c2e 100644 --- a/clang/lib/AST/ItaniumMangle.cpp +++ b/clang/lib/AST/ItaniumMangle.cpp @@ -3514,6 +3514,18 @@ recurse: case Expr::CXXThisExprClass: Out << "fpT"; break; + + case Expr::CoawaitExprClass: + // FIXME: Propose a non-vendor mangling. + Out << "v18co_await"; + mangleExpression(cast<CoawaitExpr>(E)->getOperand()); + break; + + case Expr::CoyieldExprClass: + // FIXME: Propose a non-vendor mangling. + Out << "v18co_yield"; + mangleExpression(cast<CoawaitExpr>(E)->getOperand()); + break; } } diff --git a/clang/lib/AST/StmtCXX.cpp b/clang/lib/AST/StmtCXX.cpp index aa721468e2f..e39a01daf96 100644 --- a/clang/lib/AST/StmtCXX.cpp +++ b/clang/lib/AST/StmtCXX.cpp @@ -52,8 +52,10 @@ CXXTryStmt::CXXTryStmt(SourceLocation tryLoc, Stmt *tryBlock, CXXForRangeStmt::CXXForRangeStmt(DeclStmt *Range, DeclStmt *BeginEndStmt, Expr *Cond, Expr *Inc, DeclStmt *LoopVar, Stmt *Body, SourceLocation FL, - SourceLocation CL, SourceLocation RPL) - : Stmt(CXXForRangeStmtClass), ForLoc(FL), ColonLoc(CL), RParenLoc(RPL) { + SourceLocation CAL, SourceLocation CL, + SourceLocation RPL) + : Stmt(CXXForRangeStmtClass), ForLoc(FL), CoawaitLoc(CAL), ColonLoc(CL), + RParenLoc(RPL) { SubExprs[RANGE] = Range; SubExprs[BEGINEND] = BeginEndStmt; SubExprs[COND] = Cond; diff --git a/clang/lib/AST/StmtPrinter.cpp b/clang/lib/AST/StmtPrinter.cpp index bf155f5680b..52aa59e252b 100644 --- a/clang/lib/AST/StmtPrinter.cpp +++ b/clang/lib/AST/StmtPrinter.cpp @@ -2163,6 +2163,31 @@ void StmtPrinter::VisitCXXFoldExpr(CXXFoldExpr *E) { OS << ")"; } +// C++ Coroutines TS + +void StmtPrinter::VisitCoroutineBodyStmt(CoroutineBodyStmt *S) { + Visit(S->getBody()); +} + +void StmtPrinter::VisitCoreturnStmt(CoreturnStmt *S) { + OS << "co_return"; + if (S->getOperand()) { + OS << " "; + Visit(S->getOperand()); + } + OS << ";"; +} + +void StmtPrinter::VisitCoawaitExpr(CoawaitExpr *S) { + OS << "co_await "; + PrintExpr(S->getOperand()); +} + +void StmtPrinter::VisitCoyieldExpr(CoyieldExpr *S) { + OS << "co_yield "; + PrintExpr(S->getOperand()); +} + // Obj-C void StmtPrinter::VisitObjCStringLiteral(ObjCStringLiteral *Node) { diff --git a/clang/lib/AST/StmtProfile.cpp b/clang/lib/AST/StmtProfile.cpp index 93b80e5d99c..28507c1e536 100644 --- a/clang/lib/AST/StmtProfile.cpp +++ b/clang/lib/AST/StmtProfile.cpp @@ -1362,6 +1362,22 @@ void StmtProfiler::VisitCXXFoldExpr(const CXXFoldExpr *S) { ID.AddInteger(S->getOperator()); } +void StmtProfiler::VisitCoroutineBodyStmt(const CoroutineBodyStmt *S) { + VisitStmt(S); +} + +void StmtProfiler::VisitCoreturnStmt(const CoreturnStmt *S) { + VisitStmt(S); +} + +void StmtProfiler::VisitCoawaitExpr(const CoawaitExpr *S) { + VisitExpr(S); +} + +void StmtProfiler::VisitCoyieldExpr(const CoyieldExpr *S) { + VisitExpr(S); +} + void StmtProfiler::VisitOpaqueValueExpr(const OpaqueValueExpr *E) { VisitExpr(E); } diff --git a/clang/lib/Analysis/ThreadSafetyCommon.cpp b/clang/lib/Analysis/ThreadSafetyCommon.cpp index 0b564398db1..ffe95ea22a4 100644 --- a/clang/lib/Analysis/ThreadSafetyCommon.cpp +++ b/clang/lib/Analysis/ThreadSafetyCommon.cpp @@ -445,6 +445,7 @@ til::SExpr *SExprBuilder::translateUnaryOperator(const UnaryOperator *UO, case UO_Real: case UO_Imag: case UO_Extension: + case UO_Coawait: return new (Arena) til::Undefined(UO); } return new (Arena) til::Undefined(UO); diff --git a/clang/lib/CodeGen/CGStmt.cpp b/clang/lib/CodeGen/CGStmt.cpp index f915518c26a..b1cb395b8e0 100644 --- a/clang/lib/CodeGen/CGStmt.cpp +++ b/clang/lib/CodeGen/CGStmt.cpp @@ -141,6 +141,10 @@ void CodeGenFunction::EmitStmt(const Stmt *S) { case Stmt::SwitchStmtClass: EmitSwitchStmt(cast<SwitchStmt>(*S)); break; case Stmt::GCCAsmStmtClass: // Intentional fall-through. case Stmt::MSAsmStmtClass: EmitAsmStmt(cast<AsmStmt>(*S)); break; + case Stmt::CoroutineBodyStmtClass: + case Stmt::CoreturnStmtClass: + CGM.ErrorUnsupported(S, "coroutine"); + break; case Stmt::CapturedStmtClass: { const CapturedStmt *CS = cast<CapturedStmt>(S); EmitCapturedStmt(*CS, CS->getCapturedRegionKind()); diff --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp index f3316461ac0..490bd5ada62 100644 --- a/clang/lib/Parse/ParseExpr.cpp +++ b/clang/lib/Parse/ParseExpr.cpp @@ -1048,7 +1048,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, SourceLocation CoawaitLoc = ConsumeToken(); Res = ParseCastExpression(false); if (!Res.isInvalid()) - Res = Actions.ActOnCoawaitExpr(CoawaitLoc, Res.get()); + Res = Actions.ActOnCoawaitExpr(getCurScope(), CoawaitLoc, Res.get()); return Res; } diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp index bd9b9f97313..d5f188104ed 100644 --- a/clang/lib/Parse/ParseExprCXX.cpp +++ b/clang/lib/Parse/ParseExprCXX.cpp @@ -1568,7 +1568,7 @@ ExprResult Parser::ParseCoyieldExpression() { SourceLocation Loc = ConsumeToken(); ExprResult Expr = ParseAssignmentExpression(); if (!Expr.isInvalid()) - Expr = Actions.ActOnCoyieldExpr(Loc, Expr.get()); + Expr = Actions.ActOnCoyieldExpr(getCurScope(), Loc, Expr.get()); return Expr; } diff --git a/clang/lib/Parse/ParseStmt.cpp b/clang/lib/Parse/ParseStmt.cpp index af7008f8e78..35cb0fef781 100644 --- a/clang/lib/Parse/ParseStmt.cpp +++ b/clang/lib/Parse/ParseStmt.cpp @@ -1691,13 +1691,10 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc) { StmtResult ForEachStmt; if (ForRange) { - ForRangeStmt = Actions.ActOnCXXForRangeStmt(ForLoc, CoawaitLoc, - FirstPart.get(), - ForRangeInit.ColonLoc, - ForRangeInit.RangeExpr.get(), - T.getCloseLocation(), - Sema::BFRK_Build); - + ForRangeStmt = Actions.ActOnCXXForRangeStmt( + getCurScope(), ForLoc, CoawaitLoc, FirstPart.get(), + ForRangeInit.ColonLoc, ForRangeInit.RangeExpr.get(), + T.getCloseLocation(), Sema::BFRK_Build); // Similarly, we need to do the semantic analysis for a for-range // statement immediately in order to close over temporaries correctly. diff --git a/clang/lib/Sema/ScopeInfo.cpp b/clang/lib/Sema/ScopeInfo.cpp index ba8c3642bc8..6a400a2efe5 100644 --- a/clang/lib/Sema/ScopeInfo.cpp +++ b/clang/lib/Sema/ScopeInfo.cpp @@ -33,11 +33,13 @@ void FunctionScopeInfo::Clear() { ObjCWarnForNoDesignatedInitChain = false; ObjCIsSecondaryInit = false; ObjCWarnForNoInitDelegation = false; + FirstReturnLoc = SourceLocation(); FirstCXXTryLoc = SourceLocation(); FirstSEHTryLoc = SourceLocation(); SwitchStack.clear(); Returns.clear(); + CoroutineStmts.clear(); ErrorTrap.reset(); PossiblyUnreachableDiags.clear(); WeakObjectUses.clear(); diff --git a/clang/lib/Sema/SemaCoroutine.cpp b/clang/lib/Sema/SemaCoroutine.cpp index 6545b6709a2..a2a79001f0d 100644 --- a/clang/lib/Sema/SemaCoroutine.cpp +++ b/clang/lib/Sema/SemaCoroutine.cpp @@ -12,12 +12,89 @@ //===----------------------------------------------------------------------===// #include "clang/Sema/SemaInternal.h" +#include "clang/AST/Decl.h" +#include "clang/AST/ExprCXX.h" +#include "clang/AST/StmtCXX.h" +#include "clang/Lex/Preprocessor.h" +#include "clang/Sema/Overload.h" using namespace clang; using namespace sema; +/// Look up the std::coroutine_traits<...>::promise_type for the given +/// function type. +static QualType lookupPromiseType(Sema &S, const FunctionProtoType *FnType, + SourceLocation Loc) { + // FIXME: Cache std::coroutine_traits once we've found it. + NamespaceDecl *Std = S.getStdNamespace(); + if (!Std) { + S.Diag(Loc, diag::err_implied_std_coroutine_traits_not_found); + return QualType(); + } + + LookupResult Result(S, &S.PP.getIdentifierTable().get("coroutine_traits"), + Loc, Sema::LookupOrdinaryName); + if (!S.LookupQualifiedName(Result, Std)) { + S.Diag(Loc, diag::err_implied_std_coroutine_traits_not_found); + return QualType(); + } + + ClassTemplateDecl *CoroTraits = Result.getAsSingle<ClassTemplateDecl>(); + if (!CoroTraits) { + Result.suppressDiagnostics(); + // We found something weird. Complain about the first thing we found. + NamedDecl *Found = *Result.begin(); + S.Diag(Found->getLocation(), diag::err_malformed_std_coroutine_traits); + return QualType(); + } + + // Form template argument list for coroutine_traits<R, P1, P2, ...>. + TemplateArgumentListInfo Args(Loc, Loc); + Args.addArgument(TemplateArgumentLoc( + TemplateArgument(FnType->getReturnType()), + S.Context.getTrivialTypeSourceInfo(FnType->getReturnType(), Loc))); + for (QualType T : FnType->getParamTypes()) + Args.addArgument(TemplateArgumentLoc( + TemplateArgument(T), S.Context.getTrivialTypeSourceInfo(T, Loc))); + + // Build the template-id. + QualType CoroTrait = + S.CheckTemplateIdType(TemplateName(CoroTraits), Loc, Args); + if (CoroTrait.isNull()) + return QualType(); + if (S.RequireCompleteType(Loc, CoroTrait, + diag::err_coroutine_traits_missing_specialization)) + return QualType(); + + CXXRecordDecl *RD = CoroTrait->getAsCXXRecordDecl(); + assert(RD && "specialization of class template is not a class?"); + + // Look up the ::promise_type member. + LookupResult R(S, &S.PP.getIdentifierTable().get("promise_type"), Loc, + Sema::LookupOrdinaryName); + S.LookupQualifiedName(R, RD); + auto *Promise = R.getAsSingle<TypeDecl>(); + if (!Promise) { + S.Diag(Loc, diag::err_implied_std_coroutine_traits_promise_type_not_found) + << RD; + return QualType(); + } + + // The promise type is required to be a class type. + QualType PromiseType = S.Context.getTypeDeclType(Promise); + if (!PromiseType->getAsCXXRecordDecl()) { + S.Diag(Loc, diag::err_implied_std_coroutine_traits_promise_type_not_class) + << PromiseType; + return QualType(); + } + + return PromiseType; +} + +/// Check that this is a context in which a coroutine suspension can appear. static FunctionScopeInfo * checkCoroutineContext(Sema &S, SourceLocation Loc, StringRef Keyword) { // 'co_await' and 'co_yield' are permitted in unevaluated operands. + // FIXME: Not in 'noexcept'. if (S.isUnevaluatedContext()) return nullptr; @@ -42,36 +119,143 @@ checkCoroutineContext(Sema &S, SourceLocation Loc, StringRef Keyword) { } else { auto *ScopeInfo = S.getCurFunction(); assert(ScopeInfo && "missing function scope for function"); + + // If we don't have a promise variable, build one now. + if (!ScopeInfo->CoroutinePromise && !FD->getType()->isDependentType()) { + QualType T = + lookupPromiseType(S, FD->getType()->castAs<FunctionProtoType>(), Loc); + if (T.isNull()) + return nullptr; + + // Create and default-initialize the promise. + ScopeInfo->CoroutinePromise = + VarDecl::Create(S.Context, FD, FD->getLocation(), FD->getLocation(), + &S.PP.getIdentifierTable().get("__promise"), T, + S.Context.getTrivialTypeSourceInfo(T, Loc), SC_None); + S.CheckVariableDeclarationType(ScopeInfo->CoroutinePromise); + if (!ScopeInfo->CoroutinePromise->isInvalidDecl()) + S.ActOnUninitializedDecl(ScopeInfo->CoroutinePromise, false); + } + return ScopeInfo; } return nullptr; } -ExprResult Sema::ActOnCoawaitExpr(SourceLocation Loc, Expr *E) { - auto *Context = checkCoroutineContext(*this, Loc, "co_await"); - ExprResult Res = ExprError(); +/// Build a call to 'operator co_await' if there is a suitable operator for +/// the given expression. +static ExprResult buildOperatorCoawaitCall(Sema &SemaRef, Scope *S, + SourceLocation Loc, Expr *E) { + UnresolvedSet<16> Functions; + SemaRef.LookupOverloadedOperatorName(OO_Coawait, S, E->getType(), QualType(), + Functions); + return SemaRef.CreateOverloadedUnaryOp(Loc, UO_Coawait, Functions, E); +} + +struct ReadySuspendResumeResult { + bool IsInvalid; + Expr *Results[3]; +}; + +/// Build calls to await_ready, await_suspend, and await_resume for a co_await +/// expression. +static ReadySuspendResumeResult buildCoawaitCalls(Sema &S, SourceLocation Loc, + Expr *E) { + // Assume invalid until we see otherwise. + ReadySuspendResumeResult Calls = {true, {}}; + + const StringRef Funcs[] = {"await_ready", "await_suspend", "await_resume"}; + for (size_t I = 0, N = llvm::array_lengthof(Funcs); I != N; ++I) { + DeclarationNameInfo NameInfo(&S.PP.getIdentifierTable().get(Funcs[I]), Loc); + + Expr *Operand = new (S.Context) OpaqueValueExpr( + Loc, E->getType(), E->getValueKind(), E->getObjectKind(), E); + + // FIXME: Fix BuildMemberReferenceExpr to take a const CXXScopeSpec&. + CXXScopeSpec SS; + ExprResult Result = S.BuildMemberReferenceExpr( + Operand, Operand->getType(), Loc, /*IsPtr=*/false, SS, + SourceLocation(), nullptr, NameInfo, /*TemplateArgs=*/nullptr, + /*Scope=*/nullptr); + if (Result.isInvalid()) + return Calls; - if (Context && !Res.isInvalid()) - Context->CoroutineStmts.push_back(Res.get()); + // FIXME: Pass coroutine handle to await_suspend. + Result = S.ActOnCallExpr(nullptr, Result.get(), Loc, None, Loc, nullptr); + if (Result.isInvalid()) + return Calls; + Calls.Results[I] = Result.get(); + } + + Calls.IsInvalid = false; + return Calls; +} + +ExprResult Sema::ActOnCoawaitExpr(Scope *S, SourceLocation Loc, Expr *E) { + ExprResult Awaitable = buildOperatorCoawaitCall(*this, S, Loc, E); + if (Awaitable.isInvalid()) + return ExprError(); + return BuildCoawaitExpr(Loc, Awaitable.get()); +} +ExprResult Sema::BuildCoawaitExpr(SourceLocation Loc, Expr *E) { + auto *Coroutine = checkCoroutineContext(*this, Loc, "co_await"); + + if (E->getType()->isDependentType()) { + Expr *Res = new (Context) CoawaitExpr(Loc, Context.DependentTy, E); + if (Coroutine) + Coroutine->CoroutineStmts.push_back(Res); + return Res; + } + + if (E->getType()->isPlaceholderType()) { + ExprResult R = CheckPlaceholderExpr(E); + if (R.isInvalid()) return ExprError(); + E = R.get(); + } + + // FIXME: If E is a prvalue, create a temporary. + // FIXME: If E is an xvalue, convert to lvalue. + + // Build the await_ready, await_suspend, await_resume calls. + ReadySuspendResumeResult RSS = buildCoawaitCalls(*this, Loc, E); + if (RSS.IsInvalid) + return ExprError(); + + Expr *Res = new (Context) CoawaitExpr(Loc, E, RSS.Results[0], RSS.Results[1], + RSS.Results[2]); + if (Coroutine) + Coroutine->CoroutineStmts.push_back(Res); return Res; } -ExprResult Sema::ActOnCoyieldExpr(SourceLocation Loc, Expr *E) { - auto *Context = checkCoroutineContext(*this, Loc, "co_yield"); - ExprResult Res = ExprError(); +ExprResult Sema::ActOnCoyieldExpr(Scope *S, SourceLocation Loc, Expr *E) { + // FIXME: Build yield_value call. + ExprResult Awaitable = buildOperatorCoawaitCall(*this, S, Loc, E); + if (Awaitable.isInvalid()) + return ExprError(); + return BuildCoyieldExpr(Loc, Awaitable.get()); +} +ExprResult Sema::BuildCoyieldExpr(SourceLocation Loc, Expr *E) { + auto *Coroutine = checkCoroutineContext(*this, Loc, "co_yield"); - if (Context && !Res.isInvalid()) - Context->CoroutineStmts.push_back(Res.get()); + // FIXME: Build await_* calls. + Expr *Res = new (Context) CoyieldExpr(Loc, Context.VoidTy, E); + if (Coroutine) + Coroutine->CoroutineStmts.push_back(Res); return Res; } StmtResult Sema::ActOnCoreturnStmt(SourceLocation Loc, Expr *E) { - auto *Context = checkCoroutineContext(*this, Loc, "co_return"); - StmtResult Res = StmtError(); + return BuildCoreturnStmt(Loc, E); +} +StmtResult Sema::BuildCoreturnStmt(SourceLocation Loc, Expr *E) { + auto *Coroutine = checkCoroutineContext(*this, Loc, "co_return"); - if (Context && !Res.isInvalid()) - Context->CoroutineStmts.push_back(Res.get()); + // FIXME: Build return_* calls. + Stmt *Res = new (Context) CoreturnStmt(Loc, E); + if (Coroutine) + Coroutine->CoroutineStmts.push_back(Res); return Res; } @@ -81,26 +265,25 @@ void Sema::CheckCompletedCoroutineBody(FunctionDecl *FD, Stmt *Body) { // Coroutines [stmt.return]p1: // A return statement shall not appear in a coroutine. - if (!Fn->Returns.empty()) { - Diag(Fn->Returns.front()->getLocStart(), diag::err_return_in_coroutine); + if (Fn->FirstReturnLoc.isValid()) { + Diag(Fn->FirstReturnLoc, diag::err_return_in_coroutine); auto *First = Fn->CoroutineStmts[0]; Diag(First->getLocStart(), diag::note_declared_coroutine_here) - << 0; // FIXME: Indicate the kind here + << (isa<CoawaitExpr>(First) ? 0 : + isa<CoyieldExpr>(First) ? 1 : 2); } bool AnyCoawaits = false; bool AnyCoyields = false; for (auto *CoroutineStmt : Fn->CoroutineStmts) { - (void)CoroutineStmt; - AnyCoawaits = AnyCoyields = true; // FIXME + AnyCoawaits |= isa<CoawaitExpr>(CoroutineStmt); + AnyCoyields |= isa<CoyieldExpr>(CoroutineStmt); } if (!AnyCoawaits && !AnyCoyields) Diag(Fn->CoroutineStmts.front()->getLocStart(), - diag::ext_coroutine_without_coawait_coyield); + diag::ext_coroutine_without_co_await_co_yield); - // FIXME: If we have a deduced return type, resolve it now. - // FIXME: Compute the promise type. - // FIXME: Perform analysis of initial and final suspend, and set_exception call. - // FIXME: Complete the semantic analysis of the CoroutineStmts. + // FIXME: Perform analysis of initial and final suspend, + // and set_exception call. } diff --git a/clang/lib/Sema/SemaExceptionSpec.cpp b/clang/lib/Sema/SemaExceptionSpec.cpp index a18824f1552..f993a28a13e 100644 --- a/clang/lib/Sema/SemaExceptionSpec.cpp +++ b/clang/lib/Sema/SemaExceptionSpec.cpp @@ -1063,8 +1063,10 @@ CanThrowResult Sema::canThrow(const Expr *E) { // Many other things have subexpressions, so we have to test those. // Some are simple: + case Expr::CoawaitExprClass: case Expr::ConditionalOperatorClass: case Expr::CompoundLiteralExprClass: + case Expr::CoyieldExprClass: case Expr::CXXConstCastExprClass: case Expr::CXXReinterpretCastExprClass: case Expr::CXXStdInitializerListExprClass: diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index badb2ef118f..857925da99c 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -10901,6 +10901,7 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc, } break; case UO_Extension: + case UO_Coawait: resultType = Input.get()->getType(); VK = Input.get()->getValueKind(); OK = Input.get()->getObjectKind(); diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index d4a220037ec..084e25a1cbb 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -8228,15 +8228,16 @@ void Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op, case OO_Array_New: case OO_Array_Delete: case OO_Call: - case OO_Coawait: llvm_unreachable( "Special operators don't use AddBuiltinOperatorCandidates"); case OO_Comma: case OO_Arrow: + case OO_Coawait: // C++ [over.match.oper]p3: - // -- For the operator ',', the unary operator '&', or the - // operator '->', the built-in candidates set is empty. + // -- For the operator ',', the unary operator '&', the + // operator '->', or the operator 'co_await', the + // built-in candidates set is empty. break; case OO_Plus: // '+' is either unary or binary @@ -12481,13 +12482,14 @@ ExprResult Sema::BuildLiteralOperatorCall(LookupResult &R, /// otherwise CallExpr is set to ExprError() and some non-success value /// is returned. Sema::ForRangeStatus -Sema::BuildForRangeBeginEndCall(Scope *S, SourceLocation Loc, - SourceLocation RangeLoc, VarDecl *Decl, - BeginEndFunction BEF, +Sema::BuildForRangeBeginEndCall(SourceLocation Loc, + SourceLocation RangeLoc, const DeclarationNameInfo &NameInfo, LookupResult &MemberLookup, OverloadCandidateSet *CandidateSet, Expr *Range, ExprResult *CallExpr) { + Scope *S = nullptr; + CandidateSet->clear(); if (!MemberLookup.empty()) { ExprResult MemberRef = @@ -12499,15 +12501,11 @@ Sema::BuildForRangeBeginEndCall(Scope *S, SourceLocation Loc, /*TemplateArgs=*/nullptr, S); if (MemberRef.isInvalid()) { *CallExpr = ExprError(); - Diag(Range->getLocStart(), diag::note_in_for_range) - << RangeLoc << BEF << Range->getType(); return FRS_DiagnosticIssued; } *CallExpr = ActOnCallExpr(S, MemberRef.get(), Loc, None, Loc, nullptr); if (CallExpr->isInvalid()) { *CallExpr = ExprError(); - Diag(Range->getLocStart(), diag::note_in_for_range) - << RangeLoc << BEF << Range->getType(); return FRS_DiagnosticIssued; } } else { @@ -12538,8 +12536,6 @@ Sema::BuildForRangeBeginEndCall(Scope *S, SourceLocation Loc, /*AllowTypoCorrection=*/false); if (CallExpr->isInvalid() || OverloadResult != OR_Success) { *CallExpr = ExprError(); - Diag(Range->getLocStart(), diag::note_in_for_range) - << RangeLoc << BEF << Range->getType(); return FRS_DiagnosticIssued; } } diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp index fec12000950..f8668c38932 100644 --- a/clang/lib/Sema/SemaStmt.cpp +++ b/clang/lib/Sema/SemaStmt.cpp @@ -1859,13 +1859,19 @@ static bool FinishForRangeVarDecl(Sema &SemaRef, VarDecl *Decl, Expr *Init, } namespace { +// An enum to represent whether something is dealing with a call to begin() +// or a call to end() in a range-based for loop. +enum BeginEndFunction { + BEF_begin, + BEF_end +}; /// Produce a note indicating which begin/end function was implicitly called /// by a C++11 for-range statement. This is often not obvious from the code, /// nor from the diagnostics produced when analysing the implicit expressions /// required in a for-range statement. void NoteForRangeBeginEndFunction(Sema &SemaRef, Expr *E, - Sema::BeginEndFunction BEF) { + BeginEndFunction BEF) { CallExpr *CE = dyn_cast<CallExpr>(E); if (!CE) return; @@ -1923,10 +1929,11 @@ static bool ObjCEnumerationCollection(Expr *Collection) { /// /// The body of the loop is not available yet, since it cannot be analysed until /// we have determined the type of the for-range-declaration. -StmtResult -Sema::ActOnCXXForRangeStmt(SourceLocation ForLoc, SourceLocation CoawaitLoc, - Stmt *First, SourceLocation ColonLoc, Expr *Range, - SourceLocation RParenLoc, BuildForRangeKind Kind) { +StmtResult Sema::ActOnCXXForRangeStmt(Scope *S, SourceLocation ForLoc, + SourceLocation CoawaitLoc, Stmt *First, + SourceLocation ColonLoc, Expr *Range, + SourceLocation RParenLoc, + BuildForRangeKind Kind) { if (!First) return StmtError(); @@ -1950,7 +1957,7 @@ Sema::ActOnCXXForRangeStmt(SourceLocation ForLoc, SourceLocation CoawaitLoc, // Coroutines: 'for co_await' implicitly co_awaits its range. if (CoawaitLoc.isValid()) { - ExprResult Coawait = ActOnCoawaitExpr(CoawaitLoc, Range); + ExprResult Coawait = ActOnCoawaitExpr(S, CoawaitLoc, Range); if (Coawait.isInvalid()) return StmtError(); Range = Coawait.get(); } @@ -1990,7 +1997,7 @@ Sema::ActOnCXXForRangeStmt(SourceLocation ForLoc, SourceLocation CoawaitLoc, /// BeginExpr and EndExpr are set and FRS_Success is returned on success; /// CandidateSet and BEF are set and some non-success value is returned on /// failure. -static Sema::ForRangeStatus BuildNonArrayForRange(Sema &SemaRef, Scope *S, +static Sema::ForRangeStatus BuildNonArrayForRange(Sema &SemaRef, Expr *BeginRange, Expr *EndRange, QualType RangeType, VarDecl *BeginVar, @@ -1999,7 +2006,7 @@ static Sema::ForRangeStatus BuildNonArrayForRange(Sema &SemaRef, Scope *S, OverloadCandidateSet *CandidateSet, ExprResult *BeginExpr, ExprResult *EndExpr, - Sema::BeginEndFunction *BEF) { + BeginEndFunction *BEF) { DeclarationNameInfo BeginNameInfo( &SemaRef.PP.getIdentifierTable().get("begin"), ColonLoc); DeclarationNameInfo EndNameInfo(&SemaRef.PP.getIdentifierTable().get("end"), @@ -2020,7 +2027,7 @@ static Sema::ForRangeStatus BuildNonArrayForRange(Sema &SemaRef, Scope *S, if (BeginMemberLookup.empty() != EndMemberLookup.empty()) { SourceLocation RangeLoc = BeginVar->getLocation(); - *BEF = BeginMemberLookup.empty() ? Sema::BEF_end : Sema::BEF_begin; + *BEF = BeginMemberLookup.empty() ? BEF_end : BEF_begin; SemaRef.Diag(RangeLoc, diag::err_for_range_member_begin_end_mismatch) << RangeLoc << BeginRange->getType() << *BEF; @@ -2034,29 +2041,35 @@ static Sema::ForRangeStatus BuildNonArrayForRange(Sema &SemaRef, Scope *S, } - *BEF = Sema::BEF_begin; + *BEF = BEF_begin; Sema::ForRangeStatus RangeStatus = - SemaRef.BuildForRangeBeginEndCall(S, ColonLoc, ColonLoc, BeginVar, - Sema::BEF_begin, BeginNameInfo, + SemaRef.BuildForRangeBeginEndCall(ColonLoc, ColonLoc, BeginNameInfo, BeginMemberLookup, CandidateSet, BeginRange, BeginExpr); - if (RangeStatus != Sema::FRS_Success) + if (RangeStatus != Sema::FRS_Success) { + if (RangeStatus == Sema::FRS_DiagnosticIssued) + SemaRef.Diag(BeginRange->getLocStart(), diag::note_in_for_range) + << ColonLoc << BEF_begin << BeginRange->getType(); return RangeStatus; + } if (FinishForRangeVarDecl(SemaRef, BeginVar, BeginExpr->get(), ColonLoc, diag::err_for_range_iter_deduction_failure)) { NoteForRangeBeginEndFunction(SemaRef, BeginExpr->get(), *BEF); return Sema::FRS_DiagnosticIssued; } - *BEF = Sema::BEF_end; + *BEF = BEF_end; RangeStatus = - SemaRef.BuildForRangeBeginEndCall(S, ColonLoc, ColonLoc, EndVar, - Sema::BEF_end, EndNameInfo, + SemaRef.BuildForRangeBeginEndCall(ColonLoc, ColonLoc, EndNameInfo, EndMemberLookup, CandidateSet, EndRange, EndExpr); - if (RangeStatus != Sema::FRS_Success) + if (RangeStatus != Sema::FRS_Success) { + if (RangeStatus == Sema::FRS_DiagnosticIssued) + SemaRef.Diag(EndRange->getLocStart(), diag::note_in_for_range) + << ColonLoc << BEF_end << EndRange->getType(); return RangeStatus; + } if (FinishForRangeVarDecl(SemaRef, EndVar, EndExpr->get(), ColonLoc, diag::err_for_range_iter_deduction_failure)) { NoteForRangeBeginEndFunction(SemaRef, EndExpr->get(), *BEF); @@ -2086,10 +2099,9 @@ static StmtResult RebuildForRangeWithDereference(Sema &SemaRef, Scope *S, if (AdjustedRange.isInvalid()) return StmtResult(); - StmtResult SR = - SemaRef.ActOnCXXForRangeStmt(ForLoc, CoawaitLoc, LoopVarDecl, ColonLoc, - AdjustedRange.get(), RParenLoc, - Sema::BFRK_Check); + StmtResult SR = SemaRef.ActOnCXXForRangeStmt( + S, ForLoc, CoawaitLoc, LoopVarDecl, ColonLoc, AdjustedRange.get(), + RParenLoc, Sema::BFRK_Check); if (SR.isInvalid()) return StmtResult(); } @@ -2099,8 +2111,8 @@ static StmtResult RebuildForRangeWithDereference(Sema &SemaRef, Scope *S, // case there are any other (non-fatal) problems with it. SemaRef.Diag(RangeLoc, diag::err_for_range_dereference) << Range->getType() << FixItHint::CreateInsertion(RangeLoc, "*"); - return SemaRef.ActOnCXXForRangeStmt(ForLoc, CoawaitLoc, LoopVarDecl, ColonLoc, - AdjustedRange.get(), RParenLoc, + return SemaRef.ActOnCXXForRangeStmt(S, ForLoc, CoawaitLoc, LoopVarDecl, + ColonLoc, AdjustedRange.get(), RParenLoc, Sema::BFRK_Rebuild); } @@ -2127,6 +2139,15 @@ Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation CoawaitLoc, Stmt *RangeDecl, Stmt *BeginEnd, Expr *Cond, Expr *Inc, Stmt *LoopVarDecl, SourceLocation RParenLoc, BuildForRangeKind Kind) { + // FIXME: This should not be used during template instantiation. We should + // pick up the set of unqualified lookup results for the != and + operators + // in the initial parse. + // + // Testcase (accepts-invalid): + // template<typename T> void f() { for (auto x : T()) {} } + // namespace N { struct X { X begin(); X end(); int operator*(); }; } + // bool operator!=(N::X, N::X); void operator++(N::X); + // void g() { f<N::X>(); } Scope *S = getCurScope(); DeclStmt *RangeDS = cast<DeclStmt>(RangeDecl); @@ -2226,9 +2247,9 @@ Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation CoawaitLoc, } else { OverloadCandidateSet CandidateSet(RangeLoc, OverloadCandidateSet::CSK_Normal); - Sema::BeginEndFunction BEFFailure; + BeginEndFunction BEFFailure; ForRangeStatus RangeStatus = - BuildNonArrayForRange(*this, S, BeginRangeRef.get(), + BuildNonArrayForRange(*this, BeginRangeRef.get(), EndRangeRef.get(), RangeType, BeginVar, EndVar, ColonLoc, &CandidateSet, &BeginExpr, &EndExpr, &BEFFailure); @@ -2325,7 +2346,7 @@ Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation CoawaitLoc, IncrExpr = ActOnUnaryOp(S, ColonLoc, tok::plusplus, BeginRef.get()); if (!IncrExpr.isInvalid() && CoawaitLoc.isValid()) - IncrExpr = ActOnCoawaitExpr(CoawaitLoc, IncrExpr.get()); + IncrExpr = ActOnCoawaitExpr(S, CoawaitLoc, IncrExpr.get()); if (!IncrExpr.isInvalid()) IncrExpr = ActOnFinishFullExpr(IncrExpr.get()); if (IncrExpr.isInvalid()) { @@ -2364,10 +2385,10 @@ Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation CoawaitLoc, if (Kind == BFRK_Check) return StmtResult(); - // FIXME: Pass in CoawaitLoc in the dependent case. return new (Context) CXXForRangeStmt( RangeDS, cast_or_null<DeclStmt>(BeginEndDecl.get()), NotEqExpr.get(), - IncrExpr.get(), LoopVarDS, /*Body=*/nullptr, ForLoc, ColonLoc, RParenLoc); + IncrExpr.get(), LoopVarDS, /*Body=*/nullptr, ForLoc, CoawaitLoc, + ColonLoc, RParenLoc); } /// FinishObjCForCollectionStmt - Attach the body to a objective-C foreach @@ -2925,6 +2946,9 @@ Sema::ActOnCapScopeReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) { if (CurCap->HasImplicitReturnType || NRVOCandidate) FunctionScopes.back()->Returns.push_back(Result); + if (FunctionScopes.back()->FirstReturnLoc.isInvalid()) + FunctionScopes.back()->FirstReturnLoc = ReturnLoc; + return Result; } @@ -3291,6 +3315,9 @@ StmtResult Sema::BuildReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) { if (Result->getNRVOCandidate()) FunctionScopes.back()->Returns.push_back(Result); + if (FunctionScopes.back()->FirstReturnLoc.isInvalid()) + FunctionScopes.back()->FirstReturnLoc = ReturnLoc; + return Result; } diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index 117ae56969d..176e57165ff 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -1287,6 +1287,30 @@ public: Constraints, Clobbers, Exprs, EndLoc); } + /// \brief Build a new co_return statement. + /// + /// By default, performs semantic analysis to build the new statement. + /// Subclasses may override this routine to provide different behavior. + StmtResult RebuildCoreturnStmt(SourceLocation CoreturnLoc, Expr *Result) { + return getSema().BuildCoreturnStmt(CoreturnLoc, Result); + } + + /// \brief Build a new co_await expression. + /// + /// By default, performs semantic analysis to build the new expression. + /// Subclasses may override this routine to provide different behavior. + ExprResult RebuildCoawaitExpr(SourceLocation CoawaitLoc, Expr *Result) { + return getSema().BuildCoawaitExpr(CoawaitLoc, Result); + } + + /// \brief Build a new co_yield expression. + /// + /// By default, performs semantic analysis to build the new expression. + /// Subclasses may override this routine to provide different behavior. + ExprResult RebuildCoyieldExpr(SourceLocation CoyieldLoc, Expr *Result) { + return getSema().BuildCoyieldExpr(CoyieldLoc, Result); + } + /// \brief Build a new Objective-C \@try statement. /// /// By default, performs semantic analysis to build the new statement. @@ -1715,6 +1739,7 @@ public: /// By default, performs semantic analysis to build the new statement. /// Subclasses may override this routine to provide different behavior. StmtResult RebuildCXXForRangeStmt(SourceLocation ForLoc, + SourceLocation CoawaitLoc, SourceLocation ColonLoc, Stmt *Range, Stmt *BeginEnd, Expr *Cond, Expr *Inc, @@ -1737,7 +1762,6 @@ public: } } - SourceLocation CoawaitLoc; // FIXME return getSema().BuildCXXForRangeStmt(ForLoc, CoawaitLoc, ColonLoc, Range, BeginEnd, Cond, Inc, LoopVar, RParenLoc, @@ -6403,6 +6427,56 @@ TreeTransform<Derived>::TransformMSAsmStmt(MSAsmStmt *S) { TransformedExprs, S->getEndLoc()); } +// C++ Coroutines TS + +template<typename Derived> +StmtResult +TreeTransform<Derived>::TransformCoroutineBodyStmt(CoroutineBodyStmt *S) { + // The coroutine body should be re-formed by the caller if necessary. + return getDerived().TransformStmt(S->getBody()); +} + +template<typename Derived> +StmtResult +TreeTransform<Derived>::TransformCoreturnStmt(CoreturnStmt *S) { + ExprResult Result = getDerived().TransformInitializer(S->getOperand(), + /*NotCopyInit*/false); + if (Result.isInvalid()) + return StmtError(); + + // Always rebuild; we don't know if this needs to be injected into a new + // context or if the promise type has changed. + return getDerived().RebuildCoreturnStmt(S->getKeywordLoc(), Result.get()); +} + +template<typename Derived> +ExprResult +TreeTransform<Derived>::TransformCoawaitExpr(CoawaitExpr *E) { + ExprResult Result = getDerived().TransformInitializer(E->getOperand(), + /*NotCopyInit*/false); + if (Result.isInvalid()) + return ExprError(); + + // Always rebuild; we don't know if this needs to be injected into a new + // context or if the promise type has changed. + return getDerived().RebuildCoawaitExpr(E->getKeywordLoc(), Result.get()); +} + +template<typename Derived> +ExprResult +TreeTransform<Derived>::TransformCoyieldExpr(CoyieldExpr *E) { + ExprResult Result = getDerived().TransformInitializer(E->getOperand(), + /*NotCopyInit*/false); + if (Result.isInvalid()) + return ExprError(); + + // Always rebuild; we don't know if this needs to be injected into a new + // context or if the promise type has changed. + return getDerived().RebuildCoyieldExpr(E->getKeywordLoc(), Result.get()); +} + +// Objective-C Statements. + template<typename Derived> StmtResult TreeTransform<Derived>::TransformObjCAtTryStmt(ObjCAtTryStmt *S) { @@ -6692,6 +6766,7 @@ TreeTransform<Derived>::TransformCXXForRangeStmt(CXXForRangeStmt *S) { Inc.get() != S->getInc() || LoopVar.get() != S->getLoopVarStmt()) { NewStmt = getDerived().RebuildCXXForRangeStmt(S->getForLoc(), + S->getCoawaitLoc(), S->getColonLoc(), Range.get(), BeginEnd.get(), Cond.get(), Inc.get(), LoopVar.get(), @@ -6708,6 +6783,7 @@ TreeTransform<Derived>::TransformCXXForRangeStmt(CXXForRangeStmt *S) { // it now so we have a new statement to attach the body to. if (Body.get() != S->getBody() && NewStmt.get() == S) { NewStmt = getDerived().RebuildCXXForRangeStmt(S->getForLoc(), + S->getCoawaitLoc(), S->getColonLoc(), Range.get(), BeginEnd.get(), Cond.get(), Inc.get(), LoopVar.get(), diff --git a/clang/lib/Serialization/ASTReaderStmt.cpp b/clang/lib/Serialization/ASTReaderStmt.cpp index 5f9f0522923..ab82eee10e2 100644 --- a/clang/lib/Serialization/ASTReaderStmt.cpp +++ b/clang/lib/Serialization/ASTReaderStmt.cpp @@ -381,6 +381,26 @@ void ASTStmtReader::VisitMSAsmStmt(MSAsmStmt *S) { Constraints, Exprs, Clobbers); } +void ASTStmtReader::VisitCoroutineBodyStmt(CoroutineBodyStmt *S) { + // FIXME: Implement coroutine serialization. + llvm_unreachable("unimplemented"); +} + +void ASTStmtReader::VisitCoreturnStmt(CoreturnStmt *S) { + // FIXME: Implement coroutine serialization. + llvm_unreachable("unimplemented"); +} + +void ASTStmtReader::VisitCoawaitExpr(CoawaitExpr *S) { + // FIXME: Implement coroutine serialization. + llvm_unreachable("unimplemented"); +} + +void ASTStmtReader::VisitCoyieldExpr(CoyieldExpr *S) { + // FIXME: Implement coroutine serialization. + llvm_unreachable("unimplemented"); +} + void ASTStmtReader::VisitCapturedStmt(CapturedStmt *S) { VisitStmt(S); ++Idx; @@ -1178,9 +1198,10 @@ void ASTStmtReader::VisitCXXTryStmt(CXXTryStmt *S) { void ASTStmtReader::VisitCXXForRangeStmt(CXXForRangeStmt *S) { VisitStmt(S); - S->setForLoc(ReadSourceLocation(Record, Idx)); - S->setColonLoc(ReadSourceLocation(Record, Idx)); - S->setRParenLoc(ReadSourceLocation(Record, Idx)); + S->ForLoc = ReadSourceLocation(Record, Idx); + S->CoawaitLoc = ReadSourceLocation(Record, Idx); + S->ColonLoc = ReadSourceLocation(Record, Idx); + S->RParenLoc = ReadSourceLocation(Record, Idx); S->setRangeStmt(Reader.ReadSubStmt()); S->setBeginEndStmt(Reader.ReadSubStmt()); S->setCond(Reader.ReadSubExpr()); diff --git a/clang/lib/Serialization/ASTWriterStmt.cpp b/clang/lib/Serialization/ASTWriterStmt.cpp index 7fce3217916..74dc56e72fb 100644 --- a/clang/lib/Serialization/ASTWriterStmt.cpp +++ b/clang/lib/Serialization/ASTWriterStmt.cpp @@ -287,6 +287,26 @@ void ASTStmtWriter::VisitMSAsmStmt(MSAsmStmt *S) { Code = serialization::STMT_MSASM; } +void ASTStmtWriter::VisitCoroutineBodyStmt(CoroutineBodyStmt *S) { + // FIXME: Implement coroutine serialization. + llvm_unreachable("unimplemented"); +} + +void ASTStmtWriter::VisitCoreturnStmt(CoreturnStmt *S) { + // FIXME: Implement coroutine serialization. + llvm_unreachable("unimplemented"); +} + +void ASTStmtWriter::VisitCoawaitExpr(CoawaitExpr *S) { + // FIXME: Implement coroutine serialization. + llvm_unreachable("unimplemented"); +} + +void ASTStmtWriter::VisitCoyieldExpr(CoyieldExpr *S) { + // FIXME: Implement coroutine serialization. + llvm_unreachable("unimplemented"); +} + void ASTStmtWriter::VisitCapturedStmt(CapturedStmt *S) { VisitStmt(S); // NumCaptures @@ -1135,6 +1155,7 @@ void ASTStmtWriter::VisitCXXTryStmt(CXXTryStmt *S) { void ASTStmtWriter::VisitCXXForRangeStmt(CXXForRangeStmt *S) { VisitStmt(S); Writer.AddSourceLocation(S->getForLoc(), Record); + Writer.AddSourceLocation(S->getCoawaitLoc(), Record); Writer.AddSourceLocation(S->getColonLoc(), Record); Writer.AddSourceLocation(S->getRParenLoc(), Record); Writer.AddStmt(S->getRangeStmt()); diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp index eee4928c481..afef624f5dc 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -765,6 +765,10 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred, case Stmt::PackExpansionExprClass: case Stmt::SubstNonTypeTemplateParmPackExprClass: case Stmt::FunctionParmPackExprClass: + case Stmt::CoroutineBodyStmtClass: + case Stmt::CoawaitExprClass: + case Stmt::CoreturnStmtClass: + case Stmt::CoyieldExprClass: case Stmt::SEHTryStmtClass: case Stmt::SEHExceptStmtClass: case Stmt::SEHLeaveStmtClass: |

