[cfe-commits] r164039 - in /cfe/trunk: lib/Sema/SemaChecking.cpp test/SemaObjC/warn-retain-cycle.m

Jordan Rose jordan_rose at apple.com
Mon Sep 17 10:54:30 PDT 2012


Author: jrose
Date: Mon Sep 17 12:54:30 2012
New Revision: 164039

URL: http://llvm.org/viewvc/llvm-project?rev=164039&view=rev
Log:
-Warc-retain-cycles: look through [^{...} copy] and Block_copy(^{...})

Retain cycles happen in the case where a block is persisted past its
life on the stack, and the way that occurs is by copying the block.
We should thus look through any explicit copies we see.

Note that Block_copy is actually a type-safe wrapper for _Block_copy,
which does all the real work.

<rdar://problem/12219663>

Modified:
    cfe/trunk/lib/Sema/SemaChecking.cpp
    cfe/trunk/test/SemaObjC/warn-retain-cycle.m

Modified: cfe/trunk/lib/Sema/SemaChecking.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaChecking.cpp?rev=164039&r1=164038&r2=164039&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaChecking.cpp (original)
+++ cfe/trunk/lib/Sema/SemaChecking.cpp Mon Sep 17 12:54:30 2012
@@ -5429,6 +5429,24 @@
   assert(owner.Variable && owner.Loc.isValid());
 
   e = e->IgnoreParenCasts();
+
+  // Look through [^{...} copy] and Block_copy(^{...}).
+  if (ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(e)) {
+    Selector Cmd = ME->getSelector();
+    if (Cmd.isUnarySelector() && Cmd.getNameForSlot(0) == "copy") {
+      e = ME->getInstanceReceiver();
+      if (!e)
+        return 0;
+      e = e->IgnoreParenCasts();
+    }
+  } else if (CallExpr *CE = dyn_cast<CallExpr>(e)) {
+    if (CE->getNumArgs() == 1) {
+      FunctionDecl *Fn = dyn_cast_or_null<FunctionDecl>(CE->getCalleeDecl());
+      if (Fn && Fn->getIdentifier()->isStr("_Block_copy"))
+        e = CE->getArg(0)->IgnoreParenCasts();
+    }
+  }
+  
   BlockExpr *block = dyn_cast<BlockExpr>(e);
   if (!block || !block->getBlockDecl()->capturesVariable(owner.Variable))
     return 0;

Modified: cfe/trunk/test/SemaObjC/warn-retain-cycle.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjC/warn-retain-cycle.m?rev=164039&r1=164038&r2=164039&view=diff
==============================================================================
--- cfe/trunk/test/SemaObjC/warn-retain-cycle.m (original)
+++ cfe/trunk/test/SemaObjC/warn-retain-cycle.m Mon Sep 17 12:54:30 2012
@@ -1,5 +1,7 @@
 // RUN: %clang_cc1 -fsyntax-only -fobjc-runtime-has-weak -fobjc-arc -fblocks -verify -Wno-objc-root-class %s
 
+void *_Block_copy(const void *block);
+
 @interface Test0
 - (void) setBlock: (void(^)(void)) block;
 - (void) addBlock: (void(^)(void)) block;
@@ -153,3 +155,32 @@
   };
 }
 
+
+ at interface NSObject
+- (id)copy;
+
+- (void (^)(void))someRandomMethodReturningABlock;
+ at 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
+  })];
+}
+





More information about the cfe-commits mailing list