1 // RUN: %clang_cc1 -fsyntax-only -fobjc-runtime-has-weak -fobjc-arc -fblocks -verify -Wno-objc-root-class -Wno-implicit-retain-self %s 2 3 void *_Block_copy(const void *block); 4 5 @interface Test0 6 - (void) setBlock: (void(^)(void)) block; 7 - (void) addBlock: (void(^)(void)) block; 8 - (void) actNow; 9 @end 10 void test0(Test0 *x) { 11 [x setBlock: // expected-note {{block will be retained by the captured object}} 12 ^{ [x actNow]; }]; // expected-warning {{capturing 'x' strongly in this block is likely to lead to a retain cycle}} 13 x.block = // expected-note {{block will be retained by the captured object}} 14 ^{ [x actNow]; }; // expected-warning {{capturing 'x' strongly in this block is likely to lead to a retain cycle}} 15 16 [x addBlock: // expected-note {{block will be retained by the captured object}} 17 ^{ [x actNow]; }]; // expected-warning {{capturing 'x' strongly in this block is likely to lead to a retain cycle}} 18 19 // These actually don't cause retain cycles. 20 __weak Test0 *weakx = x; 21 [x addBlock: ^{ [weakx actNow]; }]; 22 [x setBlock: ^{ [weakx actNow]; }]; 23 x.block = ^{ [weakx actNow]; }; 24 25 // These do cause retain cycles, but we're not clever enough to figure that out. 26 [weakx addBlock: ^{ [x actNow]; }]; 27 [weakx setBlock: ^{ [x actNow]; }]; 28 weakx.block = ^{ [x actNow]; }; 29 30 // rdar://11702054 31 x.block = ^{ (void)x.actNow; }; // expected-warning {{capturing 'x' strongly in this block is likely to lead to a retain cycle}} \ 32 // expected-note {{block will be retained by the captured object}} 33 } 34 35 @interface BlockOwner 36 @property (retain) void (^strong)(void); // expected-warning {{retain'ed block property does not copy the block - use copy attribute instead}} 37 @end 38 39 @interface Test1 { 40 @public 41 BlockOwner *owner; 42 }; 43 @property (retain) BlockOwner *owner; 44 @property (assign) __strong BlockOwner *owner2; // expected-error {{unsafe_unretained property 'owner2' may not also be declared __strong}} 45 @property (assign) BlockOwner *owner3; 46 @end 47 void test1(Test1 *x) { 48 x->owner.strong = ^{ (void) x; }; // expected-warning {{retain cycle}} expected-note {{block will be retained by an object strongly retained by the captured object}} 49 x.owner.strong = ^{ (void) x; }; // expected-warning {{retain cycle}} expected-note {{block will be retained by an object strongly retained by the captured object}} 50 x.owner2.strong = ^{ (void) x; }; 51 x.owner3.strong = ^{ (void) x; }; 52 } 53 54 @implementation Test1 { 55 BlockOwner * __unsafe_unretained owner3ivar; 56 __weak BlockOwner *weakowner; 57 } 58 @dynamic owner; 59 @dynamic owner2; 60 @synthesize owner3 = owner3ivar; 61 62 - (id) init { 63 self.owner.strong = ^{ (void) owner; }; // expected-warning {{retain cycle}} expected-note {{block will be retained by an object strongly retained by the captured object}} 64 self.owner2.strong = ^{ (void) owner; }; 65 66 // TODO: should we warn here? What's the story with this kind of mismatch? 67 self.owner3.strong = ^{ (void) owner; }; 68 69 owner.strong = ^{ (void) owner; }; // expected-warning {{retain cycle}} expected-note {{block will be retained by an object strongly retained by the captured object}} 70 71 owner.strong = ^{ ^{ (void) owner; }(); }; // expected-warning {{retain cycle}} expected-note {{block will be retained by an object strongly retained by the captured object}} 72 73 owner.strong = ^{ (void) sizeof(self); // expected-note {{block will be retained by an object strongly retained by the captured object}} 74 (void) owner; }; // expected-warning {{capturing 'self' strongly in this block is likely to lead to a retain cycle}} 75 76 weakowner.strong = ^{ (void) owner; }; 77 78 return self; 79 } 80 - (void) foo { 81 owner.strong = ^{ (void) owner; }; // expected-warning {{retain cycle}} expected-note {{block will be retained by an object strongly retained by the captured object}} 82 } 83 @end 84 85 void test2_helper(id); 86 @interface Test2 { 87 void (^block)(void); 88 id x; 89 } 90 @end 91 @implementation Test2 92 - (void) test { 93 block = ^{ // expected-note {{block will be retained by an object strongly retained by the captured object}} 94 test2_helper(x); // expected-warning {{capturing 'self' strongly in this block is likely to lead to a retain cycle}} 95 }; 96 } 97 @end 98 99 100 @interface NSOperationQueue {} 101 - (void)addOperationWithBlock:(void (^)(void))block; 102 - (void)addSomethingElse:(void (^)(void))block; 103 104 @end 105 106 @interface Test3 { 107 NSOperationQueue *myOperationQueue; 108 unsigned count; 109 } 110 @end 111 void doSomething(unsigned v); 112 @implementation Test3 113 - (void) test { 114 // 'addOperationWithBlock:' is specifically whitelisted. 115 [myOperationQueue addOperationWithBlock:^() { // no-warning 116 if (count > 20) { 117 doSomething(count); 118 } 119 }]; 120 } 121 - (void) test_positive { 122 // Sanity check that we are really whitelisting 'addOperationWithBlock:' and not doing 123 // something funny. 124 [myOperationQueue addSomethingElse:^() { // expected-note {{block will be retained by an object strongly retained by the captured object}} 125 if (count > 20) { 126 doSomething(count); // expected-warning {{capturing 'self' strongly in this block is likely to lead to a retain cycle}} 127 } 128 }]; 129 } 130 @end 131 132 133 void testBlockVariable() { 134 typedef void (^block_t)(void); 135 136 // This case will be caught by -Wuninitialized, and does not create a 137 // retain cycle. 138 block_t a1 = ^{ 139 a1(); // no-warning 140 }; 141 142 // This case will also be caught by -Wuninitialized. 143 block_t a2; 144 a2 = ^{ 145 a2(); // no-warning 146 }; 147 148 __block block_t b1 = ^{ // expected-note{{block will be retained by the captured object}} 149 b1(); // expected-warning{{capturing 'b1' strongly in this block is likely to lead to a retain cycle}} 150 }; 151 152 __block block_t b2; 153 b2 = ^{ // expected-note{{block will be retained by the captured object}} 154 b2(); // expected-warning{{capturing 'b2' strongly in this block is likely to lead to a retain cycle}} 155 }; 156 } 157 158 159 @interface NSObject 160 - (id)copy; 161 162 - (void (^)(void))someRandomMethodReturningABlock; 163 @end 164 165 166 void testCopying(Test0 *obj) { 167 typedef void (^block_t)(void); 168 169 [obj setBlock:[^{ // expected-note{{block will be retained by the captured object}} 170 [obj actNow]; // expected-warning{{capturing 'obj' strongly in this block is likely to lead to a retain cycle}} 171 } copy]]; 172 173 [obj addBlock:(__bridge_transfer block_t)_Block_copy((__bridge void *)^{ // expected-note{{block will be retained by the captured object}} 174 [obj actNow]; // expected-warning{{capturing 'obj' strongly in this block is likely to lead to a retain cycle}} 175 })]; 176 177 [obj addBlock:[^{ 178 [obj actNow]; // no-warning 179 } someRandomMethodReturningABlock]]; 180 181 extern block_t someRandomFunctionReturningABlock(block_t); 182 [obj setBlock:someRandomFunctionReturningABlock(^{ 183 [obj actNow]; // no-warning 184 })]; 185 } 186 187 // rdar://16944538 188 void func(int someCondition) { 189 190 __block void(^myBlock)(void) = ^{ 191 if (someCondition) { 192 doSomething(1); 193 myBlock(); 194 } 195 else { 196 myBlock = ((void*)0); 197 } 198 }; 199 200 } 201