aboutsummaryrefslogtreecommitdiff
path: root/clang/lib/Analysis/ReachableCode.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib/Analysis/ReachableCode.cpp')
-rw-r--r--clang/lib/Analysis/ReachableCode.cpp37
1 files changed, 18 insertions, 19 deletions
diff --git a/clang/lib/Analysis/ReachableCode.cpp b/clang/lib/Analysis/ReachableCode.cpp
index 3b1f716..dd81c8e 100644
--- a/clang/lib/Analysis/ReachableCode.cpp
+++ b/clang/lib/Analysis/ReachableCode.cpp
@@ -454,12 +454,11 @@ bool DeadCodeScan::isDeadCodeRoot(const clang::CFGBlock *Block) {
return isDeadRoot;
}
-// Check if the given `DeadStmt` is one of target statements or is a sub-stmt of
-// them. `Block` is the CFGBlock containing the `DeadStmt`.
-template <class... Ts>
-static bool isDeadStmtInOneOf(const Stmt *DeadStmt, const CFGBlock *Block) {
+// Check if the given `DeadStmt` is a coroutine statement and is a substmt of
+// the coroutine statement. `Block` is the CFGBlock containing the `DeadStmt`.
+static bool isInCoroutineStmt(const Stmt *DeadStmt, const CFGBlock *Block) {
// The coroutine statement, co_return, co_await, or co_yield.
- const Stmt *TargetStmt = nullptr;
+ const Stmt *CoroStmt = nullptr;
// Find the first coroutine statement after the DeadStmt in the block.
bool AfterDeadStmt = false;
for (CFGBlock::const_iterator I = Block->begin(), E = Block->end(); I != E;
@@ -468,27 +467,32 @@ static bool isDeadStmtInOneOf(const Stmt *DeadStmt, const CFGBlock *Block) {
const Stmt *S = CS->getStmt();
if (S == DeadStmt)
AfterDeadStmt = true;
- if (AfterDeadStmt && llvm::isa<Ts...>(S)) {
- TargetStmt = S;
+ if (AfterDeadStmt &&
+ // For simplicity, we only check simple coroutine statements.
+ (llvm::isa<CoreturnStmt>(S) || llvm::isa<CoroutineSuspendExpr>(S))) {
+ CoroStmt = S;
break;
}
}
- if (!TargetStmt)
+ if (!CoroStmt)
return false;
struct Checker : DynamicRecursiveASTVisitor {
const Stmt *DeadStmt;
- bool IsSubStmtOfTargetStmt = false;
- Checker(const Stmt *S) : DeadStmt(S) { ShouldVisitImplicitCode = true; }
+ bool CoroutineSubStmt = false;
+ Checker(const Stmt *S) : DeadStmt(S) {
+ // Statements captured in the CFG can be implicit.
+ ShouldVisitImplicitCode = true;
+ }
bool VisitStmt(Stmt *S) override {
if (S == DeadStmt)
- IsSubStmtOfTargetStmt = true;
+ CoroutineSubStmt = true;
return true;
}
};
Checker checker(DeadStmt);
- checker.TraverseStmt(const_cast<Stmt *>(TargetStmt));
- return checker.IsSubStmtOfTargetStmt;
+ checker.TraverseStmt(const_cast<Stmt *>(CoroStmt));
+ return checker.CoroutineSubStmt;
}
static bool isValidDeadStmt(const Stmt *S, const clang::CFGBlock *Block) {
@@ -499,12 +503,7 @@ static bool isValidDeadStmt(const Stmt *S, const clang::CFGBlock *Block) {
// Coroutine statements are never considered dead statements, because removing
// them may change the function semantic if it is the only coroutine statement
// of the coroutine.
- //
- // If the dead stmt is a sub-stmt of CXXDefaultInitExpr and CXXDefaultArgExpr,
- // we would rather expect to find CXXDefaultInitExpr and CXXDefaultArgExpr as
- // a valid dead stmt.
- return !isDeadStmtInOneOf<CoreturnStmt, CoroutineSuspendExpr,
- CXXDefaultArgExpr, CXXDefaultInitExpr>(S, Block);
+ return !isInCoroutineStmt(S, Block);
}
const Stmt *DeadCodeScan::findDeadCode(const clang::CFGBlock *Block) {