@@ -61,45 +61,6 @@ static bool isTrivialDoWhile(const CFGBlock *B, const Stmt *S) {
61
61
return false ;
62
62
}
63
63
64
- // Check if the block starts with a coroutine statement and see if the given
65
- // unreachable 'S' is the substmt of the coroutine statement.
66
- //
67
- // We suppress the unreachable warning for cases where an unreachable code is
68
- // a substmt of the coroutine statement, becase removing it will change the
69
- // function semantic if this is the only coroutine statement of the coroutine.
70
- static bool isInCoroutineStmt (const CFGBlock *Block, const Stmt* S) {
71
- // The coroutine statement, co_return, co_await, or co_yield.
72
- const Stmt* CoroStmt = nullptr ;
73
- // Find the first coroutine statement in the block.
74
- for (CFGBlock::const_iterator I = Block->begin (), E = Block->end (); I != E;
75
- ++I)
76
- if (std::optional<CFGStmt> CS = I->getAs <CFGStmt>()) {
77
- const Stmt *S = CS->getStmt ();
78
- if (llvm::isa<CoreturnStmt>(S) || llvm::isa<CoroutineSuspendExpr>(S)) {
79
- CoroStmt = S ;
80
- break ;
81
- }
82
- }
83
- if (!CoroStmt)
84
- return false ;
85
-
86
- struct Checker : RecursiveASTVisitor<Checker> {
87
- const Stmt *StmtToCheck;
88
- bool CoroutineSubStmt = false ;
89
- Checker (const Stmt *S) : StmtToCheck(S) {}
90
- bool VisitStmt (const Stmt *S) {
91
- if (S == StmtToCheck)
92
- CoroutineSubStmt = true ;
93
- return true ;
94
- }
95
- // The 'S' stmt captured in the CFG can be implicit.
96
- bool shouldVisitImplicitCode () const { return true ; }
97
- };
98
- Checker checker (S);
99
- checker.TraverseStmt (const_cast <Stmt *>(CoroStmt));
100
- return checker.CoroutineSubStmt ;
101
- }
102
-
103
64
static bool isBuiltinUnreachable (const Stmt *S) {
104
65
if (const auto *DRE = dyn_cast<DeclRefExpr>(S))
105
66
if (const auto *FDecl = dyn_cast<FunctionDecl>(DRE->getDecl ()))
@@ -493,26 +454,64 @@ bool DeadCodeScan::isDeadCodeRoot(const clang::CFGBlock *Block) {
493
454
return isDeadRoot;
494
455
}
495
456
496
- static bool isValidDeadStmt (const Stmt *S) {
457
+ // Check if the given `DeadStmt` is a coroutine statement and is a substmt of
458
+ // the coroutine statement.
459
+ static bool isInCoroutineStmt (const Stmt* DeadStmt, const CFGBlock *Block) {
460
+ // The coroutine statement, co_return, co_await, or co_yield.
461
+ const Stmt* CoroStmt = nullptr ;
462
+ // Find the first coroutine statement in the block.
463
+ for (CFGBlock::const_iterator I = Block->begin (), E = Block->end (); I != E;
464
+ ++I)
465
+ if (std::optional<CFGStmt> CS = I->getAs <CFGStmt>()) {
466
+ const Stmt *S = CS->getStmt ();
467
+ if (llvm::isa<CoreturnStmt>(S) || llvm::isa<CoroutineSuspendExpr>(S)) {
468
+ CoroStmt = S ;
469
+ break ;
470
+ }
471
+ }
472
+ if (!CoroStmt)
473
+ return false ;
474
+
475
+ struct Checker : RecursiveASTVisitor<Checker> {
476
+ const Stmt *StmtToCheck;
477
+ bool CoroutineSubStmt = false ;
478
+ Checker (const Stmt *S) : StmtToCheck(S) {}
479
+ bool VisitStmt (const Stmt *S) {
480
+ if (S == StmtToCheck)
481
+ CoroutineSubStmt = true ;
482
+ return true ;
483
+ }
484
+ // Statements captured in the CFG can be implicit.
485
+ bool shouldVisitImplicitCode () const { return true ; }
486
+ };
487
+ Checker checker (DeadStmt);
488
+ checker.TraverseStmt (const_cast <Stmt *>(CoroStmt));
489
+ return checker.CoroutineSubStmt ;
490
+ }
491
+
492
+ static bool isValidDeadStmt (const Stmt *S, const clang::CFGBlock *Block) {
497
493
if (S->getBeginLoc ().isInvalid ())
498
494
return false ;
499
495
if (const BinaryOperator *BO = dyn_cast<BinaryOperator>(S))
500
496
return BO->getOpcode () != BO_Comma;
501
- return true ;
497
+ // Coroutine statements are never considered dead statements, because removing
498
+ // them may change the function semantic if it is the only coroutine statement
499
+ // of the coroutine.
500
+ return !isInCoroutineStmt (S, Block);
502
501
}
503
502
504
503
const Stmt *DeadCodeScan::findDeadCode (const clang::CFGBlock *Block) {
505
504
for (CFGBlock::const_iterator I = Block->begin (), E = Block->end (); I!=E; ++I)
506
505
if (std::optional<CFGStmt> CS = I->getAs <CFGStmt>()) {
507
506
const Stmt *S = CS->getStmt ();
508
- if (isValidDeadStmt (S))
507
+ if (isValidDeadStmt (S, Block ))
509
508
return S;
510
509
}
511
510
512
511
CFGTerminator T = Block->getTerminator ();
513
512
if (T.isStmtBranch ()) {
514
513
const Stmt *S = T.getStmt ();
515
- if (S && isValidDeadStmt (S))
514
+ if (S && isValidDeadStmt (S, Block ))
516
515
return S;
517
516
}
518
517
@@ -663,7 +662,7 @@ void DeadCodeScan::reportDeadCode(const CFGBlock *B,
663
662
if (isa<BreakStmt>(S)) {
664
663
UK = reachable_code::UK_Break;
665
664
} else if (isTrivialDoWhile (B, S) || isBuiltinUnreachable (S) ||
666
- isBuiltinAssumeFalse (B, S, C) || isInCoroutineStmt (B, S) ) {
665
+ isBuiltinAssumeFalse (B, S, C)) {
667
666
return ;
668
667
}
669
668
else if (isDeadReturn (B, S)) {
0 commit comments