211 lines · plain
1// RUN: %clang_cc1 -fsyntax-only -fobjc-runtime-has-weak -fobjc-arc -fblocks -verify -Wno-objc-root-class -Wno-implicit-retain-self %s2 3void *_Block_copy(const void *block);4 5@interface Test06- (void) setBlock: (void(^)(void)) block;7- (void) addBlock: (void(^)(void)) block;8- (void) actNow;9@end10void 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 x.block = ^{ (void)x.actNow; }; // expected-warning {{capturing 'x' strongly in this block is likely to lead to a retain cycle}} \31 // expected-note {{block will be retained by the captured object}}32}33 34@interface BlockOwner35@property (retain) void (^strong)(void); // expected-warning {{retain'ed block property does not copy the block - use copy attribute instead}}36@end37 38@interface Test1 {39@public40 BlockOwner *owner;41};42@property (retain) BlockOwner *owner;43@property (assign) __strong BlockOwner *owner2; // expected-error {{unsafe_unretained property 'owner2' may not also be declared __strong}}44@property (assign) BlockOwner *owner3;45@end46void test1(Test1 *x) {47 x->owner.strong = ^{ (void) x; }; // expected-warning {{retain cycle}} expected-note {{block will be retained by an object strongly retained by the captured object}}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.owner2.strong = ^{ (void) x; };50 x.owner3.strong = ^{ (void) x; };51}52 53@implementation Test1 {54 BlockOwner * __unsafe_unretained owner3ivar;55 __weak BlockOwner *weakowner;56}57@dynamic owner;58@dynamic owner2;59@synthesize owner3 = owner3ivar;60 61- (id) init {62 self.owner.strong = ^{ (void) owner; }; // expected-warning {{retain cycle}} expected-note {{block will be retained by an object strongly retained by the captured object}}63 self.owner2.strong = ^{ (void) owner; };64 65 // TODO: should we warn here? What's the story with this kind of mismatch?66 self.owner3.strong = ^{ (void) owner; };67 68 owner.strong = ^{ (void) owner; }; // expected-warning {{retain cycle}} expected-note {{block will be retained by an object strongly retained by the captured object}}69 70 owner.strong = ^{ ^{ (void) owner; }(); }; // expected-warning {{retain cycle}} expected-note {{block will be retained by an object strongly retained by the captured object}}71 72 owner.strong = ^{ (void) sizeof(self); // expected-note {{block will be retained by an object strongly retained by the captured object}}73 (void) owner; }; // expected-warning {{capturing 'self' strongly in this block is likely to lead to a retain cycle}}74 75 weakowner.strong = ^{ (void) owner; };76 77 return self;78}79- (void) foo {80 owner.strong = ^{ (void) owner; }; // expected-warning {{retain cycle}} expected-note {{block will be retained by an object strongly retained by the captured object}}81}82@end83 84void test2_helper(id);85@interface Test2 {86 void (^block)(void);87 id x;88}89@end90@implementation Test291- (void) test {92 block = ^{ // expected-note {{block will be retained by an object strongly retained by the captured object}}93 test2_helper(x); // expected-warning {{capturing 'self' strongly in this block is likely to lead to a retain cycle}}94 };95}96@end97 98 99@interface NSOperationQueue {}100- (void)addOperationWithBlock:(void (^)(void))block;101- (void)addSomethingElse:(void (^)(void))block;102 103@end104 105@interface Test3 {106 NSOperationQueue *myOperationQueue;107 unsigned count;108}109@end110void doSomething(unsigned v);111@implementation Test3112- (void) test {113 // 'addOperationWithBlock:' is specifically allowlisted.114 [myOperationQueue addOperationWithBlock:^() { // no-warning115 if (count > 20) {116 doSomething(count);117 }118 }];119}120- (void) test_positive {121 // Check that we are really allowlisting 'addOperationWithBlock:' and not doing122 // something funny.123 [myOperationQueue addSomethingElse:^() { // expected-note {{block will be retained by an object strongly retained by the captured object}}124 if (count > 20) {125 doSomething(count); // expected-warning {{capturing 'self' strongly in this block is likely to lead to a retain cycle}}126 }127 }];128}129@end130 131 132void testBlockVariable(void) {133 typedef void (^block_t)(void);134 135 // This case will be caught by -Wuninitialized, and does not create a136 // retain cycle.137 block_t a1 = ^{138 a1(); // no-warning139 };140 141 // This case will also be caught by -Wuninitialized.142 block_t a2;143 a2 = ^{144 a2(); // no-warning145 };146 147 __block block_t b1 = ^{ // expected-note{{block will be retained by the captured object}}148 b1(); // expected-warning{{capturing 'b1' strongly in this block is likely to lead to a retain cycle}}149 };150 151 __block block_t b2;152 b2 = ^{ // expected-note{{block will be retained by the captured object}}153 b2(); // expected-warning{{capturing 'b2' strongly in this block is likely to lead to a retain cycle}}154 };155}156 157 158@interface NSObject159- (id)copy;160 161- (void (^)(void))someRandomMethodReturningABlock;162@end163 164 165void testCopying(Test0 *obj) {166 typedef void (^block_t)(void);167 168 [obj setBlock:[^{ // expected-note{{block will be retained by the captured object}}169 [obj actNow]; // expected-warning{{capturing 'obj' strongly in this block is likely to lead to a retain cycle}}170 } copy]];171 172 [obj addBlock:(__bridge_transfer block_t)_Block_copy((__bridge void *)^{ // expected-note{{block will be retained by the captured object}}173 [obj actNow]; // expected-warning{{capturing 'obj' strongly in this block is likely to lead to a retain cycle}}174 })];175 176 [obj addBlock:[^{177 [obj actNow]; // no-warning178 } someRandomMethodReturningABlock]];179 180 extern block_t someRandomFunctionReturningABlock(block_t);181 [obj setBlock:someRandomFunctionReturningABlock(^{182 [obj actNow]; // no-warning183 })];184}185 186void func(int someCondition) {187 188__block void(^myBlock)(void) = ^{189 if (someCondition) {190 doSomething(1);191 myBlock();192 }193 else {194 myBlock = ((void*)0);195 }196 };197 198}199 200typedef void (^a_block_t)(void);201 202@interface HonorNoEscape203- (void)addStuffUsingBlock:(__attribute__((noescape)) a_block_t)block;204@end205 206void testNoEscape(HonorNoEscape *obj) {207 [obj addStuffUsingBlock:^{208 (void)obj; // ok.209 }];210}211