| // RUN: %clang_cc1 -fsyntax-only -fobjc-runtime-has-weak -fobjc-arc -fblocks -verify -Wno-objc-root-class -Wno-implicit-retain-self %s | 
 |  | 
 | void *_Block_copy(const void *block); | 
 |  | 
 | @interface Test0 | 
 | - (void) setBlock: (void(^)(void)) block; | 
 | - (void) addBlock: (void(^)(void)) block; | 
 | - (void) actNow; | 
 | @end | 
 | void test0(Test0 *x) { | 
 |   [x setBlock: // expected-note {{block will be retained by the captured object}} | 
 |        ^{ [x actNow]; }]; // expected-warning {{capturing 'x' strongly in this block is likely to lead to a retain cycle}} | 
 |   x.block = // expected-note {{block will be retained by the captured object}} | 
 |        ^{ [x actNow]; }; // expected-warning {{capturing 'x' strongly in this block is likely to lead to a retain cycle}} | 
 |  | 
 |   [x addBlock: // expected-note {{block will be retained by the captured object}} | 
 |        ^{ [x actNow]; }]; // expected-warning {{capturing 'x' strongly in this block is likely to lead to a retain cycle}} | 
 |  | 
 |   // These actually don't cause retain cycles. | 
 |   __weak Test0 *weakx = x; | 
 |   [x addBlock: ^{ [weakx actNow]; }]; | 
 |   [x setBlock: ^{ [weakx actNow]; }]; | 
 |   x.block = ^{ [weakx actNow]; }; | 
 |  | 
 |   // These do cause retain cycles, but we're not clever enough to figure that out. | 
 |   [weakx addBlock: ^{ [x actNow]; }]; | 
 |   [weakx setBlock: ^{ [x actNow]; }]; | 
 |   weakx.block = ^{ [x actNow]; }; | 
 |  | 
 |   // rdar://11702054 | 
 |   x.block = ^{ (void)x.actNow; };  // expected-warning {{capturing 'x' strongly in this block is likely to lead to a retain cycle}} \ | 
 |                                    // expected-note {{block will be retained by the captured object}} | 
 | } | 
 |  | 
 | @interface BlockOwner | 
 | @property (retain) void (^strong)(void); // expected-warning {{retain'ed block property does not copy the block - use copy attribute instead}} | 
 | @end | 
 |  | 
 | @interface Test1 { | 
 | @public | 
 |   BlockOwner *owner; | 
 | }; | 
 | @property (retain) BlockOwner *owner; | 
 | @property (assign) __strong BlockOwner *owner2; // expected-error {{unsafe_unretained property 'owner2' may not also be declared __strong}} | 
 | @property (assign) BlockOwner *owner3; | 
 | @end | 
 | void test1(Test1 *x) { | 
 |   x->owner.strong = ^{ (void) x; }; // expected-warning {{retain cycle}} expected-note {{block will be retained by an object strongly retained by the captured object}} | 
 |   x.owner.strong = ^{ (void) x; }; // expected-warning {{retain cycle}} expected-note {{block will be retained by an object strongly retained by the captured object}} | 
 |   x.owner2.strong = ^{ (void) x; }; | 
 |   x.owner3.strong = ^{ (void) x; }; | 
 | } | 
 |  | 
 | @implementation Test1 { | 
 |   BlockOwner * __unsafe_unretained owner3ivar; | 
 |   __weak BlockOwner *weakowner; | 
 | } | 
 | @dynamic owner; | 
 | @dynamic owner2; | 
 | @synthesize owner3 = owner3ivar; | 
 |  | 
 | - (id) init { | 
 |   self.owner.strong = ^{ (void) owner; }; // expected-warning {{retain cycle}} expected-note {{block will be retained by an object strongly retained by the captured object}} | 
 |   self.owner2.strong = ^{ (void) owner; }; | 
 |  | 
 |   // TODO: should we warn here?  What's the story with this kind of mismatch? | 
 |   self.owner3.strong = ^{ (void) owner; }; | 
 |  | 
 |   owner.strong = ^{ (void) owner; }; // expected-warning {{retain cycle}} expected-note {{block will be retained by an object strongly retained by the captured object}} | 
 |  | 
 |   owner.strong = ^{ ^{ (void) owner; }(); }; // expected-warning {{retain cycle}} expected-note {{block will be retained by an object strongly retained by the captured object}} | 
 |  | 
 |   owner.strong = ^{ (void) sizeof(self); // expected-note {{block will be retained by an object strongly retained by the captured object}} | 
 |                     (void) owner; }; // expected-warning {{capturing 'self' strongly in this block is likely to lead to a retain cycle}} | 
 |  | 
 |   weakowner.strong = ^{ (void) owner; }; | 
 |  | 
 |   return self; | 
 | } | 
 | - (void) foo { | 
 |   owner.strong = ^{ (void) owner; }; // expected-warning {{retain cycle}} expected-note {{block will be retained by an object strongly retained by the captured object}} | 
 | } | 
 | @end | 
 |  | 
 | void test2_helper(id); | 
 | @interface Test2 { | 
 |   void (^block)(void); | 
 |   id x; | 
 | } | 
 | @end | 
 | @implementation Test2 | 
 | - (void) test { | 
 |   block = ^{ // expected-note {{block will be retained by an object strongly retained by the captured object}} | 
 |     test2_helper(x); // expected-warning {{capturing 'self' strongly in this block is likely to lead to a retain cycle}} | 
 |   }; | 
 | } | 
 | @end | 
 |  | 
 |  | 
 | @interface NSOperationQueue {} | 
 | - (void)addOperationWithBlock:(void (^)(void))block; | 
 | - (void)addSomethingElse:(void (^)(void))block; | 
 |  | 
 | @end | 
 |  | 
 | @interface Test3 { | 
 |   NSOperationQueue *myOperationQueue; | 
 |   unsigned count; | 
 | } | 
 | @end | 
 | void doSomething(unsigned v); | 
 | @implementation Test3 | 
 | - (void) test { | 
 |   // 'addOperationWithBlock:' is specifically whitelisted. | 
 |   [myOperationQueue addOperationWithBlock:^() { // no-warning | 
 |     if (count > 20) { | 
 |       doSomething(count); | 
 |     } | 
 |   }]; | 
 | } | 
 | - (void) test_positive { | 
 |   // Sanity check that we are really whitelisting 'addOperationWithBlock:' and not doing | 
 |   // something funny. | 
 |   [myOperationQueue addSomethingElse:^() { // expected-note {{block will be retained by an object strongly retained by the captured object}} | 
 |     if (count > 20) { | 
 |       doSomething(count); // expected-warning {{capturing 'self' strongly in this block is likely to lead to a retain cycle}} | 
 |     } | 
 |   }]; | 
 | } | 
 | @end | 
 |  | 
 |  | 
 | void testBlockVariable() { | 
 |   typedef void (^block_t)(void); | 
 |    | 
 |   // This case will be caught by -Wuninitialized, and does not create a | 
 |   // retain cycle. | 
 |   block_t a1 = ^{ | 
 |     a1(); // no-warning | 
 |   }; | 
 |  | 
 |   // This case will also be caught by -Wuninitialized. | 
 |   block_t a2; | 
 |   a2 = ^{ | 
 |     a2(); // no-warning | 
 |   }; | 
 |    | 
 |   __block block_t b1 = ^{ // expected-note{{block will be retained by the captured object}} | 
 |     b1(); // expected-warning{{capturing 'b1' strongly in this block is likely to lead to a retain cycle}} | 
 |   }; | 
 |  | 
 |   __block block_t b2; | 
 |   b2 = ^{ // expected-note{{block will be retained by the captured object}} | 
 |     b2(); // expected-warning{{capturing 'b2' strongly in this block is likely to lead to a retain cycle}} | 
 |   }; | 
 | } | 
 |  | 
 |  | 
 | @interface NSObject | 
 | - (id)copy; | 
 |  | 
 | - (void (^)(void))someRandomMethodReturningABlock; | 
 | @end | 
 |  | 
 |  | 
 | void testCopying(Test0 *obj) { | 
 |   typedef void (^block_t)(void); | 
 |  | 
 |   [obj setBlock:[^{ // expected-note{{block will be retained by the captured object}} | 
 |     [obj actNow]; // expected-warning{{capturing 'obj' strongly in this block is likely to lead to a retain cycle}} | 
 |   } copy]]; | 
 |  | 
 |   [obj addBlock:(__bridge_transfer block_t)_Block_copy((__bridge void *)^{ // expected-note{{block will be retained by the captured object}} | 
 |     [obj actNow]; // expected-warning{{capturing 'obj' strongly in this block is likely to lead to a retain cycle}} | 
 |   })]; | 
 |    | 
 |   [obj addBlock:[^{ | 
 |     [obj actNow]; // no-warning | 
 |   } someRandomMethodReturningABlock]]; | 
 |    | 
 |   extern block_t someRandomFunctionReturningABlock(block_t); | 
 |   [obj setBlock:someRandomFunctionReturningABlock(^{ | 
 |     [obj actNow]; // no-warning | 
 |   })]; | 
 | } | 
 |  | 
 | // rdar://16944538 | 
 | void func(int someCondition) { | 
 |  | 
 | __block void(^myBlock)(void) = ^{ | 
 |         if (someCondition) { | 
 |             doSomething(1); | 
 |             myBlock(); | 
 |         } | 
 |         else { | 
 | 	    myBlock = ((void*)0); | 
 |         } | 
 |    }; | 
 |  | 
 | } | 
 |  | 
 | typedef void (^a_block_t)(void); | 
 |  | 
 | @interface HonorNoEscape | 
 | - (void)addStuffUsingBlock:(__attribute__((noescape)) a_block_t)block; | 
 | @end | 
 |  | 
 | void testNoEscape(HonorNoEscape *obj) { | 
 |   [obj addStuffUsingBlock:^{ | 
 |     (void)obj; // ok. | 
 |   }]; | 
 | } |