From: Ted Kremenek Date: Thu, 27 Feb 2014 06:32:32 +0000 (+0000) Subject: [-Wunreachable-code] Don't warn about trivially unreachable return statements precede... X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=5c13e145485664e6b5d496eda10559fed4fc1b50;p=clang [-Wunreachable-code] Don't warn about trivially unreachable return statements preceded by 'noreturn' functions. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@202352 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Analysis/ReachableCode.cpp b/lib/Analysis/ReachableCode.cpp index 046c9f4792..797e02ed6f 100644 --- a/lib/Analysis/ReachableCode.cpp +++ b/lib/Analysis/ReachableCode.cpp @@ -262,6 +262,12 @@ static bool bodyEndsWithNoReturn(const CFGBlock *B) { return false; } +static bool bodyEndsWithNoReturn(const CFGBlock::AdjacentBlock &AB) { + const CFGBlock *Pred = AB.getPossiblyUnreachableBlock(); + assert(!AB.isReachable() && Pred); + return bodyEndsWithNoReturn(Pred); +} + static bool isBreakPrecededByNoReturn(const CFGBlock *B, const Stmt *S) { if (!isa(S) || B->pred_empty()) @@ -269,10 +275,53 @@ static bool isBreakPrecededByNoReturn(const CFGBlock *B, assert(B->empty()); assert(B->pred_size() == 1); - const CFGBlock::AdjacentBlock &AB = *B->pred_begin(); - const CFGBlock *Pred = AB.getPossiblyUnreachableBlock(); - assert(!AB.isReachable() && Pred); - return bodyEndsWithNoReturn(Pred); + return bodyEndsWithNoReturn(*B->pred_begin()); +} + +static bool isEnumConstant(const Expr *Ex) { + const DeclRefExpr *DR = dyn_cast(Ex); + if (!DR) + return false; + return isa(DR->getDecl()); +} + +static bool isTrivialExpression(const Expr *Ex) { + return isa(Ex) || isa(Ex) || + isEnumConstant(Ex); +} + +static bool isTrivialReturnPrecededByNoReturn(const CFGBlock *B, + const Stmt *S) { + if (B->pred_empty()) + return false; + + const Expr *Ex = dyn_cast(S); + if (!Ex) + return false; + + Ex = Ex->IgnoreParenCasts(); + + if (!isTrivialExpression(Ex)) + 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. + assert(!B->empty()); + for (CFGBlock::const_reverse_iterator I = B->rbegin(), E = B->rend(); + I != E; ++I) { + if (Optional CS = I->getAs()) { + if (const ReturnStmt *RS = dyn_cast(CS->getStmt())) { + const Expr *RE = RS->getRetValue(); + if (RE && RE->IgnoreParenCasts() == Ex) + break; + } + return false; + } + } + + assert(B->pred_size() == 1); + return bodyEndsWithNoReturn(*B->pred_begin()); } void DeadCodeScan::reportDeadCode(const CFGBlock *B, @@ -284,6 +333,10 @@ void DeadCodeScan::reportDeadCode(const CFGBlock *B, if (isBreakPrecededByNoReturn(B, S)) return; + // Suppress trivial 'return' statements that are dead. + if (isTrivialReturnPrecededByNoReturn(B, S)) + return; + // Was this an unreachable 'default' case? Such cases are covered // by -Wcovered-switch-default, if the user so desires. const Stmt *Label = B->getLabel(); diff --git a/test/Sema/warn-unreachable.c b/test/Sema/warn-unreachable.c index 59d3617caa..a6bc6a94fc 100644 --- a/test/Sema/warn-unreachable.c +++ b/test/Sema/warn-unreachable.c @@ -187,3 +187,16 @@ void unreachable_in_default(MyEnum e) { } } +// Don't warn about trivial dead returns. +int trivial_dead_return() { + raze(); + // Use the '()' to test that we unwrap such stuff + // when looking for dead code. + return ((0)); // no-warning +} + +MyEnum trival_dead_return_enum() { + raze(); + return Value1; // no-warning +} +