Devin Coughlin | b6029b7 | 2015-11-25 22:35:37 +0000 | [diff] [blame] | 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 |
Devin Coughlin | 1d40583 | 2015-11-15 17:48:22 +0000 | [diff] [blame] | 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 | |
Devin Coughlin | 1d40583 | 2015-11-15 17:48:22 +0000 | [diff] [blame] | 15 | @implementation Sub |
| 16 | - (void)callMethodOnSuperInCXXLambda; { |
| 17 | // Explicit capture. |
| 18 | [self]() { |
| 19 | [super superMethod]; |
| 20 | }(); |
| 21 | |
| 22 | // Implicit capture. |
| 23 | [=]() { |
| 24 | [super superMethod]; |
| 25 | }(); |
| 26 | } |
| 27 | |
Devin Coughlin | c289b74 | 2016-02-23 22:26:04 +0000 | [diff] [blame] | 28 | // Make sure to properly handle super-calls when a block captures |
| 29 | // a local variable named 'self'. |
| 30 | - (void)callMethodOnSuperInCXXLambdaWithRedefinedSelf; { |
| 31 | /*__weak*/ Sub *weakSelf = self; |
| 32 | // Implicit capture. (Sema outlaws explicit capture of a redefined self |
| 33 | // and a call to super [which uses the original self]). |
| 34 | [=]() { |
| 35 | Sub *self = weakSelf; |
| 36 | [=]() { |
| 37 | [super superMethod]; |
| 38 | }(); |
| 39 | }(); |
| 40 | } |
| 41 | |
Devin Coughlin | 1d40583 | 2015-11-15 17:48:22 +0000 | [diff] [blame] | 42 | - (void)swapIvars { |
| 43 | int tmp = _ivar1; |
| 44 | _ivar1 = _ivar2; |
| 45 | _ivar2 = tmp; |
| 46 | } |
| 47 | |
| 48 | - (void)callMethodOnSelfInCXXLambda; { |
| 49 | _ivar1 = 7; |
| 50 | _ivar2 = 8; |
| 51 | [self]() { |
| 52 | [self swapIvars]; |
| 53 | }(); |
| 54 | |
| 55 | clang_analyzer_eval(_ivar1 == 8); // expected-warning{{TRUE}} |
| 56 | clang_analyzer_eval(_ivar2 == 7); // expected-warning{{TRUE}} |
| 57 | } |
| 58 | |
| 59 | @end |
Devin Coughlin | b6029b7 | 2015-11-25 22:35:37 +0000 | [diff] [blame] | 60 | |
| 61 | int getValue(); |
| 62 | void useValue(int v); |
| 63 | |
| 64 | void castToBlockNoDeadStore() { |
| 65 | int v = getValue(); // no-warning |
| 66 | |
| 67 | (void)(void(^)())[v]() { // This capture should count as a use, so no dead store warning above. |
| 68 | }; |
| 69 | } |
| 70 | |
| 71 | void takesBlock(void(^block)()); |
| 72 | |
| 73 | void passToFunctionTakingBlockNoDeadStore() { |
| 74 | int v = 7; // no-warning |
| 75 | int x = 8; // no-warning |
| 76 | takesBlock([&v, x]() { |
| 77 | (void)v; |
| 78 | }); |
| 79 | } |
| 80 | |
| 81 | void castToBlockAndInline() { |
| 82 | int result = ((int(^)(int))[](int p) { |
| 83 | return p; |
| 84 | })(7); |
| 85 | |
Devin Coughlin | ebeed88 | 2015-12-04 05:00:36 +0000 | [diff] [blame] | 86 | clang_analyzer_eval(result == 7); // expected-warning{{TRUE}} |
| 87 | } |
| 88 | |
| 89 | void castToBlockWithCaptureAndInline() { |
| 90 | int y = 7; |
| 91 | |
| 92 | auto lambda = [y]{ return y; }; |
| 93 | int(^block)() = lambda; |
| 94 | |
| 95 | int result = block(); |
| 96 | clang_analyzer_eval(result == 7); // expected-warning{{TRUE}} |
| 97 | } |
| 98 | |
| 99 | void castMutableLambdaToBlock() { |
| 100 | int x = 0; |
| 101 | |
| 102 | auto lambda = [x]() mutable { |
| 103 | x = x + 1; |
| 104 | return x; |
| 105 | }; |
| 106 | |
| 107 | // The block should copy the lambda before capturing. |
| 108 | int(^block)() = lambda; |
| 109 | |
| 110 | int r1 = block(); |
| 111 | clang_analyzer_eval(r1 == 1); // expected-warning{{TRUE}} |
| 112 | |
| 113 | int r2 = block(); |
| 114 | clang_analyzer_eval(r2 == 2); // expected-warning{{TRUE}} |
| 115 | |
| 116 | // Because block copied the lambda, r3 should be 1. |
| 117 | int r3 = lambda(); |
| 118 | clang_analyzer_eval(r3 == 1); // expected-warning{{TRUE}} |
| 119 | |
| 120 | // Aliasing the block shouldn't copy the lambda. |
| 121 | int(^blockAlias)() = block; |
| 122 | |
| 123 | int r4 = blockAlias(); |
| 124 | clang_analyzer_eval(r4 == 3); // expected-warning{{TRUE}} |
| 125 | |
| 126 | int r5 = block(); |
| 127 | clang_analyzer_eval(r5 == 4); // expected-warning{{TRUE}} |
| 128 | |
| 129 | // Another copy of lambda |
| 130 | int(^blockSecondCopy)() = lambda; |
| 131 | int r6 = blockSecondCopy(); |
| 132 | clang_analyzer_eval(r6 == 2); // expected-warning{{TRUE}} |
Devin Coughlin | b6029b7 | 2015-11-25 22:35:37 +0000 | [diff] [blame] | 133 | } |
| 134 | |
| 135 | void castLambdaInLocalBlock() { |
Devin Coughlin | dfde655 | 2015-12-03 19:41:24 +0000 | [diff] [blame] | 136 | // Make sure we don't emit a spurious diagnostic about the address of a block |
| 137 | // escaping in the implicit conversion operator method for lambda-to-block |
| 138 | // conversions. |
| 139 | auto lambda = []{ }; // no-warning |
Devin Coughlin | b6029b7 | 2015-11-25 22:35:37 +0000 | [diff] [blame] | 140 | |
| 141 | void(^block)() = lambda; |
| 142 | (void)block; |
| 143 | } |