mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2024-12-02 02:38:04 +00:00
[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:
parent
de52403843
commit
3b18b050b8
@ -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
|
||||
|
@ -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
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
|
@ -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 <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'}}
|
||||
|
||||
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 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
|
||||
}
|
||||
|
@ -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}}
|
||||
}();
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user