]> granicus.if.org Git - clang/commitdiff
[analyzer] Add a checker option to detect nested dead stores
authorKristof Umann <kristof.umann@ericsson.com>
Tue, 3 Sep 2019 15:22:43 +0000 (15:22 +0000)
committerKristof Umann <kristof.umann@ericsson.com>
Tue, 3 Sep 2019 15:22:43 +0000 (15:22 +0000)
Enables the users to specify an optional flag which would warn for more dead
stores.
Previously it ignored if the dead store happened e.g. in an if condition.

if ((X = generate())) { // dead store to X
}

This patch introduces the `WarnForDeadNestedAssignments` option to the checker,
which is `false` by default - so this change would not affect any previous
users.
I have updated the code, tests and the docs as well. If I missed something, tell
me.

I also ran the analysis on Clang which generated 14 more reports compared to the
unmodified version. All of them seemed reasonable for me.

Related previous patches:
rGf224820b45c6847b91071da8d7ade59f373b96f3

Reviewers: NoQ, krememek, Szelethus, baloghadamsoftware

Reviewed By: Szelethus

Patch by Balázs Benics!

Differential Revision: https://reviews.llvm.org/D66733

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@370767 91177308-0d34-0410-b5e6-96231b3b80d8

docs/analyzer/checkers.rst
include/clang/StaticAnalyzer/Checkers/Checkers.td
lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp
test/Analysis/analyzer-config.c
test/Analysis/dead-stores.c
test/Analysis/dead-stores.cpp
test/Analysis/dead-stores.m

index f50fff918cda7aed4d4f136c9ab074ae99176a8f..a751b14809752945fa0fda2e60efac6b6403b9e8 100644 (file)
@@ -319,6 +319,15 @@ Check for values stored to variables that are never read afterwards.
    x = 1; // warn
  }
 
+The ``WarnForDeadNestedAssignments`` option enables the checker to emit
+warnings for nested dead assignments. You can disable with the
+``-analyzer-config deadcode.DeadStores:WarnForDeadNestedAssignments=false``.
+*Defaults to true*.
+
+Would warn for this e.g.:
+if ((y = make_int())) {
+}
+
 .. _nullability-checkers:
 
 nullability
index da59b3af3cd7759504f48dd80acc097fa0ea07f4..0626d29c3d6044ec118777a813ad2680ee5664dd 100644 (file)
@@ -648,6 +648,14 @@ let ParentPackage = DeadCode in {
 def DeadStoresChecker : Checker<"DeadStores">,
   HelpText<"Check for values stored to variables that are never read "
            "afterwards">,
+  CheckerOptions<[
+    CmdLineOption<Boolean,
+                  "WarnForDeadNestedAssignments",
+                  "Warns for deadstores in nested assignments."
+                  "E.g.: if ((P = f())) where P is unused.",
+                  "true",
+                  Released>
+  ]>,
   Documentation<HasDocumentation>;
 
 } // end DeadCode
index d5baa2bcba6fc79d8fa3a54367f4bd806e0dd439..e4889c1cc14df739fe79baa023726c8bc42d8f0c 100644 (file)
@@ -130,6 +130,7 @@ class DeadStoreObs : public LiveVariables::Observer {
   std::unique_ptr<ReachableCode> reachableCode;
   const CFGBlock *currentBlock;
   std::unique_ptr<llvm::DenseSet<const VarDecl *>> InEH;
+  const bool WarnForDeadNestedAssignments;
 
   enum DeadStoreKind { Standard, Enclosing, DeadIncrement, DeadInit };
 
@@ -137,9 +138,11 @@ public:
   DeadStoreObs(const CFG &cfg, ASTContext &ctx, BugReporter &br,
                const CheckerBase *checker, AnalysisDeclContext *ac,
                ParentMap &parents,
-               llvm::SmallPtrSet<const VarDecl *, 20> &escaped)
+               llvm::SmallPtrSet<const VarDecl *, 20> &escaped,
+               bool warnForDeadNestedAssignments)
       : cfg(cfg), Ctx(ctx), BR(br), Checker(checker), AC(ac), Parents(parents),
-        Escaped(escaped), currentBlock(nullptr) {}
+        Escaped(escaped), currentBlock(nullptr),
+        WarnForDeadNestedAssignments(warnForDeadNestedAssignments) {}
 
   ~DeadStoreObs() override {}
 
@@ -217,11 +220,16 @@ public:
         os << "Value stored to '" << *V << "' is never read";
         break;
 
+      // eg.: f((x = foo()))
       case Enclosing:
