forked from OSchip/llvm-project
[clang][pr55896]:co_yield/co_await thread-safety
co_await and co_yield are represented by (classes derived from) CoroutineSuspendExpr. That has a number of child nodes, not all of which are used for code-generation. In particular the operand is represented multiple times, and, like the problem with co_return (55406) it must only be emitted in the CFG exactly once. The operand also appears inside OpaqueValueExprs, but that's ok. This adds a visitor for SuspendExprs to emit the required children in the correct order. Note that this CFG is pre-coro xform. We don't have initial or final suspend points. Reviewed By: bruno Differential Revision: https://reviews.llvm.org/D127236
This commit is contained in:
parent
982053e85e
commit
65b34b78f8
|
@ -597,6 +597,8 @@ private:
|
|||
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 @@ CFGBlock *CFGBuilder::Visit(Stmt * S, AddStmtChoice asc,
|
|||
case Stmt::CoreturnStmtClass:
|
||||
return VisitReturnStmt(S);
|
||||
|
||||
case Stmt::CoyieldExprClass:
|
||||
case Stmt::CoawaitExprClass:
|
||||
return VisitCoroutineSuspendExpr(cast<CoroutineSuspendExpr>(S), asc);
|
||||
|
||||
case Stmt::SEHExceptStmtClass:
|
||||
return VisitSEHExceptStmt(cast<SEHExceptStmt>(S));
|
||||
|
||||
|
@ -3152,6 +3158,27 @@ CFGBlock *CFGBuilder::VisitReturnStmt(Stmt *S) {
|
|||
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.
|
||||
|
|
|
@ -38,10 +38,14 @@ public:
|
|||
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; });
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue