[analyzer] Add a checker option to detect nested dead stores

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

llvm-svn: 370767
This commit is contained in:
Kristof Umann 2019-09-03 15:22:43 +00:00
parent de52403843
commit 3b18b050b8
7 changed files with 262 additions and 165 deletions

View 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

View 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

View 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.
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) {

View 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

View File

@ -1,21 +1,36 @@
// 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
@ -25,25 +40,19 @@ void f3() {
}
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'}}
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;
@ -63,40 +72,39 @@ int f7b(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) {
// 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,13 +113,15 @@ 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
return 1;
}
int f12c(int y) {
// Allow initialiation of scalar variables by parameters as a form of
// defensive programming.
@ -121,22 +131,20 @@ int f12c(int y) {
}
// 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;
@ -145,15 +153,14 @@ 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 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;
}
@ -170,9 +177,9 @@ void f17() {
int f18() {
int x = 0; // no-warning
if (1)
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)
x = 10; // expected-warning{{Value stored to 'x' is never read}}
x = 10; // non-nested-warning {{Value stored to 'x' is never read}}
// unreachable.
do
x = 10; // no-warning
@ -182,25 +189,25 @@ int f18() {
int f18_a() {
int x = 0; // no-warning
return (x = 10); // 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}}
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);
}
@ -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;
@ -311,11 +317,11 @@ void f22() {
(void)x;
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:
@ -368,13 +376,13 @@ void f22() {
(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,17 +398,21 @@ 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'}}
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");
}();
@ -409,8 +421,10 @@ void f23_pos(int argc, char **argv) {
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'}}
}();
}
@ -441,19 +455,22 @@ int f24_D(int y) {
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;
}
// 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);
@ -468,7 +485,7 @@ 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;
}();
@ -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
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,23 +567,55 @@ 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() {

View 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}}
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
try {
while (test_6_aux(currDestLen)) {
currDestLen += 2; // no-warning
}
} catch (void *) {
}
catch (void *) {}
}
void test_6b() {
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}}
}
//===----------------------------------------------------------------------===//
@ -183,7 +197,8 @@ void test_block_in_dependent_context(typename T::some_t someArray) {
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}}
}();
}

View 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