-        // Don't report issues in this case, e.g.: "if (x = foo())",
-        // where 'x' is unused later.  We have yet to see a case where
-        // this is a real bug.
-        return;
+        if (!WarnForDeadNestedAssignments)
+          return;
+        BugType = "Dead nested assignment";
+        os << "Although the value stored to '" << *V
+           << "' is used in the enclosing expression, the value is never "
+              "actually read from '"
+           << *V << "'";
+        break;
     }
 
     BR.EmitBasicReport(AC->getDecl(), Checker, BugType, "Dead store", os.str(),
@@ -474,6 +482,8 @@ public:
 namespace {
 class DeadStoresChecker : public Checker<check::ASTCodeBody> {
 public:
+  bool WarnForDeadNestedAssignments = true;
+
   void checkASTCodeBody(const Decl *D, AnalysisManager& mgr,
                         BugReporter &BR) const {
 
@@ -491,15 +501,20 @@ public:
       ParentMap &pmap = mgr.getParentMap(D);
       FindEscaped FS;
       cfg.VisitBlockStmts(FS);
-      DeadStoreObs A(cfg, BR.getContext(), BR, this, AC, pmap, FS.Escaped);
+      DeadStoreObs A(cfg, BR.getContext(), BR, this, AC, pmap, FS.Escaped,
+                     WarnForDeadNestedAssignments);
       L->runOnAllBlocks(A);
     }
   }
 };
 }
 
