1// RUN: %clang_cc1 -fsyntax-only -fobjc-runtime-has-weak -fobjc-arc -fblocks -verify -Wno-objc-root-class -Wno-implicit-retain-self %s 2 3void *_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 10void 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 47void 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 85void 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 111void 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 133void 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 166void 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 188void 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