diff options
Diffstat (limited to 'clang/lib/Analysis/ReachableCode.cpp')
-rw-r--r-- | clang/lib/Analysis/ReachableCode.cpp | 62 |
1 files changed, 40 insertions, 22 deletions
diff --git a/clang/lib/Analysis/ReachableCode.cpp b/clang/lib/Analysis/ReachableCode.cpp index 994f9d2a12f..09b0efd0e68 100644 --- a/clang/lib/Analysis/ReachableCode.cpp +++ b/clang/lib/Analysis/ReachableCode.cpp @@ -59,9 +59,14 @@ static bool bodyEndsWithNoReturn(const CFGBlock::AdjacentBlock &AB) { return bodyEndsWithNoReturn(Pred); } -static bool isBreakPrecededByNoReturn(const CFGBlock *B, - const Stmt *S) { - if (!isa<BreakStmt>(S) || B->pred_empty()) +static bool isBreakPrecededByNoReturn(const CFGBlock *B, const Stmt *S, + reachable_code::UnreachableKind &UK) { + if (!isa<BreakStmt>(S)) + return false; + + UK = reachable_code::UK_Break; + + if (B->pred_empty()) return false; assert(B->empty()); @@ -131,23 +136,17 @@ static bool isTrivialExpression(const Expr *Ex) { isEnumConstant(Ex); } -static bool isTrivialReturnOrDoWhile(const CFGBlock *B, const Stmt *S) { - const Expr *Ex = dyn_cast<Expr>(S); - - if (Ex && !isTrivialExpression(Ex)) - return false; - +static bool isTrivialReturnOrDoWhile(const CFGBlock *B, const Stmt *S, + reachable_code::UnreachableKind &UK) { // Check if the block ends with a do...while() and see if 'S' is the // condition. if (const Stmt *Term = B->getTerminator()) { - if (const DoStmt *DS = dyn_cast<DoStmt>(Term)) - if (DS->getCond() == S) - return true; + if (const DoStmt *DS = dyn_cast<DoStmt>(Term)) { + const Expr *Cond = DS->getCond(); + return Cond == S && isTrivialExpression(Cond); + } } - if (B->pred_size() != 1) - return false; - // Look to see if the block ends with a 'return', and see if 'S' // is a substatement. The 'return' may not be the last element in // the block because of destructors. @@ -155,17 +154,33 @@ static bool isTrivialReturnOrDoWhile(const CFGBlock *B, const Stmt *S) { I != E; ++I) { if (Optional<CFGStmt> CS = I->getAs<CFGStmt>()) { if (const ReturnStmt *RS = dyn_cast<ReturnStmt>(CS->getStmt())) { + // Determine if we need to lock at the body of the block + // before the dead return. bool LookAtBody = false; - if (RS == S) + if (RS == S) { LookAtBody = true; + UK = reachable_code::UK_TrivialReturn; + } else { const Expr *RE = RS->getRetValue(); - if (RE && stripExprSugar(RE->IgnoreParenCasts()) == Ex) - LookAtBody = true; + if (RE) { + RE = stripExprSugar(RE->IgnoreParenCasts()); + if (RE == S) { + UK = reachable_code::UK_TrivialReturn; + LookAtBody = isTrivialExpression(RE); + } + } } - if (LookAtBody) + if (LookAtBody) { + // More than one predecessor? Restrict the heuristic + // to looking at return statements directly dominated + // by a noreturn call. + if (B->pred_size() != 1) + return false; + return bodyEndsWithNoReturn(*B->pred_begin()); + } } break; } @@ -588,19 +603,22 @@ static SourceLocation GetUnreachableLoc(const Stmt *S, void DeadCodeScan::reportDeadCode(const CFGBlock *B, const Stmt *S, clang::reachable_code::Callback &CB) { + // The kind of unreachable code found. + reachable_code::UnreachableKind UK = reachable_code::UK_Other; + // Suppress idiomatic cases of calling a noreturn function just // before executing a 'break'. If there is other code after the 'break' // in the block then don't suppress the warning. - if (isBreakPrecededByNoReturn(B, S)) + if (isBreakPrecededByNoReturn(B, S, UK)) return; // Suppress trivial 'return' statements that are dead. - if (isTrivialReturnOrDoWhile(B, S)) + if (UK == reachable_code::UK_Other && isTrivialReturnOrDoWhile(B, S, UK)) return; SourceRange R1, R2; SourceLocation Loc = GetUnreachableLoc(S, R1, R2); - CB.HandleUnreachable(Loc, R1, R2); + CB.HandleUnreachable(UK, Loc, R1, R2); } //===----------------------------------------------------------------------===// |