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