]> granicus.if.org Git - clang/commitdiff
[-Wunreachable-code] Don't warn about trivially unreachable return statements precede...
authorTed Kremenek <kremenek@apple.com>
Thu, 27 Feb 2014 06:32:32 +0000 (06:32 +0000)
committerTed Kremenek <kremenek@apple.com>
Thu, 27 Feb 2014 06:32:32 +0000 (06:32 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@202352 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Analysis/ReachableCode.cpp
test/Sema/warn-unreachable.c

index 046c9f4792b6aa77c840ea469ef82e64018b7847..797e02ed6f502cbedadcf23d8f459378d1490184 100644 (file)
@@ -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<BreakStmt>(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<DeclRefExpr>(Ex);
+  if (!DR)
+    return false;
+  return isa<EnumConstantDecl>(DR->getDecl());
+}
+
+static bool isTrivialExpression(const Expr *Ex) {
+  return isa<IntegerLiteral>(Ex) || isa<StringLiteral>(Ex) ||
+         isEnumConstant(Ex);
+}
+
+static bool isTrivialReturnPrecededByNoReturn(const CFGBlock *B,
+                                              const Stmt *S) {
+  if (B->pred_empty())
+    return false;
+
+  const Expr *Ex = dyn_cast<Expr>(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<CFGStmt> CS = I->getAs<CFGStmt>()) {
+      if (const ReturnStmt *RS = dyn_cast<ReturnStmt>(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();
index 59d3617caae91c37f2ade6278d635c10a6b3239b..a6bc6a94fc1b26166454dcadb858af182bb248b0 100644 (file)
@@ -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
+}
+