]> granicus.if.org Git - clang/commitdiff
Objective-C ARC. Blocks that strongly capture themselves
authorFariborz Jahanian <fjahanian@apple.com>
Thu, 12 Jun 2014 20:57:14 +0000 (20:57 +0000)
committerFariborz Jahanian <fjahanian@apple.com>
Thu, 12 Jun 2014 20:57:14 +0000 (20:57 +0000)
to call themselves will get the warning:
"Capturing <itself> strongly in this block is likely to
lead to a retain cycle". Cut down on the amount of noise
by noticing that user at some point sets the captured variable
to null in order to release it (and break the cycle).
// rdar://16944538

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@210823 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Sema/SemaChecking.cpp
test/SemaObjC/warn-retain-cycle.m

index fc87b231d64469342af2d7b89379a12ad2d74135..9f7a8bf7b3876dd4bdfef3af6bf26e0b9e2d33fe 100644 (file)
@@ -7286,10 +7286,12 @@ namespace {
   struct FindCaptureVisitor : EvaluatedExprVisitor<FindCaptureVisitor> {
     FindCaptureVisitor(ASTContext &Context, VarDecl *variable)
       : EvaluatedExprVisitor<FindCaptureVisitor>(Context),
-        Variable(variable), Capturer(nullptr) {}
-
+        Context(Context), Variable(variable), Capturer(nullptr),
+        VarWillBeReased(false) {}
+    ASTContext &Context;
     VarDecl *Variable;
     Expr *Capturer;
+    bool VarWillBeReased;
 
     void VisitDeclRefExpr(DeclRefExpr *ref) {
       if (ref->getDecl() == Variable && !Capturer)
@@ -7314,6 +7316,21 @@ namespace {
       if (OVE->getSourceExpr())
         Visit(OVE->getSourceExpr());
     }
+    void VisitBinaryOperator(BinaryOperator *BinOp) {
+      if (!Variable || VarWillBeReased || BinOp->getOpcode() != BO_Assign)
+        return;
+      Expr *LHS = BinOp->getLHS();
+      if (const DeclRefExpr *DRE = dyn_cast_or_null<DeclRefExpr>(LHS)) {
+        if (DRE->getDecl() != Variable)
+          return;
+        if (Expr *RHS = BinOp->getRHS()) {
+          RHS = RHS->IgnoreParenCasts();
+          llvm::APSInt Value;
+          VarWillBeReased =
+            (RHS && RHS->isIntegerConstantExpr(Value, Context) && Value == 0);
+        }
+      }
+    }
   };
 }
 
@@ -7351,7 +7368,7 @@ static Expr *findCapturingExpr(Sema &S, Expr *e, RetainCycleOwner &owner) {
 
   FindCaptureVisitor visitor(S.Context, owner.Variable);
   visitor.Visit(block->getBlockDecl()->getBody());
-  return visitor.Capturer;
+  return visitor.VarWillBeReased ? nullptr : visitor.Capturer;
 }
 
 static void diagnoseRetainCycle(Sema &S, Expr *capturer,
index eb4e966c772665ba53d74a095035aad50d009f78..4398d29e4a8cbccac2f351ebfc862df6da59e5cd 100644 (file)
@@ -122,8 +122,8 @@ void doSomething(unsigned v);
   // 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) { // expected-warning {{capturing 'self' strongly in this block is likely to lead to a retain cycle}}
-      doSomething(count);
+    if (count > 20) {
+      doSomething(count); // expected-warning {{capturing 'self' strongly in this block is likely to lead to a retain cycle}}
     }
   }];
 }
@@ -184,3 +184,17 @@ void testCopying(Test0 *obj) {
   })];
 }
 
+// rdar://16944538
+void func(int someCondition) {
+
+__block void(^myBlock)(void) = ^{
+        if (someCondition) {
+            doSomething(1);
+            myBlock();
+        }
+        else {
+           myBlock = ((void*)0);
+        }
+   };
+
+}