Skip to content

Commit

Permalink
[clang][pr55896]:co_yield/co_await thread-safety
Browse files Browse the repository at this point in the history
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
  • Loading branch information
urnathan committed Jun 9, 2022
1 parent 982053e commit 65b34b7
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 0 deletions.
27 changes: 27 additions & 0 deletions clang/lib/Analysis/CFG.cpp
Expand Up @@ -597,6 +597,8 @@ class CFGBuilder {
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);
Expand Down Expand Up @@ -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));

Expand Down Expand Up @@ -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.
Expand Down
4 changes: 4 additions & 0 deletions clang/test/SemaCXX/thread-safety-coro.cpp
Expand Up @@ -38,10 +38,14 @@ class Task {
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; });
}

0 comments on commit 65b34b7

Please sign in to comment.