r203994 - Start breaking -Wunreachable-code up into different diagnostic groups.

Ted Kremenek kremenek at apple.com
Fri Mar 14 18:26:33 PDT 2014


Author: kremenek
Date: Fri Mar 14 20:26:32 2014
New Revision: 203994

URL: http://llvm.org/viewvc/llvm-project?rev=203994&view=rev
Log:
Start breaking -Wunreachable-code up into different diagnostic groups.

Recent work on -Wunreachable-code has focused on suppressing uninteresting
unreachable code that center around "configuration values", but
there are still some set of cases that are sometimes interesting
or uninteresting depending on the codebase.  For example, a dead
"break" statement may not be interesting for a particular codebase,
potentially because it is auto-generated or simply because code
is written defensively.

To address these workflow differences, -Wunreachable-code is now
broken into several diagnostic groups:

-Wunreachable-code: intended to be a reasonable "default" for
most users.

and then other groups that turn on more aggressive checking:

-Wunreachable-code-break: warn about dead break statements

-Wunreachable-code-trivial-return: warn about dead return statements
that return "trivial" values (e.g., return 0).  Other return
statements that return non-trivial values are still reported
under -Wunreachable-code (this is an area subject to more refinement).

-Wunreachable-code-aggressive: supergroup that enables all these
groups.

The goal is to eventually make -Wunreachable-code good enough to
either be in -Wall or on-by-default, thus finessing these warnings
into different groups helps achieve maximum signal for more users.

TODO: the tests need to be updated to reflect this extra control
via diagnostic flags.

Modified:
    cfe/trunk/include/clang/Analysis/Analyses/ReachableCode.h
    cfe/trunk/include/clang/Basic/DiagnosticGroups.td
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/lib/Analysis/ReachableCode.cpp
    cfe/trunk/lib/Sema/AnalysisBasedWarnings.cpp
    cfe/trunk/test/Sema/warn-unreachable.c
    cfe/trunk/test/SemaCXX/unreachable-code.cpp
    cfe/trunk/test/SemaCXX/warn-unreachable.cpp
    cfe/trunk/test/SemaObjC/warn-unreachable.m

