[clang] Reapply [Analyzer][CFG] Correctly handle rebuilt default arg and default init expression (PR #146281)
via cfe-commits
cfe-commits at lists.llvm.org
Sun Jun 29 10:00:51 PDT 2025
================
@@ -453,70 +455,35 @@ bool DeadCodeScan::isDeadCodeRoot(const clang::CFGBlock *Block) {
return isDeadRoot;
}
-// 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 *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;
- ++I)
- if (std::optional<CFGStmt> CS = I->getAs<CFGStmt>()) {
- const Stmt *S = CS->getStmt();
- if (S == DeadStmt)
- AfterDeadStmt = true;
- if (AfterDeadStmt &&
- // For simplicity, we only check simple coroutine statements.
- (llvm::isa<CoreturnStmt>(S) || llvm::isa<CoroutineSuspendExpr>(S))) {
- CoroStmt = S;
- break;
- }
- }
- if (!CoroStmt)
- return false;
- struct Checker : DynamicRecursiveASTVisitor {
- const Stmt *DeadStmt;
- 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)
- CoroutineSubStmt = true;
- return true;
- }
- };
- Checker checker(DeadStmt);
- checker.TraverseStmt(const_cast<Stmt *>(CoroStmt));
- return checker.CoroutineSubStmt;
-}
-
-static bool isValidDeadStmt(const Stmt *S, const clang::CFGBlock *Block) {
+static bool isValidDeadStmt(ParentMap &PM, const Stmt *S, const clang::CFGBlock *Block) {
if (S->getBeginLoc().isInvalid())
return false;
if (const BinaryOperator *BO = dyn_cast<BinaryOperator>(S))
return BO->getOpcode() != BO_Comma;
// 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.
- return !isInCoroutineStmt(S, Block);
+ return !PM.getInnerMostAncestor<CoreturnStmt, CoroutineSuspendExpr>(S);
}
const Stmt *DeadCodeScan::findDeadCode(const clang::CFGBlock *Block) {
+ auto &PM = AC.getParentMap();
+
for (CFGBlock::const_iterator I = Block->begin(), E = Block->end(); I!=E; ++I)
if (std::optional<CFGStmt> CS = I->getAs<CFGStmt>()) {
const Stmt *S = CS->getStmt();
- if (isValidDeadStmt(S, Block))
+ auto *RewrittenParent =
+ PM.getOuterMostAncestor<CXXDefaultArgExpr, CXXDefaultInitExpr>(S);
----------------
yronglin wrote:
I try to fix Nico's example(https://github.com/llvm/llvm-project/issues/128195) about the wrong unrachable code location. The root cause of this issue is that this PR introduce "rewritten" expressions in `CFGBlock`. When we are finding the real dead code, we should try to ignore the "rewritten" sub-expression nodes in `CXXDefaultInitExpr`/`CXXDefaultArgExpr`, but I'm not sure this option is make sense. What do you think?
https://github.com/llvm/llvm-project/pull/146281
More information about the cfe-commits
mailing list