diff --git a/clang/lib/Analysis/CFG.cpp b/clang/lib/Analysis/CFG.cpp --- a/clang/lib/Analysis/CFG.cpp +++ b/clang/lib/Analysis/CFG.cpp @@ -597,6 +597,8 @@ CFGBlock *VisitObjCMessageExpr(ObjCMessageExpr *E, AddStmtChoice asc); CFGBlock *VisitPseudoObjectExpr(PseudoObjectExpr *E); CFGBlock *VisitReturnStmt(Stmt *S); + CFGBlock *VisitCoroutineSuspendExpr(CoroutineSuspendExpr *S, + AddStmtChoice asc); CFGBlock *VisitSEHExceptStmt(SEHExceptStmt *S); CFGBlock *VisitSEHFinallyStmt(SEHFinallyStmt *S); CFGBlock *VisitSEHLeaveStmt(SEHLeaveStmt *S); @@ -2297,6 +2299,10 @@ case Stmt::CoreturnStmtClass: return VisitReturnStmt(S); + case Stmt::CoyieldExprClass: + case Stmt::CoawaitExprClass: + return VisitCoroutineSuspendExpr(cast(S), asc); + case Stmt::SEHExceptStmtClass: return VisitSEHExceptStmt(cast(S)); @@ -3152,6 +3158,27 @@ return B; } +CFGBlock *CFGBuilder::VisitCoroutineSuspendExpr(CoroutineSuspendExpr *E, + AddStmtChoice asc) { + // We're modelling the pre-coro-xform CFG. Thus just evalate the various + // active components of the co_await or co_yield. Note we do not model the + // edge from the builtin_suspend to the exit node. + if (asc.alwaysAdd(*this, E)) { + autoCreateBlock(); + appendStmt(Block, E); + } + CFGBlock *B = Block; + if (auto *R = Visit(E->getResumeExpr())) + B = R; + if (auto *R = Visit(E->getSuspendExpr())) + B = R; + if (auto *R = Visit(E->getReadyExpr())) + B = R; + if (auto *R = Visit(E->getCommonExpr())) + B = R; + return B; +} + CFGBlock *CFGBuilder::VisitSEHExceptStmt(SEHExceptStmt *ES) { // SEHExceptStmt are treated like labels, so they are the first statement in a // block. diff --git a/clang/test/SemaCXX/thread-safety-coro.cpp b/clang/test/SemaCXX/thread-safety-coro.cpp --- a/clang/test/SemaCXX/thread-safety-coro.cpp +++ b/clang/test/SemaCXX/thread-safety-coro.cpp @@ -38,10 +38,14 @@ Task get_return_object() noexcept; void unhandled_exception() noexcept; void return_value(int value) noexcept; + + std::suspend_always yield_value(int value) noexcept; }; }; Task Foo() noexcept { // ICE'd + co_yield({ int frame = 0; 0; }); + co_await({ int frame = 0; std::suspend_always(); }); co_return({ int frame = 0; 0; }); }