From 98be881816f1497a682e53df327fba017a1f07e1 Mon Sep 17 00:00:00 2001 From: Fariborz Jahanian Date: Thu, 12 Jun 2014 20:57:14 +0000 Subject: [PATCH] Objective-C ARC. Blocks that strongly capture themselves to call themselves will get the warning: "Capturing 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 | 23 ++++++++++++++++++++--- test/SemaObjC/warn-retain-cycle.m | 18 ++++++++++++++++-- 2 files changed, 36 insertions(+), 5 deletions(-) diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp index fc87b231d6..9f7a8bf7b3 100644 --- a/lib/Sema/SemaChecking.cpp +++ b/lib/Sema/SemaChecking.cpp @@ -7286,10 +7286,12 @@ namespace { struct FindCaptureVisitor : EvaluatedExprVisitor { FindCaptureVisitor(ASTContext &Context, VarDecl *variable) : EvaluatedExprVisitor(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(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, diff --git a/test/SemaObjC/warn-retain-cycle.m b/test/SemaObjC/warn-retain-cycle.m index eb4e966c77..4398d29e4a 100644 --- a/test/SemaObjC/warn-retain-cycle.m +++ b/test/SemaObjC/warn-retain-cycle.m @@ -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); + } + }; + +} -- 2.40.0