Skip to content

Commit 65b34b7

Browse files
committed
[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
1 parent 982053e commit 65b34b7

File tree

2 files changed

+31
-0
lines changed

2 files changed

+31
-0
lines changed

clang/lib/Analysis/CFG.cpp

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -597,6 +597,8 @@ class CFGBuilder {
597597
CFGBlock *VisitObjCMessageExpr(ObjCMessageExpr *E, AddStmtChoice asc);
598598
CFGBlock *VisitPseudoObjectExpr(PseudoObjectExpr *E);
599599
CFGBlock *VisitReturnStmt(Stmt *S);
600+
CFGBlock *VisitCoroutineSuspendExpr(CoroutineSuspendExpr *S,
601+
AddStmtChoice asc);
600602
CFGBlock *VisitSEHExceptStmt(SEHExceptStmt *S);
601603
CFGBlock *VisitSEHFinallyStmt(SEHFinallyStmt *S);
602604
CFGBlock *VisitSEHLeaveStmt(SEHLeaveStmt *S);
@@ -2297,6 +2299,10 @@ CFGBlock *CFGBuilder::Visit(Stmt * S, AddStmtChoice asc,
22972299
case Stmt::CoreturnStmtClass:
22982300
return VisitReturnStmt(S);
22992301

2302+
case Stmt::CoyieldExprClass:
2303+
case Stmt::CoawaitExprClass:
2304+
return VisitCoroutineSuspendExpr(cast<CoroutineSuspendExpr>(S), asc);
2305+
23002306
case Stmt::SEHExceptStmtClass:
23012307
return VisitSEHExceptStmt(cast<SEHExceptStmt>(S));
23022308

@@ -3152,6 +3158,27 @@ CFGBlock *CFGBuilder::VisitReturnStmt(Stmt *S) {
31523158
return B;
31533159
}
31543160

3161+
CFGBlock *CFGBuilder::VisitCoroutineSuspendExpr(CoroutineSuspendExpr *E,
3162+
AddStmtChoice asc) {
3163+
// We're modelling the pre-coro-xform CFG. Thus just evalate the various
3164+
// active components of the co_await or co_yield. Note we do not model the
3165+
// edge from the builtin_suspend to the exit node.
3166+
if (asc.alwaysAdd(*this, E)) {
3167+
autoCreateBlock();
3168+
appendStmt(Block, E);
3169+
}
3170+
CFGBlock *B = Block;
3171+
if (auto *R = Visit(E->getResumeExpr()))
3172+
B = R;
3173+
if (auto *R = Visit(E->getSuspendExpr()))
3174+
B = R;
3175+
if (auto *R = Visit(E->getReadyExpr()))
3176+
B = R;
3177+
if (auto *R = Visit(E->getCommonExpr()))
3178+
B = R;
3179+
return B;
3180+
}
3181+
31553182
CFGBlock *CFGBuilder::VisitSEHExceptStmt(SEHExceptStmt *ES) {
31563183
// SEHExceptStmt are treated like labels, so they are the first statement in a
31573184
// block.

clang/test/SemaCXX/thread-safety-coro.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,10 +38,14 @@ class Task {
3838
Task get_return_object() noexcept;
3939
void unhandled_exception() noexcept;
4040
void return_value(int value) noexcept;
41+
42+
std::suspend_always yield_value(int value) noexcept;
4143
};
4244
};
4345

4446
Task Foo() noexcept {
4547
// ICE'd
48+
co_yield({ int frame = 0; 0; });
49+
co_await({ int frame = 0; std::suspend_always(); });
4650
co_return({ int frame = 0; 0; });
4751
}

0 commit comments

Comments
 (0)