Index: cfe/trunk/include/clang/AST/DeclBase.h =================================================================== --- cfe/trunk/include/clang/AST/DeclBase.h +++ cfe/trunk/include/clang/AST/DeclBase.h @@ -41,6 +41,7 @@ class ASTContext; class ASTMutationListener; class Attr; +class BlockDecl; class DeclContext; class ExternalSourceSymbolAttr; class FunctionDecl; @@ -1792,6 +1793,20 @@ bool isClosure() const { return getDeclKind() == Decl::Block; } + /// Return this DeclContext if it is a BlockDecl. Otherwise, return the + /// innermost enclosing BlockDecl or null if there are no enclosing blocks. + const BlockDecl *getInnermostBlockDecl() const { + const DeclContext *Ctx = this; + + do { + if (Ctx->isClosure()) + return cast(Ctx); + Ctx = Ctx->getParent(); + } while (Ctx); + + return nullptr; + } + bool isObjCContainer() const { switch (getDeclKind()) { case Decl::ObjCCategory: Index: cfe/trunk/include/clang/Sema/Sema.h =================================================================== --- cfe/trunk/include/clang/Sema/Sema.h +++ cfe/trunk/include/clang/Sema/Sema.h @@ -1213,6 +1213,11 @@ /// of -Wselector. llvm::MapVector ReferencedSelectors; + /// List of SourceLocations where 'self' is implicitly retained inside a + /// block. + llvm::SmallVector, 1> + ImplicitlyRetainedSelfLocs; + /// Kinds of C++ special members. enum CXXSpecialMember { CXXDefaultConstructor, Index: cfe/trunk/lib/Sema/SemaDecl.cpp =================================================================== --- cfe/trunk/lib/Sema/SemaDecl.cpp +++ cfe/trunk/lib/Sema/SemaDecl.cpp @@ -13150,6 +13150,35 @@ bool IsLambda = false; }; +static void diagnoseImplicitlyRetainedSelf(Sema &S) { + llvm::DenseMap EscapeInfo; + + auto IsOrNestedInEscapingBlock = [&](const BlockDecl *BD) { + if (EscapeInfo.count(BD)) + return EscapeInfo[BD]; + + bool R = false; + const BlockDecl *CurBD = BD; + + do { + R = !CurBD->doesNotEscape(); + if (R) + break; + CurBD = CurBD->getParent()->getInnermostBlockDecl(); + } while (CurBD); + + return EscapeInfo[BD] = R; + }; + + // If the location where 'self' is implicitly retained is inside a escaping + // block, emit a diagnostic. + for (const std::pair &P : + S.ImplicitlyRetainedSelfLocs) + if (IsOrNestedInEscapingBlock(P.second)) + S.Diag(P.first, diag::warn_implicitly_retains_self) + << FixItHint::CreateInsertion(P.first, "self->"); +} + Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body, bool IsInstantiation) { FunctionDecl *FD = dcl ? dcl->getAsFunction() : nullptr; @@ -13361,6 +13390,8 @@ diag::warn_objc_secondary_init_missing_init_call); getCurFunction()->ObjCWarnForNoInitDelegation = false; } + + diagnoseImplicitlyRetainedSelf(*this); } else { // Parsing the function declaration failed in some way. Pop the fake scope // we pushed on. Index: cfe/trunk/lib/Sema/SemaDeclObjC.cpp =================================================================== --- cfe/trunk/lib/Sema/SemaDeclObjC.cpp +++ cfe/trunk/lib/Sema/SemaDeclObjC.cpp @@ -359,6 +359,7 @@ /// ActOnStartOfObjCMethodDef - This routine sets up parameters; invisible /// and user declared, in the method definition's AST. void Sema::ActOnStartOfObjCMethodDef(Scope *FnBodyScope, Decl *D) { + ImplicitlyRetainedSelfLocs.clear(); assert((getCurMethodDecl() == nullptr) && "Methodparsing confused"); ObjCMethodDecl *MDecl = dyn_cast_or_null(D); Index: cfe/trunk/lib/Sema/SemaExpr.cpp =================================================================== --- cfe/trunk/lib/Sema/SemaExpr.cpp +++ cfe/trunk/lib/Sema/SemaExpr.cpp @@ -2575,11 +2575,9 @@ !Diags.isIgnored(diag::warn_arc_repeated_use_of_weak, Loc)) getCurFunction()->recordUseOfWeak(Result); } - if (getLangOpts().ObjCAutoRefCount) { - if (CurContext->isClosure()) - Diag(Loc, diag::warn_implicitly_retains_self) - << FixItHint::CreateInsertion(Loc, "self->"); - } + if (getLangOpts().ObjCAutoRefCount) + if (const BlockDecl *BD = CurContext->getInnermostBlockDecl()) + ImplicitlyRetainedSelfLocs.push_back({Loc, BD}); return Result; } Index: cfe/trunk/test/SemaObjC/warn-implicit-self-in-block.m =================================================================== --- cfe/trunk/test/SemaObjC/warn-implicit-self-in-block.m +++ cfe/trunk/test/SemaObjC/warn-implicit-self-in-block.m @@ -1,18 +0,0 @@ -// RUN: %clang_cc1 -x objective-c -fobjc-arc -fblocks -Wimplicit-retain-self -verify %s -// rdar://11194874 - -@interface Root @end - -@interface I : Root -{ - int _bar; -} -@end - -@implementation I - - (void)foo{ - ^{ - _bar = 3; // expected-warning {{block implicitly retains 'self'; explicitly mention 'self' to indicate this is intended behavior}} - }(); - } -@end Index: cfe/trunk/test/SemaObjCXX/warn-implicit-self-in-block.mm =================================================================== --- cfe/trunk/test/SemaObjCXX/warn-implicit-self-in-block.mm +++ cfe/trunk/test/SemaObjCXX/warn-implicit-self-in-block.mm @@ -0,0 +1,42 @@ +// RUN: %clang_cc1 -x objective-c++ -std=c++11 -fobjc-arc -fblocks -Wimplicit-retain-self -verify %s +// rdar://11194874 + +typedef void (^BlockTy)(); + +void noescapeFunc(__attribute__((noescape)) BlockTy); +void escapeFunc(BlockTy); + +@interface Root @end + +@interface I : Root +{ + int _bar; +} +@end + +@implementation I + - (void)foo{ + ^{ + _bar = 3; // expected-warning {{block implicitly retains 'self'; explicitly mention 'self' to indicate this is intended behavior}} + }(); + } + + - (void)testNested{ + noescapeFunc(^{ + (void)_bar; + escapeFunc(^{ + (void)_bar; // expected-warning {{block implicitly retains 'self'; explicitly mention 'self' to indicate this is intended behavior}} + noescapeFunc(^{ + (void)_bar; // expected-warning {{block implicitly retains 'self'; explicitly mention 'self' to indicate this is intended behavior}} + }); + (void)_bar; // expected-warning {{block implicitly retains 'self'; explicitly mention 'self' to indicate this is intended behavior}} + }); + (void)_bar; + }); + } + + - (void)testLambdaInBlock{ + noescapeFunc(^{ [&](){ (void)_bar; }(); }); + escapeFunc(^{ [&](){ (void)_bar; }(); }); // expected-warning {{block implicitly retains 'self'; explicitly mention 'self' to indicate this is intended behavior}} + } +@end