1 // RUN: %clang_cc1 -std=c++11 -fsyntax-only -fblocks -Wno-objc-root-class -analyze -analyzer-checker=core,deadcode,debug.ExprInspection -analyzer-config inline-lambdas=true -verify %s 2 3 int clang_analyzer_eval(int); 4 5 @interface Super 6 - (void)superMethod; 7 @end 8 9 @interface Sub : Super { 10 int _ivar1; 11 int _ivar2; 12 } 13 @end 14 15 16 @implementation Sub 17 - (void)callMethodOnSuperInCXXLambda; { 18 // Explicit capture. 19 [self]() { 20 [super superMethod]; 21 }(); 22 23 // Implicit capture. 24 [=]() { 25 [super superMethod]; 26 }(); 27 } 28 29 - (void)swapIvars { 30 int tmp = _ivar1; 31 _ivar1 = _ivar2; 32 _ivar2 = tmp; 33 } 34 35 - (void)callMethodOnSelfInCXXLambda; { 36 _ivar1 = 7; 37 _ivar2 = 8; 38 [self]() { 39 [self swapIvars]; 40 }(); 41 42 clang_analyzer_eval(_ivar1 == 8); // expected-warning{{TRUE}} 43 clang_analyzer_eval(_ivar2 == 7); // expected-warning{{TRUE}} 44 } 45 46 @end 47 48 int getValue(); 49 void useValue(int v); 50 51 void castToBlockNoDeadStore() { 52 int v = getValue(); // no-warning 53 54 (void)(void(^)())[v]() { // This capture should count as a use, so no dead store warning above. 55 }; 56 } 57 58 void takesBlock(void(^block)()); 59 60 void passToFunctionTakingBlockNoDeadStore() { 61 int v = 7; // no-warning 62 int x = 8; // no-warning 63 takesBlock([&v, x]() { 64 (void)v; 65 }); 66 } 67 68 void castToBlockAndInline() { 69 int result = ((int(^)(int))[](int p) { 70 return p; 71 })(7); 72 73 clang_analyzer_eval(result == 7); // expected-warning{{TRUE}} 74 } 75 76 void castToBlockWithCaptureAndInline() { 77 int y = 7; 78 79 auto lambda = [y]{ return y; }; 80 int(^block)() = lambda; 81 82 int result = block(); 83 clang_analyzer_eval(result == 7); // expected-warning{{TRUE}} 84 } 85 86 void castMutableLambdaToBlock() { 87 int x = 0; 88 89 auto lambda = [x]() mutable { 90 x = x + 1; 91 return x; 92 }; 93 94 // The block should copy the lambda before capturing. 95 int(^block)() = lambda; 96 97 int r1 = block(); 98 clang_analyzer_eval(r1 == 1); // expected-warning{{TRUE}} 99 100 int r2 = block(); 101 clang_analyzer_eval(r2 == 2); // expected-warning{{TRUE}} 102 103 // Because block copied the lambda, r3 should be 1. 104 int r3 = lambda(); 105 clang_analyzer_eval(r3 == 1); // expected-warning{{TRUE}} 106 107 // Aliasing the block shouldn't copy the lambda. 108 int(^blockAlias)() = block; 109 110 int r4 = blockAlias(); 111 clang_analyzer_eval(r4 == 3); // expected-warning{{TRUE}} 112 113 int r5 = block(); 114 clang_analyzer_eval(r5 == 4); // expected-warning{{TRUE}} 115 116 // Another copy of lambda 117 int(^blockSecondCopy)() = lambda; 118 int r6 = blockSecondCopy(); 119 clang_analyzer_eval(r6 == 2); // expected-warning{{TRUE}} 120 } 121 122 void castLambdaInLocalBlock() { 123 // Make sure we don't emit a spurious diagnostic about the address of a block 124 // escaping in the implicit conversion operator method for lambda-to-block 125 // conversions. 126 auto lambda = []{ }; // no-warning 127 128 void(^block)() = lambda; 129 (void)block; 130 } 131