1 // RUN: %clang_cc1 -fsyntax-only -fobjc-runtime-has-weak -fobjc-arc -fblocks -verify -Wno-objc-root-class -Wno-implicit-retain-self %s
3 void *_Block_copy(const void *block);
6 - (void) setBlock: (void(^)(void)) block;
7 - (void) addBlock: (void(^)(void)) block;
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}}
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}}
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]; };
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]; };
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}}
35 @property (retain) void (^strong)(void); // expected-warning {{retain'ed block property does not copy the block - use copy attribute instead}}
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;
46 void 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; };
53 @implementation Test1 {
54 BlockOwner * __unsafe_unretained owner3ivar;
55 __weak BlockOwner *weakowner;
59 @synthesize owner3 = owner3ivar;
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; };
65 // TODO: should we warn here? What's the story with this kind of mismatch?
66 self.owner3.strong = ^{ (void) owner; };
68 owner.strong = ^{ (void) owner; }; // expected-warning {{retain cycle}} expected-note {{block will be retained by an object strongly retained by the captured object}}
70 owner.strong = ^{ ^{ (void) owner; }(); }; // expected-warning {{retain cycle}} expected-note {{block will be retained by an object strongly retained by the captured object}}
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}}
75 weakowner.strong = ^{ (void) owner; };
80 owner.strong = ^{ (void) owner; }; // expected-warning {{retain cycle}} expected-note {{block will be retained by an object strongly retained by the captured object}}
84 void test2_helper(id);
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}}
99 @interface NSOperationQueue {}
100 - (void)addOperationWithBlock:(void (^)(void))block;
101 - (void)addSomethingElse:(void (^)(void))block;
106 NSOperationQueue *myOperationQueue;
110 void doSomething(unsigned v);
111 @implementation Test3
113 // 'addOperationWithBlock:' is specifically allowlisted.
114 [myOperationQueue addOperationWithBlock:^() { // no-warning
120 - (void) test_positive {
121 // Check that we are really allowlisting 'addOperationWithBlock:' and not doing
123 [myOperationQueue addSomethingElse:^() { // expected-note {{block will be retained by an object strongly retained by the captured object}}
125 doSomething(count); // expected-warning {{capturing 'self' strongly in this block is likely to lead to a retain cycle}}
132 void testBlockVariable(void) {
133 typedef void (^block_t)(void);
135 // This case will be caught by -Wuninitialized, and does not create a
141 // This case will also be caught by -Wuninitialized.
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}}
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}}
161 - (void (^)(void))someRandomMethodReturningABlock;
165 void testCopying(Test0 *obj) {
166 typedef void (^block_t)(void);
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}}
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}}
177 [obj actNow]; // no-warning
178 } someRandomMethodReturningABlock]];
180 extern block_t someRandomFunctionReturningABlock(block_t);
181 [obj setBlock:someRandomFunctionReturningABlock(^{
182 [obj actNow]; // no-warning
186 void func(int someCondition) {
188 __block void(^myBlock)(void) = ^{
194 myBlock = ((void*)0);
200 typedef void (^a_block_t)(void);
202 @interface HonorNoEscape
203 - (void)addStuffUsingBlock:(__attribute__((noescape)) a_block_t)block;
206 void testNoEscape(HonorNoEscape *obj) {
207 [obj addStuffUsingBlock:^{