Modified: cfe/trunk/include/clang/Analysis/Analyses/ReachableCode.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/Analyses/ReachableCode.h?rev=203994&r1=203993&r2=203994&view=diff
==============================================================================
--- cfe/trunk/include/clang/Analysis/Analyses/ReachableCode.h (original)
+++ cfe/trunk/include/clang/Analysis/Analyses/ReachableCode.h Fri Mar 14 20:26:32 2014
@@ -37,11 +37,19 @@ namespace clang {
 namespace clang {
 namespace reachable_code {
 
+/// Classifications of unreachable code.
+enum UnreachableKind {
+  UK_TrivialReturn,
+  UK_Break,
+  UK_Other
+};
+
 class Callback {
   virtual void anchor();
 public:
   virtual ~Callback() {}
-  virtual void HandleUnreachable(SourceLocation L, SourceRange R1,
+  virtual void HandleUnreachable(UnreachableKind UK,
+                                 SourceLocation L, SourceRange R1,
                                  SourceRange R2) = 0;
 };
 

Modified: cfe/trunk/include/clang/Basic/DiagnosticGroups.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticGroups.td?rev=203994&r1=203993&r2=203994&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticGroups.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticGroups.td Fri Mar 14 20:26:32 2014
@@ -424,6 +424,21 @@ def CharSubscript : DiagGroup<"char-subs
 def LargeByValueCopy : DiagGroup<"large-by-value-copy">;
 def DuplicateArgDecl : DiagGroup<"duplicate-method-arg">;
 
+// Unreachable code warning groups.
+//
+//  The goal is make -Wunreachable-code on by default, in -Wall, or at
+//  least actively used, with more noisy versions of the warning covered
+//  under separate flags.
+//
+def UnreachableCode : DiagGroup<"unreachable-code">;
+def UnreachableCodeBreak : DiagGroup<"unreachable-code-break",
+                            [UnreachableCode]>;
+def UnreachableCodeTrivialReturn : DiagGroup<"unreachable-code-trivial-return",
+                                    [UnreachableCode]>;
+def UnreachableCodeAggressive : DiagGroup<"unreachable-code-aggressive",
+                                    [UnreachableCodeBreak,
+                                     UnreachableCodeTrivialReturn]>;
+
 // Aggregation warning settings.
 
 // -Widiomatic-parentheses contains warnings about 'idiomatic'

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=203994&r1=203993&r2=203994&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Fri Mar 14 20:26:32 2014
@@ -359,8 +359,17 @@ def warn_suggest_noreturn_function : War
 def warn_suggest_noreturn_block : Warning<
   "block could be declared with attribute 'noreturn'">,
   InGroup<MissingNoreturn>, DefaultIgnore;
-def warn_unreachable : Warning<"will never be executed">,
-  InGroup<DiagGroup<"unreachable-code">>, DefaultIgnore;
+
+// Unreachable code.
+def warn_unreachable : Warning<
+  "will never be executed">,
+  InGroup<UnreachableCode>, DefaultIgnore;
+def warn_unreachable_break : Warning<
+  "'break' will never be executed">,
+  InGroup<UnreachableCodeBreak>, DefaultIgnore;
+def warn_unreachable_trivial_return : Warning<
+  "'return' will never be executed">,
+  InGroup<UnreachableCodeTrivialReturn>, DefaultIgnore;
 
 /// Built-in functions.
 def ext_implicit_lib_function_decl : ExtWarn<

Modified: cfe/trunk/lib/Analysis/ReachableCode.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/ReachableCode.cpp?rev=203994&r1=203993&r2=203994&view=diff
==============================================================================
--- cfe/trunk/lib/Analysis/ReachableCode.cpp (original)
+++ cfe/trunk/lib/Analysis/ReachableCode.cpp Fri Mar 14 20:26:32 2014
@@ -59,9 +59,14 @@ static bool bodyEndsWithNoReturn(const C
   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 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(con
        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(
 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);
 }
 
 //===----------------------------------------------------------------------===//

Modified: cfe/trunk/lib/Sema/AnalysisBasedWarnings.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/AnalysisBasedWarnings.cpp?rev=203994&r1=203993&r2=203994&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/AnalysisBasedWarnings.cpp (original)
+++ cfe/trunk/lib/Sema/AnalysisBasedWarnings.cpp Fri Mar 14 20:26:32 2014
@@ -65,9 +65,22 @@ namespace {
   public:
     UnreachableCodeHandler(Sema &s) : S(s) {}
 
-    void HandleUnreachable(SourceLocation L, SourceRange R1,
+    void HandleUnreachable(reachable_code::UnreachableKind UK,
+                           SourceLocation L, SourceRange R1,
                            SourceRange R2) override {
-      S.Diag(L, diag::warn_unreachable) << R1 << R2;
+      unsigned diag = diag::warn_unreachable;
+      switch (UK) {
+        case reachable_code::UK_Break:
+          diag = diag::warn_unreachable_break;
+          break;
+        case reachable_code::UK_TrivialReturn:
+          diag = diag::warn_unreachable_trivial_return;
+          break;
+        case reachable_code::UK_Other:
+          break;
+      }
+
+      S.Diag(L, diag) << R1 << R2;
     }
   };
 }

Modified: cfe/trunk/test/Sema/warn-unreachable.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/warn-unreachable.c?rev=203994&r1=203993&r2=203994&view=diff
==============================================================================
--- cfe/trunk/test/Sema/warn-unreachable.c (original)
+++ cfe/trunk/test/Sema/warn-unreachable.c Fri Mar 14 20:26:32 2014
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 %s -fsyntax-only -verify -fblocks -Wunreachable-code -Wno-unused-value -Wno-covered-switch-default -I %S/Inputs
+// RUN: %clang_cc1 %s -fsyntax-only -verify -fblocks -Wunreachable-code-aggressive -Wno-unused-value -Wno-covered-switch-default -I %S/Inputs
 
 #include "warn-unreachable.h"
 

Modified: cfe/trunk/test/SemaCXX/unreachable-code.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/unreachable-code.cpp?rev=203994&r1=203993&r2=203994&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/unreachable-code.cpp (original)
+++ cfe/trunk/test/SemaCXX/unreachable-code.cpp Fri Mar 14 20:26:32 2014
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -fsyntax-only -Wunreachable-code -fblocks -verify %s
+// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -fsyntax-only -Wunreachable-code-aggressive -fblocks -verify %s
 
 int j;
 int bar();

Modified: cfe/trunk/test/SemaCXX/warn-unreachable.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/warn-unreachable.cpp?rev=203994&r1=203993&r2=203994&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/warn-unreachable.cpp (original)
+++ cfe/trunk/test/SemaCXX/warn-unreachable.cpp Fri Mar 14 20:26:32 2014
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 %s -fcxx-exceptions -fexceptions -fsyntax-only -verify -fblocks -Wunreachable-code -Wno-unused-value
+// RUN: %clang_cc1 %s -fcxx-exceptions -fexceptions -fsyntax-only -verify -fblocks -Wunreachable-code-aggressive -Wno-unused-value
 
 int &halt() __attribute__((noreturn));
 int &live();

Modified: cfe/trunk/test/SemaObjC/warn-unreachable.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjC/warn-unreachable.m?rev=203994&r1=203993&r2=203994&view=diff
==============================================================================
--- cfe/trunk/test/SemaObjC/warn-unreachable.m (original)
+++ cfe/trunk/test/SemaObjC/warn-unreachable.m Fri Mar 14 20:26:32 2014
@@ -1,4 +1,4 @@
-// RUN: %clang %s -fsyntax-only -Xclang -verify -fblocks -Wunreachable-code -Wno-unused-value -Wno-covered-switch-default
+// RUN: %clang %s -fsyntax-only -Xclang -verify -fblocks -Wunreachable-code-aggressive -Wno-unused-value -Wno-covered-switch-default
 
 // This previously triggered a warning from -Wunreachable-code because of
 // a busted CFG.





More information about the cfe-commits mailing list