677 lines · c
1// RUN: %check_analyzer_fixit %s %t \2// RUN: -Wunused-variable -fblocks -Wno-unreachable-code \3// RUN: -analyzer-checker=core,deadcode.DeadStores \4// RUN: -analyzer-config deadcode.DeadStores:ShowFixIts=true \5// RUN: -analyzer-config \6// RUN: deadcode.DeadStores:WarnForDeadNestedAssignments=false \7// RUN: -verify=non-nested8 9// RUN: %check_analyzer_fixit %s %t \10// RUN: -Wunused-variable -fblocks -Wno-unreachable-code \11// RUN: -analyzer-checker=core,deadcode.DeadStores \12// RUN: -analyzer-config deadcode.DeadStores:ShowFixIts=true \13// RUN: -verify=non-nested,nested14 15extern int printf(const char *, ...);16 17void f1(void) {18 int k, y; // non-nested-warning {{unused variable 'k'}}19 // non-nested-warning@-1 {{unused variable 'y'}}20 int abc = 1;21 long idx = abc + 3 * 5; // non-nested-warning {{never read}}22 // non-nested-warning@-1 {{unused variable 'idx'}}23 // CHECK-FIXES: int abc = 1;24 // CHECK-FIXES-NEXT: long idx;25}26 27void f2(void *b) {28 char *c = (char *)b; // no-warning29 char *d = b + 1; // non-nested-warning {{never read}}30 // non-nested-warning@-1 {{unused variable 'd'}}31 // CHECK-FIXES: char *c = (char *)b;32 // CHECK-FIXES-NEXT: char *d;33 34 printf("%s", c);35}36 37int f(void);38void f3(void) {39 int r;40 if ((r = f()) != 0) { // no-warning41 int y = r; // no-warning42 printf("the error is: %d\n", y);43 }44}45 46void f4(int k) {47 k = 1;48 if (k)49 f1();50 k = 2; // non-nested-warning {{never read}}51}52 53void f5(void) {54 int x = 4; // no-warning55 int *p = &x; // non-nested-warning {{never read}}56 // non-nested-warning@-1 {{unused variable 'p'}}57 // CHECK-FIXES: int x = 4;58 // CHECK-FIXES-NEXT: int *p;59}60 61int f6(void) {62 int x = 4;63 ++x; // no-warning64 return 1;65}66 67int f7(int *p) {68 // This is allowed for defensive programming.69 p = 0; // no-warning70 return 1;71}72 73int f7b(int *p) {74 // This is allowed for defensive programming.75 p = (0); // no-warning76 return 1;77}78 79int f7c(int *p) {80 // This is allowed for defensive programming.81 p = (void *)0; // no-warning82 return 1;83}84 85int f7d(int *p) {86 // This is allowed for defensive programming.87 p = (void *)(0); // no-warning88 return 1;89}90 91// Warn for dead stores in nested expressions.92int f8(int *p) {93 extern int *baz(void);94 if ((p = baz())) // nested-warning {{Although the value stored}}95 return 1;96 return 0;97}98 99int f9(void) {100 int x = 4;101 x = x + 10; // non-nested-warning {{never read}}102 return 1;103}104 105int f10(void) {106 int x = 4;107 x = 10 + x; // non-nested-warning {{never read}}108 return 1;109}110 111int f11(void) {112 int x = 4;113 return x++; // non-nested-warning {{never read}}114}115 116int f11b(void) {117 int x = 4;118 return ((((++x)))); // no-warning119}120 121int f12a(int y) {122 int x = y; // non-nested-warning {{unused variable 'x'}}123 return 1;124}125 126int f12b(int y) {127 int x __attribute__((unused)) = y; // no-warning128 return 1;129}130 131int f12c(int y) {132 // Allow initialiation of scalar variables by parameters as a form of133 // defensive programming.134 int x = y; // no-warning135 x = 1;136 return x;137}138 139// Filed with PR 2630. This code should produce no warnings.140int f13(void) {141 int a = 1;142 int b, c = b = a + a;143 144 if (b > 0)145 return (0);146 return (a + b + c);147}148 149// Filed with PR 2763.150int f14(int count) {151 int index, nextLineIndex;152 for (index = 0; index < count; index = nextLineIndex + 1) {153 nextLineIndex = index + 1; // no-warning154 continue;155 }156 return index;157}158 159void f15(unsigned x, unsigned y) {160 int count = x * y; // no-warning161 int z[count]; // non-nested-warning {{unused variable 'z'}}162}163 164// Warn for dead stores in nested expressions.165int f16(int x) {166 x = x * 2;167 x = sizeof(int[x = (x || x + 1) * 2]) ? 5 : 8;168 // nested-warning@-1 {{Although the value stored}}169 return x;170}171 172// Self-assignments should not be flagged as dead stores.173void f17(void) {174 int x = 1;175 x = x;176}177 178// The values of dead stores are only "consumed" in an enclosing expression179// what that value is actually used. In other words, don't say "Although the180// value stored to 'x' is used...".181int f18(void) {182 int x = 0; // no-warning183 if (1)184 x = 10; // non-nested-warning {{Value stored to 'x' is never read}}185 while (1)186 x = 10; // non-nested-warning {{Value stored to 'x' is never read}}187 // unreachable.188 do189 x = 10; // no-warning190 while (1);191 return (x = 10); // no-warning192}193 194int f18_a(void) {195 int x = 0; // no-warning196 return (x = 10); // nested-warning {{Although the value stored}}197}198 199void f18_b(void) {200 int x = 0; // no-warning201 if (1)202 x = 10; // non-nested-warning {{Value stored to 'x' is never read}}203}204 205void f18_c(void) {206 int x = 0;207 while (1)208 x = 10; // non-nested-warning {{Value stored to 'x' is never read}}209}210 211void f18_d(void) {212 int x = 0; // no-warning213 do214 x = 10; // non-nested-warning {{Value stored to 'x' is never read}}215 while (1);216}217 218// PR 3514: false positive `dead initialization` warning for init to global219// http://llvm.org/bugs/show_bug.cgi?id=3514220extern const int MyConstant;221int f19(void) {222 int x = MyConstant; // no-warning223 x = 1;224 return x;225}226 227int f19b(void) { // This case is the same as f19.228 const int MyConstant = 0;229 int x = MyConstant; // no-warning230 x = 1;231 return x;232}233 234void f20(void) {235 int x = 1; // no-warning236#pragma unused(x)237}238 239void halt(void) __attribute__((noreturn));240int f21(void) {241 int x = 4;242 x = x + 1; // non-nested-warning {{never read}}243 if (1) {244 halt();245 (void)x;246 }247 return 1;248}249 250int j;251void f22(void) {252 int x = 4;253 int y1 = 4;254 int y2 = 4;255 int y3 = 4;256 int y4 = 4;257 int y5 = 4;258 int y6 = 4;259 int y7 = 4;260 int y8 = 4;261 int y9 = 4;262 int y10 = 4;263 int y11 = 4;264 int y12 = 4;265 int y13 = 4;266 int y14 = 4;267 int y15 = 4;268 int y16 = 4;269 int y17 = 4;270 int y18 = 4;271 int y19 = 4;272 int y20 = 4;273 274 x = x + 1; // non-nested-warning {{never read}}275 ++y1;276 ++y2;277 ++y3;278 ++y4;279 ++y5;280 ++y6;281 ++y7;282 ++y8;283 ++y9;284 ++y10;285 ++y11;286 ++y12;287 ++y13;288 ++y14;289 ++y15;290 ++y16;291 ++y17;292 ++y18;293 ++y19;294 ++y20;295 296 switch (j) {297 case 1:298 if (0)299 (void)x;300 if (1) {301 (void)y1;302 return;303 }304 (void)x;305 break;306 case 2:307 if (0)308 (void)x;309 else {310 (void)y2;311 return;312 }313 (void)x;314 break;315 case 3:316 if (1) {317 (void)y3;318 return;319 } else320 (void)x;321 (void)x;322 break;323 case 4:324 0 ?: ((void)y4, ({ return; }));325 (void)x;326 break;327 case 5:328 1 ?: (void)x;329 0 ? (void)x : ((void)y5, ({ return; }));330 (void)x;331 break;332 case 6:333 1 ? ((void)y6, ({ return; })) : (void)x;334 (void)x;335 break;336 case 7:337 (void)(0 && x);338 (void)y7;339 (void)(0 || (y8, ({ return; }), 1));340 // non-nested-warning@-1 {{left operand of comma operator has no effect}}341 (void)x;342 break;343 case 8:344 (void)(1 && (y9, ({ return; }), 1));345 // non-nested-warning@-1 {{left operand of comma operator has no effect}}346 (void)x;347 break;348 case 9:349 (void)(1 || x);350 (void)y10;351 break;352 case 10:353 while (0) {354 (void)x;355 }356 (void)y11;357 break;358 case 11:359 while (1) {360 (void)y12;361 }362 (void)x;363 break;364 case 12:365 do {366 (void)y13;367 } while (0);368 (void)y14;369 break;370 case 13:371 do {372 (void)y15;373 } while (1);374 (void)x;375 break;376 case 14:377 for (;;) {378 (void)y16;379 }380 (void)x;381 break;382 case 15:383 for (; 1;) {384 (void)y17;385 }386 (void)x;387 break;388 case 16:389 for (; 0;) {390 (void)x;391 }392 (void)y18;393 break;394 case 17:395 __builtin_choose_expr(0, (void)x, ((void)y19, ({ return; })));396 (void)x;397 break;398 case 19:399 __builtin_choose_expr(1, ((void)y20, ({ return; })), (void)x);400 (void)x;401 break;402 }403}404 405void f23_aux(const char *s);406void f23(int argc, char **argv) {407 int shouldLog = (argc > 1); // no-warning408 ^{409 if (shouldLog)410 f23_aux("I did too use it!\n");411 else412 f23_aux("I shouldn't log. Wait.. d'oh!\n");413 }();414}415 416void f23_pos(int argc, char **argv) {417 int shouldLog = (argc > 1);418 // non-nested-warning@-1 {{Value stored to 'shouldLog' during its initialization is never read}}419 // non-nested-warning@-2 {{unused variable 'shouldLog'}}420 // CHECK-FIXES: void f23_pos(int argc, char **argv) {421 // CHECK-FIXES-NEXT: int shouldLog;422 ^{423 f23_aux("I did too use it!\n");424 }();425}426 427void f24_A(int y) {428 // FIXME: One day this should be reported as dead since 'z = x + y' is dead.429 int x = (y > 2); // no-warning430 ^{431 int z = x + y;432 // non-nested-warning@-1 {{Value stored to 'z' during its initialization is never read}}433 // non-nested-warning@-2 {{unused variable 'z'}}434 // CHECK-FIXES: void f24_A(int y) {435 // CHECK-FIXES-NEXT: //436 // CHECK-FIXES-NEXT: int x = (y > 2);437 // CHECK-FIXES-NEXT: ^{438 // CHECK-FIXES-NEXT: int z;439 }();440}441 442void f24_B(int y) {443 // FIXME: One day this should be reported as dead since 'x' is just overwritten.444 __block int x = (y > 2); // no-warning445 ^{446 // FIXME: This should eventually be a dead store since it is never read either.447 x = 5; // no-warning448 }();449}450 451int f24_C(int y) {452 // FIXME: One day this should be reported as dead since 'x' is just overwritten.453 __block int x = (y > 2); // no-warning454 ^{455 x = 5; // no-warning456 }();457 return x;458}459 460int f24_D(int y) {461 __block int x = (y > 2); // no-warning462 ^{463 if (y > 4)464 x = 5; // no-warning465 }();466 return x;467}468 469// This example shows that writing to a variable captured by a block means that470// it might not be dead.471int f25(int y) {472 __block int x = (y > 2);473 __block int z = 0;474 void (^foo)(void) = ^{475 z = x + y;476 };477 x = 4; // no-warning478 foo();479 return z;480}481 482// This test is mostly the same as 'f25', but shows that the heuristic of483// pruning out dead stores for variables that are just marked '__block' is484// overly conservative.485int f25_b(int y) {486 // FIXME: we should eventually report a dead store here.487 __block int x = (y > 2);488 __block int z = 0;489 x = 4; // no-warning490 return z;491}492 493int f26_nestedblocks(void) {494 int z;495 z = 1;496 __block int y = 0;497 ^{498 int k;499 k = 1; // non-nested-warning {{Value stored to 'k' is never read}}500 ^{501 y = z + 1;502 }();503 }();504 return y;505}506 507// The FOREACH macro in QT uses 'break' statements within statement expressions508// placed within the increment code of for loops.509void rdar8014335(void) {510 for (int i = 0 ; i != 10 ; ({ break; })) {511 for (;; ({ ++i; break; }))512 ;513 // non-nested-warning@-2 {{'break' is bound to current loop, GCC binds it to the enclosing loop}}514 // Note that the next value stored to 'i' is never executed515 // because the next statement to be executed is the 'break'516 // in the increment code of the first loop.517 i = i * 3; // non-nested-warning {{Value stored to 'i' is never read}}518 }519}520 521// NullStmts followed by do...while() can lead to disconnected CFG522//523// This previously caused bogus dead-stores warnings because the body of the first do...while was524// disconnected from the entry of the function.525typedef struct { float r; float i; } s_rdar8320674;526typedef struct { s_rdar8320674 x[1]; } s2_rdar8320674;527 528void rdar8320674(s_rdar8320674 *z, unsigned y, s2_rdar8320674 *st, int m)529{530 s_rdar8320674 * z2;531 s_rdar8320674 * tw1 = st->x;532 s_rdar8320674 t;533 z2 = z + m;534 do{535 ; ;536 do{ (t).r = (*z2).r*(*tw1).r - (*z2).i*(*tw1).i; (t).i = (*z2).r*(*tw1).i + (*z2).i*(*tw1).r; }while(0);537 tw1 += y;538 do { (*z2).r=(*z).r-(t).r; (*z2).i=(*z).i-(t).i; }while(0);539 do { (*z).r += (t).r; (*z).i += (t).i; }while(0);540 ++z2;541 ++z;542 }while (--m);543}544 545// Avoid dead stores resulting from an assignment (and use) being unreachable.546void rdar8405222_aux(int i);547void rdar8405222(void) {548 const int show = 0;549 int i = 0;550 if (show)551 i = 5; // no-warning552 if (show)553 rdar8405222_aux(i);554}555 556// Look through chains of assignments, e.g.: int x = y = 0, when employing557// silencing heuristics.558int radar11185138_foo(void) {559 int x, y;560 x = y = 0; // non-nested-warning {{never read}}561 return y;562}563 564int rdar11185138_bar(void) {565 int y;566 int x = y = 0; // nested-warning {{Although the value stored}}567 x = 2;568 y = 2;569 return x + y;570}571 572int *radar11185138_baz(void) {573 int *x, *y;574 x = y = 0; // no-warning575 return y;576}577 578int getInt(void);579int *getPtr(void);580void testBOComma(void) {581 int x0 = (getInt(), 0); // non-nested-warning {{unused variable 'x0'}}582 int x1 = (getInt(), getInt());583 // non-nested-warning@-1 {{Value stored to 'x1' during its initialization is never read}}584 // non-nested-warning@-2 {{unused variable 'x1'}}585 586 int x2 = (getInt(), getInt(), getInt());587 // non-nested-warning@-1 {{Value stored to 'x2' during its initialization is never read}}588 // non-nested-warning@-2 {{unused variable 'x2'}}589 590 int x3;591 x3 = (getInt(), getInt(), 0);592 // non-nested-warning@-1 {{Value stored to 'x3' is never read}}593 594 int x4 = (getInt(), (getInt(), 0));595 // non-nested-warning@-1 {{unused variable 'x4'}}596 597 int y;598 int x5 = (getInt(), (y = 0));599 // non-nested-warning@-1 {{unused variable 'x5'}}600 // nested-warning@-2 {{Although the value stored}}601 602 int x6 = (getInt(), (y = getInt()));603 // non-nested-warning@-1 {{Value stored to 'x6' during its initialization is never read}}604 // non-nested-warning@-2 {{unused variable 'x6'}}605 // nested-warning@-3 {{Although the value stored}}606 607 int x7 = 0, x8 = getInt();608 // non-nested-warning@-1 {{Value stored to 'x8' during its initialization is never read}}609 // non-nested-warning@-2 {{unused variable 'x8'}}610 // non-nested-warning@-3 {{unused variable 'x7'}}611 612 int x9 = getInt(), x10 = 0;613 // non-nested-warning@-1 {{Value stored to 'x9' during its initialization is never read}}614 // non-nested-warning@-2 {{unused variable 'x9'}}615 // non-nested-warning@-3 {{unused variable 'x10'}}616 617 int m = getInt(), mm, mmm;618 // non-nested-warning@-1 {{Value stored to 'm' during its initialization is never read}}619 // non-nested-warning@-2 {{unused variable 'm'}}620 // non-nested-warning@-3 {{unused variable 'mm'}}621 // non-nested-warning@-4 {{unused variable 'mmm'}}622 623 int n, nn = getInt();624 // non-nested-warning@-1 {{Value stored to 'nn' during its initialization is never read}}625 // non-nested-warning@-2 {{unused variable 'n'}}626 // non-nested-warning@-3 {{unused variable 'nn'}}627 628 int *p;629 p = (getPtr(), (int *)0); // no warning630}631 632void testVolatile(void) {633 volatile int v;634 v = 0; // no warning635}636 637struct Foo {638 int x;639 int y;640};641 642struct Foo rdar34122265_getFoo(void);643 644int rdar34122265_test(int input) {645 // This is allowed for defensive programming.646 struct Foo foo = {0, 0};647 if (input > 0) {648 foo = rdar34122265_getFoo();649 } else {650 return 0;651 }652 return foo.x + foo.y;653}654 655void rdar34122265_test_cast(void) {656 // This is allowed for defensive programming.657 struct Foo foo = {0, 0};658 (void)foo;659}660 661struct Bar {662 struct Foo x, y;663};664 665struct Bar rdar34122265_getBar(void);666 667int rdar34122265_test_nested(int input) {668 // This is allowed for defensive programming.669 struct Bar bar = {{0, 0}, {0, 0}};670 if (input > 0) {671 bar = rdar34122265_getBar();672 } else {673 return 0;674 }675 return bar.x.x + bar.y.y;676}677