-void ento::registerDeadStoresChecker(CheckerManager &mgr) {
-  mgr.registerChecker<DeadStoresChecker>();
+void ento::registerDeadStoresChecker(CheckerManager &Mgr) {
+  auto Chk = Mgr.registerChecker<DeadStoresChecker>();
+
+  const AnalyzerOptions &AnOpts = Mgr.getAnalyzerOptions();
+  Chk->WarnForDeadNestedAssignments =
+      AnOpts.getCheckerBooleanOption(Chk, "WarnForDeadNestedAssignments");
 }
 
 bool ento::shouldRegisterDeadStoresChecker(const LangOptions &LO) {
index 63d22596dddf28bc09955b919645c7d663dba41f..c8a24eea50175827d59226b32ce98844041bd2db 100644 (file)
@@ -30,6 +30,7 @@
 // CHECK-NEXT: ctu-dir = ""
 // CHECK-NEXT: ctu-import-threshold = 100
 // CHECK-NEXT: ctu-index-name = externalDefMap.txt
+// CHECK-NEXT: deadcode.DeadStores:WarnForDeadNestedAssignments = true
 // CHECK-NEXT: debug.AnalysisOrder:* = false
 // CHECK-NEXT: debug.AnalysisOrder:Bind = false
 // CHECK-NEXT: debug.AnalysisOrder:EndFunction = false
@@ -93,4 +94,4 @@
 // CHECK-NEXT: unroll-loops = false
 // CHECK-NEXT: widen-loops = false
 // CHECK-NEXT: [stats]
-// CHECK-NEXT: num-entries = 90
+// CHECK-NEXT: num-entries = 91
index 84217a286a551fc73a89da91c8b9ff7e7bb63f22..26377f7617ee5d08131b49b931241d975015b915 100644 (file)
-// RUN: %clang_analyze_cc1 -Wunused-variable -analyzer-checker=core,deadcode.DeadStores -fblocks -verify -Wno-unreachable-code -analyzer-opt-analyze-nested-blocks %s
-// RUN: %clang_analyze_cc1 -Wunused-variable -analyzer-checker=core,deadcode.DeadStores -analyzer-store=region -fblocks -verify -Wno-unreachable-code -analyzer-opt-analyze-nested-blocks %s
+// RUN: %clang_analyze_cc1 -Wunused-variable -fblocks -Wno-unreachable-code     \
+// RUN:  -analyzer-checker=core,deadcode.DeadStores                             \
+// RUN:  -analyzer-config deadcode.DeadStores:WarnForDeadNestedAssignments=false\
+// RUN:  -analyzer-opt-analyze-nested-blocks -verify=non-nested %s
+//
+// RUN: %clang_analyze_cc1 -Wunused-variable -fblocks -Wno-unreachable-code     \
+// RUN:  -analyzer-checker=core,deadcode.DeadStores                             \
+// RUN:  -analyzer-config deadcode.DeadStores:WarnForDeadNestedAssignments=false\
+// RUN:  -analyzer-opt-analyze-nested-blocks -verify=non-nested                 \
+// RUN:  -analyzer-store=region %s
+//
+// RUN: %clang_analyze_cc1 -Wunused-variable -fblocks -Wno-unreachable-code     \
+// RUN:  -analyzer-checker=core,deadcode.DeadStores                             \
+// RUN:  -analyzer-opt-analyze-nested-blocks -verify=non-nested,nested %s
 
 void f1() {
-  int k, y; // expected-warning{{unused variable 'k'}} expected-warning{{unused variable 'y'}}
-  int abc=1;
-  long idx=abc+3*5; // expected-warning {{never read}} expected-warning{{unused variable 'idx'}}
+  int k, y; // non-nested-warning {{unused variable 'k'}}
+            // non-nested-warning@-1 {{unused variable 'y'}}
+  int abc = 1;
+  long idx = abc + 3 * 5; // non-nested-warning {{never read}}
+                          // non-nested-warning@-1 {{unused variable 'idx'}}
 }
 
 void f2(void *b) {
- char *c = (char*)b; // no-warning
- char *d = b+1; // expected-warning {{never read}} expected-warning{{unused variable 'd'}}
- printf("%s", c); // expected-warning{{implicitly declaring library function 'printf' with type 'int (const char *, ...)'}} \
- // expected-note{{include the header <stdio.h> or explicitly provide a declaration for 'printf'}}
+  char *c = (char *)b; // no-warning
+  char *d = b + 1;     // non-nested-warning {{never read}}
+                       // non-nested-warning@-1 {{unused variable 'd'}}
+  printf("%s", c);
+  // non-nested-warning@-1 {{implicitly declaring library function 'printf' with type 'int (const char *, ...)'}}
+  // non-nested-note@-2 {{include the header <stdio.h> or explicitly provide a declaration for 'printf'}}
 }
 
 int f();
-
 void f3() {
   int r;
   if ((r = f()) != 0) { // no-warning
-    int y = r; // no-warning
+    int y = r;          // no-warning
     printf("the error is: %d\n", y);
   }
 }
 
 void f4(int k) {
-  
   k = 1;
-  
   if (k)
     f1();
-    
-  k = 2;  // expected-warning {{never read}}
+  k = 2; // non-nested-warning {{never read}}
 }
-  
-void f5() {
-
-  int x = 4; // no-warning
-  int *p = &x; // expected-warning{{never read}} expected-warning{{unused variable 'p'}}
 
+void f5() {
+  int x = 4;   // no-warning
+  int *p = &x; // non-nested-warning {{never read}}
+               // non-nested-warning@-1 {{unused variable 'p'}}
 }
 
-//
 int f6() {
-  
   int x = 4;
   ++x; // no-warning
   return 1;
 }
 
-int f7(int *p) {  
+int f7(int *p) {
   // This is allowed for defensive programming.
-  p = 0; // no-warning  
+  p = 0; // no-warning
   return 1;
 }
 
-int f7b(int *p) {  
+int f7b(int *p) {
   // This is allowed for defensive programming.
-  p = (0); // no-warning  
+  p = (0); // no-warning
   return 1;
 }
 
-int f7c(int *p) {  
+int f7c(int *p) {
   // This is allowed for defensive programming.
-  p = (void*) 0; // no-warning  
+  p = (void *)0; // no-warning
   return 1;
 }
 
-int f7d(int *p) {  
+int f7d(int *p) {
   // This is allowed for defensive programming.
-  p = (void*) (0); // no-warning  
+  p = (void *)(0); // no-warning
   return 1;
 }
 
-// Don't warn for dead stores in nested expressions.  We have yet
-// to see a real bug in this scenario.
+// Warn for dead stores in nested expressions.
 int f8(int *p) {
   extern int *baz();
-  if ((p = baz())) // no-warning
+  if ((p = baz())) // nested-warning {{Although the value stored}}
     return 1;
   return 0;
 }
 
 int f9() {
   int x = 4;
-  x = x + 10; // expected-warning{{never read}}
+  x = x + 10; // non-nested-warning {{never read}}
   return 1;
 }
 
 int f10() {
   int x = 4;
-  x = 10 + x; // expected-warning{{never read}}
+  x = 10 + x; // non-nested-warning {{never read}}
   return 1;
 }
 
 int f11() {
   int x = 4;
-  return x++; // expected-warning{{never read}}
+  return x++; // non-nested-warning {{never read}}
 }
 
 int f11b() {
@@ -105,38 +113,38 @@ int f11b() {
 }
 
 int f12a(int y) {
-  int x = y;  // expected-warning{{unused variable 'x'}}
+  int x = y; // non-nested-warning {{unused variable 'x'}}
   return 1;
 }
+
 int f12b(int y) {
-  int x __attribute__((unused)) = y;  // no-warning
+  int x __attribute__((unused)) = y; // no-warning
   return 1;
 }
+
 int f12c(int y) {
   // Allow initialiation of scalar variables by parameters as a form of
   // defensive programming.
-  int x = y;  // no-warning
+  int x = y; // no-warning
   x = 1;
   return x;
 }
 
 // Filed with PR 2630.  This code should produce no warnings.
-int f13(void)
-{
+int f13(void) {
   int a = 1;
   int b, c = b = a + a;
 
   if (b > 0)
     return (0);
-
   return (a + b + c);
 }
 
 // Filed with PR 2763.
 int f14(int count) {
   int index, nextLineIndex;
-  for (index = 0; index < count; index = nextLineIndex+1) {
-    nextLineIndex = index+1;  // no-warning
+  for (index = 0; index < count; index = nextLineIndex + 1) {
+    nextLineIndex = index + 1; // no-warning
     continue;
   }
   return index;
@@ -144,16 +152,15 @@ int f14(int count) {
 
 // Test case for <rdar://problem/6248086>
 void f15(unsigned x, unsigned y) {
-  int count = x * y;   // no-warning
-  int z[count]; // expected-warning{{unused variable 'z'}}
+  int count = x * y; // no-warning
+  int z[count];      // non-nested-warning {{unused variable 'z'}}
 }
 
-// Don't warn for dead stores in nested expressions.  We have yet
-// to see a real bug in this scenario.
+// Warn for dead stores in nested expressions.
 int f16(int x) {
   x = x * 2;
-  x = sizeof(int [x = (x || x + 1) * 2])
-      ? 5 : 8;
+  x = sizeof(int[x = (x || x + 1) * 2]) ? 5 : 8;
+  // nested-warning@-1 {{Although the value stored}}
   return x;
 }
 
@@ -168,39 +175,39 @@ void f17() {
 // what that value is actually used.  In other words, don't say "Although the
 // value stored to 'x' is used...".
 int f18() {
-   int x = 0; // no-warning
-   if (1)
-      x = 10;  // expected-warning{{Value stored to 'x' is never read}}
-   while (1)
-      x = 10;  // expected-warning{{Value stored to 'x' is never read}}
-   // unreachable.
-   do
-      x = 10;   // no-warning
-   while (1);
-   return (x = 10); // no-warning
+  int x = 0; // no-warning
+  if (1)
+    x = 10; // non-nested-warning {{Value stored to 'x' is never read}}
+  while (1)
+    x = 10; // non-nested-warning {{Value stored to 'x' is never read}}
+  // unreachable.
+  do
+    x = 10; // no-warning
+  while (1);
+  return (x = 10); // no-warning
 }
 
 int f18_a() {
-   int x = 0; // no-warning
-   return (x = 10); // no-warning
+  int x = 0;       // no-warning
+  return (x = 10); // nested-warning {{Although the value stored}}
 }
 
 void f18_b() {
-   int x = 0; // no-warning
-   if (1)
-      x = 10;  // expected-warning{{Value stored to 'x' is never read}}
+  int x = 0; // no-warning
+  if (1)
+    x = 10; // non-nested-warning {{Value stored to 'x' is never read}}
 }
 
 void f18_c() {
   int x = 0;
   while (1)
-     x = 10;  // expected-warning{{Value stored to 'x' is never read}}
+    x = 10; // non-nested-warning {{Value stored to 'x' is never read}}
 }
 
 void f18_d() {
   int x = 0; // no-warning
   do
-     x = 10;   // expected-warning{{Value stored to 'x' is never read}}
+    x = 10; // non-nested-warning {{Value stored to 'x' is never read}}
   while (1);
 }
 
@@ -208,7 +215,7 @@ void f18_d() {
 //  http://llvm.org/bugs/show_bug.cgi?id=3514
 extern const int MyConstant;
 int f19(void) {
-  int x = MyConstant;  // no-warning
+  int x = MyConstant; // no-warning
   x = 1;
   return x;
 }
@@ -217,7 +224,7 @@ int f19b(void) { // This case is the same as f19.
   const int MyConstant = 0;
   int x = MyConstant; // no-warning
   x = 1;
-  return x;  
+  return x;
 }
 
 void f20(void) {
@@ -228,8 +235,7 @@ void f20(void) {
 void halt() __attribute__((noreturn));
 int f21() {
   int x = 4;
-  
-  x = x + 1; // expected-warning{{never read}}
+  x = x + 1; // non-nested-warning {{never read}}
   if (1) {
     halt();
     (void)x;
@@ -261,7 +267,7 @@ void f22() {
   int y19 = 4;
   int y20 = 4;
 
-  x = x + 1; // expected-warning{{never read}}
+  x = x + 1; // non-nested-warning {{never read}}
   ++y1;
   ++y2;
   ++y3;
@@ -309,13 +315,13 @@ void f22() {
     } else
       (void)x;
     (void)x;
-  break;
+    break;
   case 4:
-    0 ? : ((void)y4, ({ return; }));
+    0 ?: ((void)y4, ({ return; }));
     (void)x;
     break;
   case 5:
-    1 ? : (void)x;
+    1 ?: (void)x;
     0 ? (void)x : ((void)y5, ({ return; }));
     (void)x;
     break;
@@ -326,11 +332,13 @@ void f22() {
   case 7:
     (void)(0 && x);
     (void)y7;
-    (void)(0 || (y8, ({ return; }), 1));  // expected-warning {{expression result unused}}
+    (void)(0 || (y8, ({ return; }), 1));
+    // non-nested-warning@-1 {{expression result unused}}
     (void)x;
     break;
   case 8:
-    (void)(1 && (y9, ({ return; }), 1));  // expected-warning {{expression result unused}}
+    (void)(1 && (y9, ({ return; }), 1));
+    // non-nested-warning@-1 {{expression result unused}}
     (void)x;
     break;
   case 9:
@@ -365,16 +373,16 @@ void f22() {
     for (;;) {
       (void)y16;
     }
-    (void)x;    
+    (void)x;
     break;
   case 15:
-    for (;1;) {
+    for (; 1;) {
       (void)y17;
     }
     (void)x;
     break;
   case 16:
-    for (;0;) {
+    for (; 0;) {
       (void)x;
     }
     (void)y18;
@@ -390,28 +398,34 @@ void f22() {
   }
 }
 
-void f23_aux(const chars);
+void f23_aux(const char *s);
 void f23(int argc, char **argv) {
   int shouldLog = (argc > 1); // no-warning
-  ^{ 
-     if (shouldLog) f23_aux("I did too use it!\n");
-     else f23_aux("I shouldn't log.  Wait.. d'oh!\n");
+  ^{
+    if (shouldLog)
+      f23_aux("I did too use it!\n");
+    else
+      f23_aux("I shouldn't log.  Wait.. d'oh!\n");
   }();
 }
 
 void f23_pos(int argc, char **argv) {
-  int shouldLog = (argc > 1); // expected-warning{{Value stored to 'shouldLog' during its initialization is never read}} expected-warning{{unused variable 'shouldLog'}}
-  ^{ 
-     f23_aux("I did too use it!\n");
-  }();  
+  int shouldLog = (argc > 1);
+  // non-nested-warning@-1 {{Value stored to 'shouldLog' during its initialization is never read}}
+  // non-nested-warning@-2 {{unused variable 'shouldLog'}}
+  ^{
+    f23_aux("I did too use it!\n");
+  }();
 }
 
 void f24_A(int y) {
   // FIXME: One day this should be reported as dead since 'z = x + y' is dead.
   int x = (y > 2); // no-warning
-  ^ {
-      int z = x + y; // expected-warning{{Value stored to 'z' during its initialization is never read}} expected-warning{{unused variable 'z'}}
-  }();  
+  ^{
+    int z = x + y;
+    // non-nested-warning@-1 {{Value stored to 'z' during its initialization is never read}}
+    // non-nested-warning@-2 {{unused variable 'z'}}
+  }();
 }
 
 void f24_B(int y) {
@@ -426,7 +440,7 @@ void f24_B(int y) {
 int f24_C(int y) {
   // FIXME: One day this should be reported as dead since 'x' is just overwritten.
   __block int x = (y > 2); // no-warning
-  ^{ 
+  ^{
     x = 5; // no-warning
   }();
   return x;
@@ -434,32 +448,35 @@ int f24_C(int y) {
 
 int f24_D(int y) {
   __block int x = (y > 2); // no-warning
-  ^{ 
+  ^{
     if (y > 4)
       x = 5; // no-warning
   }();
   return x;
 }
 
-// This example shows that writing to a variable captured by a block means that it might
-// not be dead.
+// This example shows that writing to a variable captured by a block means that
+// it might not be dead.
 int f25(int y) {
   __block int x = (y > 2);
   __block int z = 0;
-  void (^foo)() = ^{ z = x + y; };
+  void (^foo)() = ^{
+    z = x + y;
+  };
   x = 4; // no-warning
   foo();
-  return z; 
+  return z;
 }
 
-// This test is mostly the same as 'f25', but shows that the heuristic of pruning out dead
-// stores for variables that are just marked '__block' is overly conservative.
+// This test is mostly the same as 'f25', but shows that the heuristic of
+// pruning out dead stores for variables that are just marked '__block' is
+// overly conservative.
 int f25_b(int y) {
   // FIXME: we should eventually report a dead store here.
   __block int x = (y > 2);
   __block int z = 0;
   x = 4; // no-warning
-  return z; 
+  return z;
 }
 
 int f26_nestedblocks() {
@@ -468,10 +485,10 @@ int f26_nestedblocks() {
   __block int y = 0;
   ^{
     int k;
-    k = 1; // expected-warning{{Value stored to 'k' is never read}}
+    k = 1; // non-nested-warning {{Value stored to 'k' is never read}}
     ^{
-        y = z + 1;
-     }();
+      y = z + 1;
+    }();
   }();
   return y;
 }
@@ -480,11 +497,13 @@ int f26_nestedblocks() {
 // placed within the increment code of for loops.
 void rdar8014335() {
   for (int i = 0 ; i != 10 ; ({ break; })) {
-    for ( ; ; ({ ++i; break; })) ; // expected-warning {{'break' is bound to current loop, GCC binds it to the enclosing loop}}
+    for (;; ({ ++i; break; }))
+      ;
+    // non-nested-warning@-2 {{'break' is bound to current loop, GCC binds it to the enclosing loop}}
     // Note that the next value stored to 'i' is never executed
     // because the next statement to be executed is the 'break'
     // in the increment code of the first loop.
-    i = i * 3; // expected-warning{{Value stored to 'i' is never read}}
+    i = i * 3; // non-nested-warning {{Value stored to 'i' is never read}}
   }
 }
 
@@ -517,10 +536,8 @@ void rdar8405222_aux(int i);
 void rdar8405222() {
   const int show = 0;
   int i = 0;
-    
   if (show)
-      i = 5; // no-warning
-
+    i = 5; // no-warning
   if (show)
     rdar8405222_aux(i);
 }
@@ -529,13 +546,13 @@ void rdar8405222() {
 // silencing heuristics.
 int radar11185138_foo() {
   int x, y;
-  x = y = 0; // expected-warning {{never read}}
+  x = y = 0; // non-nested-warning {{never read}}
   return y;
 }
 
 int rdar11185138_bar() {
   int y;
-  int x = y = 0; // no-warning
+  int x = y = 0; // nested-warning {{Although the value stored}}
   x = 2;
   y = 2;
   return x + y;
@@ -550,26 +567,58 @@ int *radar11185138_baz() {
 int getInt();
 int *getPtr();
 void testBOComma() {
-  int x0 = (getInt(), 0); // expected-warning{{unused variable 'x0'}}
-  int x1 = (getInt(), getInt()); // expected-warning {{Value stored to 'x1' during its initialization is never read}} // expected-warning{{unused variable 'x1'}}
-  int x2 = (getInt(), getInt(), getInt()); //expected-warning{{Value stored to 'x2' during its initialization is never read}} // expected-warning{{unused variable 'x2'}}
+  int x0 = (getInt(), 0); // non-nested-warning {{unused variable 'x0'}}
+  int x1 = (getInt(), getInt());
+  // non-nested-warning@-1 {{Value stored to 'x1' during its initialization is never read}}
+  // non-nested-warning@-2 {{unused variable 'x1'}}
+
+  int x2 = (getInt(), getInt(), getInt());
+  // non-nested-warning@-1 {{Value stored to 'x2' during its initialization is never read}}
+  // non-nested-warning@-2 {{unused variable 'x2'}}
+
   int x3;
-  x3 = (getInt(), getInt(), 0); // expected-warning{{Value stored to 'x3' is never read}}
-  int x4 = (getInt(), (getInt(), 0)); // expected-warning{{unused variable 'x4'}}
+  x3 = (getInt(), getInt(), 0);
+  // non-nested-warning@-1 {{Value stored to 'x3' is never read}}
+
+  int x4 = (getInt(), (getInt(), 0));
+  // non-nested-warning@-1 {{unused variable 'x4'}}
+
   int y;
-  int x5 = (getInt(), (y = 0)); // expected-warning{{unused variable 'x5'}}
-  int x6 = (getInt(), (y = getInt())); //expected-warning {{Value stored to 'x6' during its initialization is never read}} // expected-warning{{unused variable 'x6'}}
-  int x7 = 0, x8 = getInt(); //expected-warning {{Value stored to 'x8' during its initialization is never read}} // expected-warning{{unused variable 'x8'}} // expected-warning{{unused variable 'x7'}}
-  int x9 = getInt(), x10 = 0; //expected-warning {{Value stored to 'x9' during its initialization is never read}} // expected-warning{{unused variable 'x9'}}  // expected-warning{{unused variable 'x10'}}
-  int m = getInt(), mm, mmm; //expected-warning {{Value stored to 'm' during its initialization is never read}} // expected-warning{{unused variable 'm'}} // expected-warning{{unused variable 'mm'}} // expected-warning{{unused variable 'mmm'}}
-  int n, nn = getInt(); //expected-warning {{Value stored to 'nn' during its initialization is never read}} // expected-warning{{unused variable 'n'}} // expected-warning{{unused variable 'nn'}}
+  int x5 = (getInt(), (y = 0));
+  // non-nested-warning@-1 {{unused variable 'x5'}}
+  // nested-warning@-2 {{Although the value stored}}
+
+  int x6 = (getInt(), (y = getInt()));
+  // non-nested-warning@-1 {{Value stored to 'x6' during its initialization is never read}}
+  // non-nested-warning@-2 {{unused variable 'x6'}}
+  // nested-warning@-3 {{Although the value stored}}
+
+  int x7 = 0, x8 = getInt();
+  // non-nested-warning@-1 {{Value stored to 'x8' during its initialization is never read}}
+  // non-nested-warning@-2 {{unused variable 'x8'}}
+  // non-nested-warning@-3 {{unused variable 'x7'}}
+
+  int x9 = getInt(), x10 = 0;
+  // non-nested-warning@-1 {{Value stored to 'x9' during its initialization is never read}}
+  // non-nested-warning@-2 {{unused variable 'x9'}}
+  // non-nested-warning@-3 {{unused variable 'x10'}}
+
+  int m = getInt(), mm, mmm;
+  // non-nested-warning@-1 {{Value stored to 'm' during its initialization is never read}}
+  // non-nested-warning@-2 {{unused variable 'm'}}
+  // non-nested-warning@-3 {{unused variable 'mm'}}
+  // non-nested-warning@-4 {{unused variable 'mmm'}}
+
+  int n, nn = getInt();
+  // non-nested-warning@-1 {{Value stored to 'nn' during its initialization is never read}}
+  // non-nested-warning@-2 {{unused variable 'n'}}
+  // non-nested-warning@-3 {{unused variable 'nn'}}
 
   int *p;
   p = (getPtr(), (int *)0); // no warning
-
 }
 
 void testVolatile() {
-    volatile int v;
-    v = 0; // no warning
+  volatile int v;
+  v = 0; // no warning
 }
index d926ccf5ecf69f01f817b345acc56b585a0046cf..94865b36a9084fe4c81e90ede326afc3f186ece4 100644 (file)
@@ -1,15 +1,26 @@
-// RUN: %clang_analyze_cc1 -fcxx-exceptions -fexceptions -fblocks -std=c++11 -analyzer-checker=deadcode.DeadStores -verify -Wno-unreachable-code %s
-// RUN: %clang_analyze_cc1 -fcxx-exceptions -fexceptions -fblocks -std=c++11 -analyzer-store=region -analyzer-checker=deadcode.DeadStores -verify -Wno-unreachable-code %s
+// RUN: %clang_analyze_cc1 -fcxx-exceptions -fexceptions -fblocks -std=c++11    \
+// RUN:  -analyzer-checker=deadcode.DeadStores -Wno-unreachable-code            \
+// RUN:  -analyzer-config deadcode.DeadStores:WarnForDeadNestedAssignments=false\
+// RUN:  -verify=non-nested %s
+//
+// RUN: %clang_analyze_cc1 -fcxx-exceptions -fexceptions -fblocks -std=c++11    \
+// RUN:  -analyzer-store=region -analyzer-checker=deadcode.DeadStores           \
+// RUN:  -analyzer-config deadcode.DeadStores:WarnForDeadNestedAssignments=false\
+// RUN:  -Wno-unreachable-code -verify=non-nested %s
+//
+// RUN: %clang_analyze_cc1 -fcxx-exceptions -fexceptions -fblocks -std=c++11    \
+// RUN:  -analyzer-checker=deadcode.DeadStores -Wno-unreachable-code            \
+// RUN:  -verify=non-nested,nested %s
 
 //===----------------------------------------------------------------------===//
 // Basic dead store checking (but in C++ mode).
 //===----------------------------------------------------------------------===//
 
 int j;
+int make_int();
 void test1() {
   int x = 4;
-
-  x = x + 1; // expected-warning{{never read}}
+  x = x + 1; // non-nested-warning {{never read}}
 
   switch (j) {
   case 1:
@@ -17,6 +28,11 @@ void test1() {
     (void)x;
     break;
   }
+
+  int y;
+  (void)y;
+  if ((y = make_int())) // nested-warning {{Although the value stored}}
+    return;
 }
 
 //===----------------------------------------------------------------------===//
@@ -25,6 +41,7 @@ void test1() {
 
 class Test2 {
   int &x;
+
 public:
   Test2(int &y) : x(y) {}
   ~Test2() { ++x; }
@@ -66,17 +83,17 @@ void test2_b() {
 //===----------------------------------------------------------------------===//
 
 void test3_a(int x) {
-   x = x + 1; // expected-warning{{never read}}
+  x = x + 1; // non-nested-warning {{never read}}
 }
 
 void test3_b(int &x) {
-  x = x + 1; // no-warninge
+  x = x + 1; // no-warning
 }
 
 void test3_c(int x) {
   int &y = x;
-  // Shows the limitation of dead stores tracking.  The write is really
-  // dead since the value cannot escape the function.
+  // Shows the limitation of dead stores tracking. The write is really dead
+  // since the value cannot escape the function.
   ++y; // no-warning
 }
 
@@ -94,7 +111,7 @@ void test3_e(int &x) {
 //===----------------------------------------------------------------------===//
 
 static void test_new(unsigned n) {
-  char **p = new char* [n]; // expected-warning{{never read}}
+  char **p = new char *[n]; // non-nested-warning {{never read}}
 }
 
 //===----------------------------------------------------------------------===//
@@ -102,11 +119,11 @@ static void test_new(unsigned n) {
 //===----------------------------------------------------------------------===//
 
 namespace foo {
-  int test_4(int x) {
-    x = 2; // expected-warning{{Value stored to 'x' is never read}}
-    x = 2;
-    return x;
-  }
+int test_4(int x) {
+  x = 2; // non-nested-warning {{Value stored to 'x' is never read}}
+  x = 2;
+  return x;
+}
 }
 
 //===----------------------------------------------------------------------===//
@@ -119,42 +136,39 @@ int test_5() {
   try {
     x = 2; // no-warning
     test_5_Aux();
-  }
-  catch (int z) {
+  } catch (int z) {
     return x + z;
   }
   return 1;
 }
 
-
 int test_6_aux(unsigned x);
-
 void test_6() {
-  unsigned currDestLen = 0;  // no-warning
+  unsigned currDestLen = 0; // no-warning
   try {
     while (test_6_aux(currDestLen)) {
       currDestLen += 2; // no-warning
-    } 
+    }
+  } catch (void *) {
   }
-  catch (void *) {}
 }
 
 void test_6b() {
-  unsigned currDestLen = 0;  // no-warning
+  unsigned currDestLen = 0; // no-warning
   try {
     while (test_6_aux(currDestLen)) {
-      currDestLen += 2; // expected-warning {{Value stored to 'currDestLen' is never read}}
+      currDestLen += 2;
+      // non-nested-warning@-1 {{Value stored to 'currDestLen' is never read}}
       break;
-    } 
+    }
+  } catch (void *) {
   }
-  catch (void *) {}
 }
 
-
 void testCXX11Using() {
   using Int = int;
   Int value;
-  value = 1; // expected-warning {{never read}}
+  value = 1; // non-nested-warning {{never read}}
 }
 
 //===----------------------------------------------------------------------===//
@@ -177,13 +191,14 @@ int radar_13213575() {
 template <class T>
 void test_block_in_dependent_context(typename T::some_t someArray) {
   ^{
-     int i = someArray[0]; // no-warning
+    int i = someArray[0]; // no-warning
   }();
 }
 
 void test_block_in_non_dependent_context(int *someArray) {
   ^{
-     int i = someArray[0]; // expected-warning {{Value stored to 'i' during its initialization is never read}}
+    int i = someArray[0];
+    // non-nested-warning@-1 {{Value stored to 'i' during its initialization is never read}}
   }();
 }
 
index 9f91f393a116409e6222e84061520aac547fd219..27543ab38139bda4cb303fee37995c3a7a5c8201 100644 (file)
@@ -1,5 +1,4 @@
 // RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.core -analyzer-checker=deadcode.DeadStores,osx.cocoa.RetainCount -fblocks -verify -Wno-objc-root-class %s
-// expected-no-diagnostics
 
 typedef signed char BOOL;
 typedef unsigned int NSUInteger;
@@ -72,7 +71,8 @@ void foo_rdar8527823();
 
 @implementation Rdar7947686_B
 - (id) init {
-  id x = (self = [super init]); // no-warning
+  id x = (self = [super init]);
+  // expected-warning@-1 {{Although the value stored to 'self'}}
   return x;
 }
 @end