[-Wunreachable-code] Don't warn about trivially unreachable return statements preceded by 'noreturn' functions.

llvm-svn: 202352
diff --git a/clang/lib/Analysis/ReachableCode.cpp b/clang/lib/Analysis/ReachableCode.cpp
index 046c9f4..797e02e 100644
--- a/clang/lib/Analysis/ReachableCode.cpp
+++ b/clang/lib/Analysis/ReachableCode.cpp
@@ -262,6 +262,12 @@
   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 @@
 
   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 @@
   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();