From cfb041434e33a16d7ba0ba4576194a7d42b2f3f8 Mon Sep 17 00:00:00 2001 From: Kristof Umann Date: Tue, 3 Sep 2019 15:22:43 +0000 Subject: [PATCH] [analyzer] Add a checker option to detect nested dead stores MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit 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 | 9 + .../clang/StaticAnalyzer/Checkers/Checkers.td | 8 + .../Checkers/DeadStoresChecker.cpp | 33 +- test/Analysis/analyzer-config.c | 3 +- test/Analysis/dead-stores.c | 297 ++++++++++-------- test/Analysis/dead-stores.cpp | 73 +++-- test/Analysis/dead-stores.m | 4 +- 7 files changed, 262 insertions(+), 165 deletions(-) diff --git a/docs/analyzer/checkers.rst b/docs/analyzer/checkers.rst index f50fff918c..a751b14809 100644 --- a/docs/analyzer/checkers.rst +++ b/docs/analyzer/checkers.rst @@ -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 diff --git a/include/clang/StaticAnalyzer/Checkers/Checkers.td b/include/clang/StaticAnalyzer/Checkers/Checkers.td index da59b3af3c..0626d29c3d 100644 --- a/include/clang/StaticAnalyzer/Checkers/Checkers.td +++ b/include/clang/StaticAnalyzer/Checkers/Checkers.td @@ -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 + ]>, Documentation; } // end DeadCode diff --git a/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp b/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp index d5baa2bcba..e4889c1cc1 100644 --- a/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp @@ -130,6 +130,7 @@ class DeadStoreObs : public LiveVariables::Observer { std::unique_ptr reachableCode; const CFGBlock *currentBlock; std::unique_ptr> 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 &escaped) + llvm::SmallPtrSet &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 { 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(); +void ento::registerDeadStoresChecker(CheckerManager &Mgr) { + auto Chk = Mgr.registerChecker(); + + const AnalyzerOptions &AnOpts = Mgr.getAnalyzerOptions(); + Chk->WarnForDeadNestedAssignments = + AnOpts.getCheckerBooleanOption(Chk, "WarnForDeadNestedAssignments"); } bool ento::shouldRegisterDeadStoresChecker(const LangOptions &LO) { diff --git a/test/Analysis/analyzer-config.c b/test/Analysis/analyzer-config.c index 63d22596dd..c8a24eea50 100644 --- a/test/Analysis/analyzer-config.c +++ b/test/Analysis/analyzer-config.c @@ -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 diff --git a/test/Analysis/dead-stores.c b/test/Analysis/dead-stores.c index 84217a286a..26377f7617 100644 --- a/test/Analysis/dead-stores.c +++ b/test/Analysis/dead-stores.c @@ -1,102 +1,110 @@ -// 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 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 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 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 char* s); +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 } diff --git a/test/Analysis/dead-stores.cpp b/test/Analysis/dead-stores.cpp index d926ccf5ec..94865b36a9 100644 --- a/test/Analysis/dead-stores.cpp +++ b/test/Analysis/dead-stores.cpp @@ -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 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}} }(); } diff --git a/test/Analysis/dead-stores.m b/test/Analysis/dead-stores.m index 9f91f393a1..27543ab381 100644 --- a/test/Analysis/dead-stores.m +++ b/test/Analysis/dead-stores.m @@ -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 -- 2.40.0