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