Index: cfe/trunk/docs/analyzer/checkers.rst =================================================================== --- cfe/trunk/docs/analyzer/checkers.rst +++ cfe/trunk/docs/analyzer/checkers.rst @@ -319,6 +319,15 @@ 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: cfe/trunk/include/clang/StaticAnalyzer/Checkers/Checkers.td =================================================================== --- cfe/trunk/include/clang/StaticAnalyzer/Checkers/Checkers.td +++ cfe/trunk/include/clang/StaticAnalyzer/Checkers/Checkers.td @@ -648,6 +648,14 @@ def DeadStoresChecker : Checker<"DeadStores">, HelpText<"Check for values stored to variables that are never read " "afterwards">, + CheckerOptions<[ + CmdLineOption + ]>, Documentation; } // end DeadCode Index: cfe/trunk/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp =================================================================== --- cfe/trunk/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp +++ cfe/trunk/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp @@ -130,6 +130,7 @@ std::unique_ptr reachableCode; const CFGBlock *currentBlock; std::unique_ptr> InEH; + const bool WarnForDeadNestedAssignments; enum DeadStoreKind { Standard, Enclosing, DeadIncrement, DeadInit }; @@ -137,9 +138,11 @@ 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 @@ 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 @@ namespace { class DeadStoresChecker : public Checker { public: + bool WarnForDeadNestedAssignments = true; + void checkASTCodeBody(const Decl *D, AnalysisManager& mgr, BugReporter &BR) const { @@ -491,15 +501,20 @@ 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) { Index: cfe/trunk/test/Analysis/analyzer-config.c =================================================================== --- cfe/trunk/test/Analysis/analyzer-config.c +++ cfe/trunk/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 Index: cfe/trunk/test/Analysis/dead-stores.c =================================================================== --- cfe/trunk/test/Analysis/dead-stores.c +++ cfe/trunk/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 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 @@ // 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 @@ // 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 @@ // 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 @@ const int MyConstant = 0; int x = MyConstant; // no-warning x = 1; - return x; + return x; } void f20(void) { @@ -228,8 +235,7 @@ 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 @@ 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 @@ } 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 @@ 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 @@ 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 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 @@ 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_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 @@ __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 @@ // 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() { 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 @@ // 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 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: cfe/trunk/test/Analysis/dead-stores.cpp =================================================================== --- cfe/trunk/test/Analysis/dead-stores.cpp +++ cfe/trunk/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)x; break; } + + int y; + (void)y; + if ((y = make_int())) // nested-warning {{Although the value stored}} + return; } //===----------------------------------------------------------------------===// @@ -25,6 +41,7 @@ class Test2 { int &x; + public: Test2(int &y) : x(y) {} ~Test2() { ++x; } @@ -66,17 +83,17 @@ //===----------------------------------------------------------------------===// 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 @@ //===----------------------------------------------------------------------===// 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 @@ //===----------------------------------------------------------------------===// 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 @@ 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 @@ 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}} }(); } Index: cfe/trunk/test/Analysis/dead-stores.m =================================================================== --- cfe/trunk/test/Analysis/dead-stores.m +++ cfe/trunk/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 @@ @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