diff options
author | Jordan Rose <jordan_rose@apple.com> | 2012-09-15 02:48:31 +0000 |
---|---|---|
committer | Jordan Rose <jordan_rose@apple.com> | 2012-09-15 02:48:31 +0000 |
commit | e10f4d384f5ae113d72a5193a1332c1930635ccc (patch) | |
tree | a547f7a40de30e936ef4976b96ad16b56831c7ab /lib/Sema | |
parent | 98e95bf1c84560684356088af7f4878bdacb5856 (diff) |
-Warc-retain-cycles: warn at variable initialization as well as assignment.
Specifically, this should warn:
__block block_t a = ^{ a(); };
Furthermore, this case which previously warned now does not, since the value
of 'b' is captured before the assignment occurs:
block_t b; // not __block
b = ^{ b(); };
(This will of course warn under -Wuninitialized, as before.)
<rdar://problem/11015883>
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@163962 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Sema')
-rw-r--r-- | lib/Sema/SemaChecking.cpp | 17 | ||||
-rw-r--r-- | lib/Sema/SemaDecl.cpp | 6 | ||||
-rw-r--r-- | lib/Sema/SemaExpr.cpp | 14 |
3 files changed, 32 insertions, 5 deletions
diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp index b46081dc99..0e6b5ec9a3 100644 --- a/lib/Sema/SemaChecking.cpp +++ b/lib/Sema/SemaChecking.cpp @@ -5299,7 +5299,8 @@ static bool considerVariable(VarDecl *var, Expr *ref, RetainCycleOwner &owner) { return false; owner.Variable = var; - owner.setLocsFrom(ref); + if (ref) + owner.setLocsFrom(ref); return true; } @@ -5499,6 +5500,20 @@ void Sema::checkRetainCycles(Expr *receiver, Expr *argument) { diagnoseRetainCycle(*this, capturer, owner); } +void Sema::checkRetainCycles(VarDecl *Var, Expr *Init) { + RetainCycleOwner Owner; + if (!considerVariable(Var, /*DeclRefExpr=*/0, Owner)) + return; + + // Because we don't have an expression for the variable, we have to set the + // location explicitly here. + Owner.Loc = Var->getLocation(); + Owner.Range = Var->getSourceRange(); + + if (Expr *Capturer = findCapturingExpr(*this, Init, Owner)) + diagnoseRetainCycle(*this, Capturer, Owner); +} + bool Sema::checkUnsafeAssigns(SourceLocation Loc, QualType LHS, Expr *RHS) { Qualifiers::ObjCLifetime LT = LHS.getObjCLifetime(); diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 134b965a33..edcfcb68e1 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -6582,9 +6582,13 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, // Check any implicit conversions within the expression. CheckImplicitConversions(Init, VDecl->getLocation()); - if (!VDecl->isInvalidDecl()) + if (!VDecl->isInvalidDecl()) { checkUnsafeAssigns(VDecl->getLocation(), VDecl->getType(), Init); + if (VDecl->hasAttr<BlocksAttr>()) + checkRetainCycles(VDecl, Init); + } + Init = MaybeCreateExprWithCleanups(Init); // Attach the initializer to the decl. VDecl->setInit(Init); diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 3d143c8097..97591be98e 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -7698,10 +7698,18 @@ QualType Sema::CheckAssignmentOperands(Expr *LHSExpr, ExprResult &RHS, } if (ConvTy == Compatible) { - if (LHSType.getObjCLifetime() == Qualifiers::OCL_Strong) - checkRetainCycles(LHSExpr, RHS.get()); - else if (getLangOpts().ObjCAutoRefCount) + if (LHSType.getObjCLifetime() == Qualifiers::OCL_Strong) { + // Warn about retain cycles where a block captures the LHS, but + // not if the LHS is a simple variable into which the block is + // being stored...unless that variable can be captured by reference! + const Expr *InnerLHS = LHSExpr->IgnoreParenCasts(); + const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(InnerLHS); + if (!DRE || DRE->getDecl()->hasAttr<BlocksAttr>()) + checkRetainCycles(LHSExpr, RHS.get()); + + } else if (getLangOpts().ObjCAutoRefCount) { checkUnsafeExprAssigns(Loc, LHSExpr, RHS.get()); + } } } else { // Compound assignment "x += y" |