dead-stores.c revision a676d501a001657892c483bd4d651650e168f337
1// RUN: %clang_cc1 -Wunused-variable -analyze -analyzer-checker=DeadStores,core.experimental.IdempotentOps -analyzer-check-objc-mem -fblocks -verify -Wno-unreachable-code -analyzer-opt-analyze-nested-blocks %s 2// RUN: %clang_cc1 -Wunused-variable -analyze -analyzer-checker=DeadStores,core.experimental.IdempotentOps -analyzer-check-objc-mem -analyzer-store=basic -analyzer-constraints=basic -fblocks -verify -Wno-unreachable-code -analyzer-opt-analyze-nested-blocks %s 3// RUN: %clang_cc1 -Wunused-variable -analyze -analyzer-checker=DeadStores,core.experimental.IdempotentOps -analyzer-check-objc-mem -analyzer-store=basic -analyzer-constraints=range -fblocks -verify -Wno-unreachable-code -analyzer-opt-analyze-nested-blocks %s 4// RUN: %clang_cc1 -Wunused-variable -analyze -analyzer-checker=DeadStores,core.experimental.IdempotentOps -analyzer-check-objc-mem -analyzer-store=region -analyzer-constraints=basic -fblocks -verify -Wno-unreachable-code -analyzer-opt-analyze-nested-blocks %s 5// RUN: %clang_cc1 -Wunused-variable -analyze -analyzer-checker=DeadStores,core.experimental.IdempotentOps -analyzer-check-objc-mem -analyzer-store=region -analyzer-constraints=range -fblocks -verify -Wno-unreachable-code -analyzer-opt-analyze-nested-blocks %s 6 7void f1() { 8 int k, y; // expected-warning{{unused variable 'k'}} expected-warning{{unused variable 'y'}} 9 int abc=1; 10 long idx=abc+3*5; // expected-warning {{never read}} expected-warning{{unused variable 'idx'}} 11} 12 13void f2(void *b) { 14 char *c = (char*)b; // no-warning 15 char *d = b+1; // expected-warning {{never read}} expected-warning{{unused variable 'd'}} 16 printf("%s", c); // expected-warning{{implicitly declaring C library function 'printf' with type 'int (const char *, ...)'}} \ 17 // expected-note{{please include the header <stdio.h> or explicitly provide a declaration for 'printf'}} 18} 19 20int f(); 21 22void f3() { 23 int r; 24 if ((r = f()) != 0) { // no-warning 25 int y = r; // no-warning 26 printf("the error is: %d\n", y); 27 } 28} 29 30void f4(int k) { 31 32 k = 1; 33 34 if (k) 35 f1(); 36 37 k = 2; // expected-warning {{never read}} 38} 39 40void f5() { 41 42 int x = 4; // no-warning 43 int *p = &x; // expected-warning{{never read}} expected-warning{{unused variable 'p'}} 44 45} 46 47// 48int f6() { 49 50 int x = 4; 51 ++x; // no-warning 52 return 1; 53} 54 55int f7(int *p) { 56 // This is allowed for defensive programming. 57 p = 0; // no-warning 58 return 1; 59} 60 61int f7b(int *p) { 62 // This is allowed for defensive programming. 63 p = (0); // no-warning 64 return 1; 65} 66 67int f7c(int *p) { 68 // This is allowed for defensive programming. 69 p = (void*) 0; // no-warning 70 return 1; 71} 72 73int f7d(int *p) { 74 // This is allowed for defensive programming. 75 p = (void*) (0); // no-warning 76 return 1; 77} 78 79// Don't warn for dead stores in nested expressions. We have yet 80// to see a real bug in this scenario. 81int f8(int *p) { 82 extern int *baz(); 83 if ((p = baz())) // no-warning 84 return 1; 85 return 0; 86} 87 88int f9() { 89 int x = 4; 90 x = x + 10; // expected-warning{{never read}} 91 return 1; 92} 93 94int f10() { 95 int x = 4; 96 x = 10 + x; // expected-warning{{never read}} 97 return 1; 98} 99 100int f11() { 101 int x = 4; 102 return x++; // expected-warning{{never read}} 103} 104 105int f11b() { 106 int x = 4; 107 return ((((++x)))); // no-warning 108} 109 110int f12a(int y) { 111 int x = y; // expected-warning{{unused variable 'x'}} 112 return 1; 113} 114int f12b(int y) { 115 int x __attribute__((unused)) = y; // no-warning 116 return 1; 117} 118int f12c(int y) { 119 // Allow initialiation of scalar variables by parameters as a form of 120 // defensive programming. 121 int x = y; // no-warning 122 x = 1; 123 return x; 124} 125 126// Filed with PR 2630. This code should produce no warnings. 127int f13(void) 128{ 129 int a = 1; 130 int b, c = b = a + a; 131 132 if (b > 0) 133 return (0); 134 135 return (a + b + c); 136} 137 138// Filed with PR 2763. 139int f14(int count) { 140 int index, nextLineIndex; 141 for (index = 0; index < count; index = nextLineIndex+1) { 142 nextLineIndex = index+1; // no-warning 143 continue; 144 } 145 return index; 146} 147 148// Test case for <rdar://problem/6248086> 149void f15(unsigned x, unsigned y) { 150 int count = x * y; // no-warning 151 int z[count]; // expected-warning{{unused variable 'z'}} 152} 153 154// Don't warn for dead stores in nested expressions. We have yet 155// to see a real bug in this scenario. 156int f16(int x) { 157 x = x * 2; 158 x = sizeof(int [x = (x || x + 1) * 2]) // expected-warning{{The left operand to '+' is always 0}} expected-warning{{The left operand to '*' is always 1}} 159 ? 5 : 8; 160 return x; 161} 162 163// Self-assignments should not be flagged as dead stores. 164void f17() { 165 int x = 1; 166 x = x; 167} 168 169// <rdar://problem/6506065> 170// The values of dead stores are only "consumed" in an enclosing expression 171// what that value is actually used. In other words, don't say "Although the 172// value stored to 'x' is used...". 173int f18() { 174 int x = 0; // no-warning 175 if (1) 176 x = 10; // expected-warning{{Value stored to 'x' is never read}} 177 while (1) 178 x = 10; // expected-warning{{Value stored to 'x' is never read}} 179 // unreachable. 180 do 181 x = 10; // no-warning 182 while (1); 183 return (x = 10); // no-warning 184} 185 186int f18_a() { 187 int x = 0; // no-warning 188 return (x = 10); // no-warning 189} 190 191void f18_b() { 192 int x = 0; // no-warning 193 if (1) 194 x = 10; // expected-warning{{Value stored to 'x' is never read}} 195} 196 197void f18_c() { 198 int x = 0; 199 while (1) 200 x = 10; // expected-warning{{Value stored to 'x' is never read}} 201} 202 203void f18_d() { 204 int x = 0; // no-warning 205 do 206 x = 10; // expected-warning{{Value stored to 'x' is never read}} 207 while (1); 208} 209 210// PR 3514: false positive `dead initialization` warning for init to global 211// http://llvm.org/bugs/show_bug.cgi?id=3514 212extern const int MyConstant; 213int f19(void) { 214 int x = MyConstant; // no-warning 215 x = 1; 216 return x; 217} 218 219int f19b(void) { // This case is the same as f19. 220 const int MyConstant = 0; 221 int x = MyConstant; // no-warning 222 x = 1; 223 return x; 224} 225 226void f20(void) { 227 int x = 1; // no-warning 228#pragma unused(x) 229} 230 231void halt() __attribute__((noreturn)); 232int f21() { 233 int x = 4; 234 235 x = x + 1; // expected-warning{{never read}} 236 if (1) { 237 halt(); 238 (void)x; 239 } 240 return 1; 241} 242 243int j; 244void f22() { 245 int x = 4; 246 int y1 = 4; 247 int y2 = 4; 248 int y3 = 4; 249 int y4 = 4; 250 int y5 = 4; 251 int y6 = 4; 252 int y7 = 4; 253 int y8 = 4; 254 int y9 = 4; 255 int y10 = 4; 256 int y11 = 4; 257 int y12 = 4; 258 int y13 = 4; 259 int y14 = 4; 260 int y15 = 4; 261 int y16 = 4; 262 int y17 = 4; 263 int y18 = 4; 264 int y19 = 4; 265 int y20 = 4; 266 267 x = x + 1; // expected-warning{{never read}} 268 ++y1; 269 ++y2; 270 ++y3; 271 ++y4; 272 ++y5; 273 ++y6; 274 ++y7; 275 ++y8; 276 ++y9; 277 ++y10; 278 ++y11; 279 ++y12; 280 ++y13; 281 ++y14; 282 ++y15; 283 ++y16; 284 ++y17; 285 ++y18; 286 ++y19; 287 ++y20; 288 289 switch (j) { 290 case 1: 291 if (0) 292 (void)x; 293 if (1) { 294 (void)y1; 295 return; 296 } 297 (void)x; 298 break; 299 case 2: 300 if (0) 301 (void)x; 302 else { 303 (void)y2; 304 return; 305 } 306 (void)x; 307 break; 308 case 3: 309 if (1) { 310 (void)y3; 311 return; 312 } else 313 (void)x; 314 (void)x; 315 break; 316 case 4: 317 0 ? : ((void)y4, ({ return; })); 318 (void)x; 319 break; 320 case 5: 321 1 ? : (void)x; 322 0 ? (void)x : ((void)y5, ({ return; })); 323 (void)x; 324 break; 325 case 6: 326 1 ? ((void)y6, ({ return; })) : (void)x; 327 (void)x; 328 break; 329 case 7: 330 (void)(0 && x); 331 (void)y7; 332 (void)(0 || (y8, ({ return; }), 1)); // expected-warning {{expression result unused}} 333 (void)x; 334 break; 335 case 8: 336 (void)(1 && (y9, ({ return; }), 1)); // expected-warning {{expression result unused}} 337 (void)x; 338 break; 339 case 9: 340 (void)(1 || x); 341 (void)y10; 342 break; 343 case 10: 344 while (0) { 345 (void)x; 346 } 347 (void)y11; 348 break; 349 case 11: 350 while (1) { 351 (void)y12; 352 } 353 (void)x; 354 break; 355 case 12: 356 do { 357 (void)y13; 358 } while (0); 359 (void)y14; 360 break; 361 case 13: 362 do { 363 (void)y15; 364 } while (1); 365 (void)x; 366 break; 367 case 14: 368 for (;;) { 369 (void)y16; 370 } 371 (void)x; 372 break; 373 case 15: 374 for (;1;) { 375 (void)y17; 376 } 377 (void)x; 378 break; 379 case 16: 380 for (;0;) { 381 (void)x; 382 } 383 (void)y18; 384 break; 385 case 17: 386 __builtin_choose_expr(0, (void)x, ((void)y19, ({ return; }))); 387 (void)x; 388 break; 389 case 19: 390 __builtin_choose_expr(1, ((void)y20, ({ return; })), (void)x); 391 (void)x; 392 break; 393 } 394} 395 396void f23_aux(const char* s); 397void f23(int argc, char **argv) { 398 int shouldLog = (argc > 1); // no-warning 399 ^{ 400 if (shouldLog) f23_aux("I did too use it!\n"); 401 else f23_aux("I shouldn't log. Wait.. d'oh!\n"); 402 }(); 403} 404 405void f23_pos(int argc, char **argv) { 406 int shouldLog = (argc > 1); // expected-warning{{Value stored to 'shouldLog' during its initialization is never read}} expected-warning{{unused variable 'shouldLog'}} 407 ^{ 408 f23_aux("I did too use it!\n"); 409 }(); 410} 411 412void f24_A(int y) { 413 // FIXME: One day this should be reported as dead since 'z = x + y' is dead. 414 int x = (y > 2); // no-warning 415 ^ { 416 int z = x + y; // expected-warning{{Value stored to 'z' during its initialization is never read}} expected-warning{{unused variable 'z'}} 417 }(); 418} 419 420void f24_B(int y) { 421 // FIXME: One day this should be reported as dead since 'x' is just overwritten. 422 __block int x = (y > 2); // no-warning 423 ^{ 424 // FIXME: This should eventually be a dead store since it is never read either. 425 x = 5; // no-warning 426 }(); 427} 428 429int f24_C(int y) { 430 // FIXME: One day this should be reported as dead since 'x' is just overwritten. 431 __block int x = (y > 2); // no-warning 432 ^{ 433 x = 5; // no-warning 434 }(); 435 return x; 436} 437 438int f24_D(int y) { 439 __block int x = (y > 2); // no-warning 440 ^{ 441 if (y > 4) 442 x = 5; // no-warning 443 }(); 444 return x; 445} 446 447// This example shows that writing to a variable captured by a block means that it might 448// not be dead. 449int f25(int y) { 450 __block int x = (y > 2); 451 __block int z = 0; 452 void (^foo)() = ^{ z = x + y; }; 453 x = 4; // no-warning 454 foo(); 455 return z; 456} 457 458// This test is mostly the same as 'f25', but shows that the heuristic of pruning out dead 459// stores for variables that are just marked '__block' is overly conservative. 460int f25_b(int y) { 461 // FIXME: we should eventually report a dead store here. 462 __block int x = (y > 2); 463 __block int z = 0; 464 x = 4; // no-warning 465 return z; 466} 467 468int f26_nestedblocks() { 469 int z; 470 z = 1; 471 __block int y = 0; 472 ^{ 473 int k; 474 k = 1; // expected-warning{{Value stored to 'k' is never read}} 475 ^{ 476 y = z + 1; 477 }(); 478 }(); 479 return y; 480} 481 482// The FOREACH macro in QT uses 'break' statements within statement expressions 483// placed within the increment code of for loops. 484void rdar8014335() { 485 for (int i = 0 ; i != 10 ; ({ break; })) { 486 for ( ; ; ({ ++i; break; })) ; 487 // Note that the next value stored to 'i' is never executed 488 // because the next statement to be executed is the 'break' 489 // in the increment code of the first loop. 490 i = i * 3; // expected-warning{{Value stored to 'i' is never read}} expected-warning{{The left operand to '*' is always 1}} 491 } 492} 493 494// <rdar://problem/8320674> NullStmts followed by do...while() can lead to disconnected CFG 495// 496// This previously caused bogus dead-stores warnings because the body of the first do...while was 497// disconnected from the entry of the function. 498typedef struct { float r; float i; } s_rdar8320674; 499typedef struct { s_rdar8320674 x[1]; } s2_rdar8320674; 500 501void rdar8320674(s_rdar8320674 *z, unsigned y, s2_rdar8320674 *st, int m) 502{ 503 s_rdar8320674 * z2; 504 s_rdar8320674 * tw1 = st->x; 505 s_rdar8320674 t; 506 z2 = z + m; 507 do{ 508 ; ; 509 do{ (t).r = (*z2).r*(*tw1).r - (*z2).i*(*tw1).i; (t).i = (*z2).r*(*tw1).i + (*z2).i*(*tw1).r; }while(0); 510 tw1 += y; 511 do { (*z2).r=(*z).r-(t).r; (*z2).i=(*z).i-(t).i; }while(0); 512 do { (*z).r += (t).r; (*z).i += (t).i; }while(0); 513 ++z2; 514 ++z; 515 }while (--m); 516} 517 518// Avoid dead stores resulting from an assignment (and use) being unreachable. 519void rdar8405222_aux(int i); 520void rdar8405222() { 521 const int show = 0; 522 int i = 0; 523 524 if (show) 525 i = 5; // no-warning 526 527 if (show) 528 rdar8405222_aux(i); 529} 530 531