[PATCH] D60736: [Sema][ObjC] Don't warn about a block implicitly retaining self if the block is marked noescape

2019-04-17 Thread Akira Hatanaka via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rL358624: [Sema][ObjC] Dont warn about an implicitly 
retained self if the (authored by ahatanak, committed by ).
Herald added a project: LLVM.
Herald added a subscriber: llvm-commits.

Changed prior to commit:
  https://reviews.llvm.org/D60736?vs=195639=195650#toc

Repository:
  rL LLVM

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D60736/new/

https://reviews.llvm.org/D60736

Files:
  cfe/trunk/include/clang/AST/DeclBase.h
  cfe/trunk/include/clang/Sema/Sema.h
  cfe/trunk/lib/Sema/SemaDecl.cpp
  cfe/trunk/lib/Sema/SemaDeclObjC.cpp
  cfe/trunk/lib/Sema/SemaExpr.cpp
  cfe/trunk/test/SemaObjC/warn-implicit-self-in-block.m
  cfe/trunk/test/SemaObjCXX/warn-implicit-self-in-block.mm

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/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
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/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 ) {
+  llvm::DenseMap EscapeInfo;
+
+  auto 

[PATCH] D60736: [Sema][ObjC] Don't warn about a block implicitly retaining self if the block is marked noescape

2019-04-17 Thread Erik Pilkington via Phabricator via cfe-commits
erik.pilkington accepted this revision.
erik.pilkington added a comment.

LGTM too, thanks!




Comment at: lib/Sema/SemaDecl.cpp:13169
+do {
+  R = R || !CurBD->doesNotEscape();
+  if (R)

This can just be R = !CurBD->doesNotEscape();


Repository:
  rC Clang

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D60736/new/

https://reviews.llvm.org/D60736



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D60736: [Sema][ObjC] Don't warn about a block implicitly retaining self if the block is marked noescape

2019-04-17 Thread Akira Hatanaka via Phabricator via cfe-commits
ahatanak updated this revision to Diff 195639.
ahatanak added a comment.

Diagnose implicitly retained self in `ActOnFinishFunctionBody`.


Repository:
  rC Clang

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D60736/new/

https://reviews.llvm.org/D60736

Files:
  include/clang/AST/DeclBase.h
  include/clang/Sema/Sema.h
  lib/Sema/SemaDecl.cpp
  lib/Sema/SemaDeclObjC.cpp
  lib/Sema/SemaExpr.cpp
  test/SemaObjC/warn-implicit-self-in-block.m
  test/SemaObjCXX/warn-implicit-self-in-block.mm

Index: test/SemaObjCXX/warn-implicit-self-in-block.mm
===
--- /dev/null
+++ 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
Index: test/SemaObjC/warn-implicit-self-in-block.m
===
--- test/SemaObjC/warn-implicit-self-in-block.m
+++ /dev/null
@@ -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: lib/Sema/SemaExpr.cpp
===
--- lib/Sema/SemaExpr.cpp
+++ 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: lib/Sema/SemaDeclObjC.cpp
===
--- lib/Sema/SemaDeclObjC.cpp
+++ 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: lib/Sema/SemaDecl.cpp
===
--- lib/Sema/SemaDecl.cpp
+++ lib/Sema/SemaDecl.cpp
@@ -13155,6 +13155,35 @@
   bool IsLambda = false;
 };
 
+static void diagnoseImplicitlyRetainedSelf(Sema ) {
+  llvm::DenseMap EscapeInfo;
+
+  auto IsOrNestedInEscapingBlock = [&](const BlockDecl *BD) {
+if (EscapeInfo.count(BD))
+  return EscapeInfo[BD];
+
+bool R = false;
+const BlockDecl *CurBD = BD;
+
+do {
+  R = 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  :
+   S.ImplicitlyRetainedSelfLocs)
+if (IsOrNestedInEscapingBlock(P.second))
+  S.Diag(P.first, diag::warn_implicitly_retains_self)
+  << FixItHint::CreateInsertion(P.first, "self->");
+}
+
 Decl 

[PATCH] D60736: [Sema][ObjC] Don't warn about a block implicitly retaining self if the block is marked noescape

2019-04-17 Thread John McCall via Phabricator via cfe-commits
rjmccall accepted this revision.
rjmccall added a comment.
This revision is now accepted and ready to land.

Alright, LGTM.


Repository:
  rC Clang

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D60736/new/

https://reviews.llvm.org/D60736



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D60736: [Sema][ObjC] Don't warn about a block implicitly retaining self if the block is marked noescape

2019-04-17 Thread Erik Pilkington via Phabricator via cfe-commits
erik.pilkington added inline comments.



Comment at: lib/Parse/ParseObjc.cpp:3696-3699
+
+  Actions.ActOnEndOfObjCMethodDef();
+
   // Clean up the remaining EOF token.

Any reason not to do this check in `ActOnFinishFunctionBody` (which is called 
by ParseFunctionStatementBody)? Seems like there are some similar diagnostics 
implemented there.


Repository:
  rC Clang

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D60736/new/

https://reviews.llvm.org/D60736



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D60736: [Sema][ObjC] Don't warn about a block implicitly retaining self if the block is marked noescape

2019-04-17 Thread Akira Hatanaka via Phabricator via cfe-commits
ahatanak updated this revision to Diff 195601.
ahatanak marked an inline comment as done.
ahatanak added a comment.

Rename function.


Repository:
  rC Clang

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D60736/new/

https://reviews.llvm.org/D60736

Files:
  include/clang/AST/DeclBase.h
  include/clang/Sema/Sema.h
  lib/Parse/ParseObjc.cpp
  lib/Sema/SemaDeclObjC.cpp
  lib/Sema/SemaExpr.cpp
  test/SemaObjC/warn-implicit-self-in-block.m
  test/SemaObjCXX/warn-implicit-self-in-block.mm

Index: test/SemaObjCXX/warn-implicit-self-in-block.mm
===
--- /dev/null
+++ 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
Index: test/SemaObjC/warn-implicit-self-in-block.m
===
--- test/SemaObjC/warn-implicit-self-in-block.m
+++ /dev/null
@@ -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: lib/Sema/SemaExpr.cpp
===
--- lib/Sema/SemaExpr.cpp
+++ 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: lib/Sema/SemaDeclObjC.cpp
===
--- lib/Sema/SemaDeclObjC.cpp
+++ 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);
 
@@ -494,6 +495,35 @@
   }
 }
 
+void Sema::ActOnEndOfObjCMethodDef() {
+  llvm::DenseMap EscapeInfo;
+
+  auto IsOrNestedInEscapingBlock = [&](const BlockDecl *BD) {
+if (EscapeInfo.count(BD))
+  return EscapeInfo[BD];
+
+bool R = false;
+const BlockDecl *CurBD = BD;
+
+do {
+  R = 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  :
+   ImplicitlyRetainedSelfLocs)
+if (IsOrNestedInEscapingBlock(P.second))
+  Diag(P.first, diag::warn_implicitly_retains_self)
+  << FixItHint::CreateInsertion(P.first, "self->");
+}
+
 namespace {
 
 // Callback to only accept typo corrections that are Objective-C classes.
Index: lib/Parse/ParseObjc.cpp
===
--- lib/Parse/ParseObjc.cpp
+++ 

[PATCH] D60736: [Sema][ObjC] Don't warn about a block implicitly retaining self if the block is marked noescape

2019-04-17 Thread John McCall via Phabricator via cfe-commits
rjmccall added inline comments.



Comment at: include/clang/AST/DeclBase.h:1798
+  /// innermost enclosing BlockDecl or null if there are no enclosing blocks.
+  const BlockDecl *getInnerMostBlockDecl() const {
+const DeclContext *Ctx = this;

"innermost" is one word, so this should be `getInnermostBlockDecl`.



Comment at: lib/Sema/SemaExpr.cpp:2580
+if (const BlockDecl *BD = CurContext->getInnerMostBlockDecl())
+  if (!getDiagnostics().isIgnored(diag::warn_implicitly_retains_self, 
Loc))
+ImplicitlyRetainedSelfLocs.push_back({Loc, BD});

ahatanak wrote:
> rjmccall wrote:
> > IIRC this check can be expensive enough that it's probably not worth doing 
> > if you expect these entries to typically not result in diagnostics.
> `DiagStateMap::lookup` is doing a binary search. Is that what makes this 
> check expensive?
Yeah.  It's not immensely expensive, but adding some entries to a vector in the 
fast path and then processing them later probably makes more sense.


Repository:
  rC Clang

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D60736/new/

https://reviews.llvm.org/D60736



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D60736: [Sema][ObjC] Don't warn about a block implicitly retaining self if the block is marked noescape

2019-04-17 Thread Akira Hatanaka via Phabricator via cfe-commits
ahatanak added inline comments.



Comment at: lib/Sema/SemaExpr.cpp:2580
+if (const BlockDecl *BD = CurContext->getInnerMostBlockDecl())
+  if (!getDiagnostics().isIgnored(diag::warn_implicitly_retains_self, 
Loc))
+ImplicitlyRetainedSelfLocs.push_back({Loc, BD});

rjmccall wrote:
> IIRC this check can be expensive enough that it's probably not worth doing if 
> you expect these entries to typically not result in diagnostics.
`DiagStateMap::lookup` is doing a binary search. Is that what makes this check 
expensive?


Repository:
  rC Clang

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D60736/new/

https://reviews.llvm.org/D60736



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D60736: [Sema][ObjC] Don't warn about a block implicitly retaining self if the block is marked noescape

2019-04-17 Thread Akira Hatanaka via Phabricator via cfe-commits
ahatanak updated this revision to Diff 195589.
ahatanak marked 2 inline comments as done.
ahatanak added a comment.

Remove a potentially expensive check.


Repository:
  rC Clang

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D60736/new/

https://reviews.llvm.org/D60736

Files:
  include/clang/AST/DeclBase.h
  include/clang/Sema/Sema.h
  lib/Parse/ParseObjc.cpp
  lib/Sema/SemaDeclObjC.cpp
  lib/Sema/SemaExpr.cpp
  test/SemaObjC/warn-implicit-self-in-block.m
  test/SemaObjCXX/warn-implicit-self-in-block.mm

Index: test/SemaObjCXX/warn-implicit-self-in-block.mm
===
--- /dev/null
+++ 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
Index: test/SemaObjC/warn-implicit-self-in-block.m
===
--- test/SemaObjC/warn-implicit-self-in-block.m
+++ /dev/null
@@ -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: lib/Sema/SemaExpr.cpp
===
--- lib/Sema/SemaExpr.cpp
+++ 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: lib/Sema/SemaDeclObjC.cpp
===
--- lib/Sema/SemaDeclObjC.cpp
+++ 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);
 
@@ -494,6 +495,35 @@
   }
 }
 
+void Sema::ActOnEndOfObjCMethodDef() {
+  llvm::DenseMap EscapeInfo;
+
+  auto IsOrNestedInEscapingBlock = [&](const BlockDecl *BD) {
+if (EscapeInfo.count(BD))
+  return EscapeInfo[BD];
+
+bool R = false;
+const BlockDecl *CurBD = BD;
+
+do {
+  R = 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  :
+   ImplicitlyRetainedSelfLocs)
+if (IsOrNestedInEscapingBlock(P.second))
+  Diag(P.first, diag::warn_implicitly_retains_self)
+  << FixItHint::CreateInsertion(P.first, "self->");
+}
+
 namespace {
 
 // Callback to only accept typo corrections that are Objective-C classes.
Index: lib/Parse/ParseObjc.cpp
===
--- 

[PATCH] D60736: [Sema][ObjC] Don't warn about a block implicitly retaining self if the block is marked noescape

2019-04-16 Thread John McCall via Phabricator via cfe-commits
rjmccall added inline comments.



Comment at: lib/Sema/SemaExpr.cpp:2580
+if (const BlockDecl *BD = CurContext->getInnerMostBlockDecl())
+  if (!getDiagnostics().isIgnored(diag::warn_implicitly_retains_self, 
Loc))
+ImplicitlyRetainedSelfLocs.push_back({Loc, BD});

IIRC this check can be expensive enough that it's probably not worth doing if 
you expect these entries to typically not result in diagnostics.


Repository:
  rC Clang

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D60736/new/

https://reviews.llvm.org/D60736



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D60736: [Sema][ObjC] Don't warn about a block implicitly retaining self if the block is marked noescape

2019-04-16 Thread Akira Hatanaka via Phabricator via cfe-commits
ahatanak updated this revision to Diff 195498.
ahatanak added a comment.

Keep a list of pairs of BlockDecl and SourceLocation and, after the body of an 
ObjC method is parsed, emit a diagnostic if a SourceLocation in the list is 
inside an escaping block.


Repository:
  rC Clang

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D60736/new/

https://reviews.llvm.org/D60736

Files:
  include/clang/AST/DeclBase.h
  include/clang/Sema/Sema.h
  lib/Parse/ParseObjc.cpp
  lib/Sema/SemaDeclObjC.cpp
  lib/Sema/SemaExpr.cpp
  test/SemaObjC/warn-implicit-self-in-block.m
  test/SemaObjCXX/warn-implicit-self-in-block.mm

Index: test/SemaObjCXX/warn-implicit-self-in-block.mm
===
--- /dev/null
+++ 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
Index: test/SemaObjC/warn-implicit-self-in-block.m
===
--- test/SemaObjC/warn-implicit-self-in-block.m
+++ /dev/null
@@ -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: lib/Sema/SemaExpr.cpp
===
--- lib/Sema/SemaExpr.cpp
+++ lib/Sema/SemaExpr.cpp
@@ -2575,11 +2575,10 @@
 !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())
+  if (!getDiagnostics().isIgnored(diag::warn_implicitly_retains_self, Loc))
+ImplicitlyRetainedSelfLocs.push_back({Loc, BD});
 
   return Result;
 }
Index: lib/Sema/SemaDeclObjC.cpp
===
--- lib/Sema/SemaDeclObjC.cpp
+++ 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);
 
@@ -494,6 +495,35 @@
   }
 }
 
+void Sema::ActOnEndOfObjCMethodDef() {
+  llvm::DenseMap EscapeInfo;
+
+  auto IsOrNestedInEscapingBlock = [&](const BlockDecl *BD) {
+if (EscapeInfo.count(BD))
+  return EscapeInfo[BD];
+
+bool R = false;
+const BlockDecl *CurBD = BD;
+
+do {
+  R = 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  :
+   ImplicitlyRetainedSelfLocs)
+if (IsOrNestedInEscapingBlock(P.second))
+  Diag(P.first, diag::warn_implicitly_retains_self)
+  << FixItHint::CreateInsertion(P.first, "self->");
+}
+
 namespace {
 
 // 

[PATCH] D60736: [Sema][ObjC] Don't warn about a block implicitly retaining self if the block is marked noescape

2019-04-15 Thread Erik Pilkington via Phabricator via cfe-commits
erik.pilkington added a comment.

Akira and I were just talking about an alternative approach to this: Keep a 
vector of pairs of BlockDecls and SourceLocations in the enclosing method's 
FunctionScopeInfo, and emit any unsuppressed  diagnostics when popping the 
method. This would avoid having to traverse all the blocks in methods in ARC 
mode, at the cost of a small amount of memory.




Comment at: lib/Sema/Sema.cpp:1682-1687
+  void VisitBlockDecl(const BlockDecl *BD) {
+bool OldVisitingEscapingBlock = VisitingEscapingBlock;
+VisitingEscapingBlock = VisitingEscapingBlock || !BD->doesNotEscape();
+Visit(BD->getBody());
+VisitingEscapingBlock = OldVisitingEscapingBlock;
+  }

Maybe call this "diagnoseBlockDecl" or something so it doesn't sounds like a 
CRTP-overridden method.


Repository:
  rC Clang

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D60736/new/

https://reviews.llvm.org/D60736



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D60736: [Sema][ObjC] Don't warn about a block implicitly retaining self if the block is marked noescape

2019-04-15 Thread Akira Hatanaka via Phabricator via cfe-commits
ahatanak added a comment.

Sorry, clang was failing to diagnose `self` referenced inside a c++ lambda that 
was nested inside a block.


Repository:
  rC Clang

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D60736/new/

https://reviews.llvm.org/D60736



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D60736: [Sema][ObjC] Don't warn about a block implicitly retaining self if the block is marked noescape

2019-04-15 Thread Akira Hatanaka via Phabricator via cfe-commits
ahatanak created this revision.
ahatanak added reviewers: rjmccall, erik.pilkington, arphaman.
ahatanak added a project: clang.
Herald added subscribers: dexonsmith, jkorous.

If the block implicitly referencing `self` doesn't escape, there is no risk of 
creating retain cycles, so clang shouldn't diagnose it and force users to add 
`self->` to silence the diagnostic.

Also, fix a bug where clang was failing to diagnose `self` referenced inside a 
block that was nested inside a c++ lambda.

rdar://problem/25059955


Repository:
  rC Clang

https://reviews.llvm.org/D60736

Files:
  include/clang/Sema/ScopeInfo.h
  lib/Sema/Sema.cpp
  lib/Sema/SemaDeclObjC.cpp
  lib/Sema/SemaExpr.cpp
  test/SemaObjC/warn-implicit-self-in-block.m
  test/SemaObjCXX/warn-implicit-self-in-block.mm

Index: test/SemaObjCXX/warn-implicit-self-in-block.mm
===
--- /dev/null
+++ 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
Index: test/SemaObjC/warn-implicit-self-in-block.m
===
--- test/SemaObjC/warn-implicit-self-in-block.m
+++ /dev/null
@@ -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: lib/Sema/SemaExpr.cpp
===
--- lib/Sema/SemaExpr.cpp
+++ lib/Sema/SemaExpr.cpp
@@ -2575,11 +2575,6 @@
 !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->");
-  }
 
   return Result;
 }
@@ -13652,6 +13647,9 @@
 }
   }
 
+  if (getCurFunction())
+getCurFunction()->addBlock(Block, /*IsIntroducedInCurrentScope*/true);
+
   PushBlockScope(CurScope, Block);
   CurContext->addDecl(Block);
   if (CurScope)
@@ -13913,9 +13911,6 @@
 }
   }
 
-  if (getCurFunction())
-getCurFunction()->addBlock(BD);
-
   return Result;
 }
 
Index: lib/Sema/SemaDeclObjC.cpp
===
--- lib/Sema/SemaDeclObjC.cpp
+++ lib/Sema/SemaDeclObjC.cpp
@@ -378,6 +378,7 @@
   // Allow all of Sema to see that we are entering a method definition.
   PushDeclContext(FnBodyScope, MDecl);
   PushFunctionScope();
+  getCurFunction()->setIsObjCMethod();
 
   // Create Decl objects for each parameter, entrring them in the scope for
   // binding to their use.
Index: lib/Sema/Sema.cpp
===
--- lib/Sema/Sema.cpp
+++ lib/Sema/Sema.cpp
@@ -20,6 +20,7 @@
 #include "clang/AST/ExprCXX.h"
 #include "clang/AST/PrettyDeclStackTrace.h"
 #include "clang/AST/StmtCXX.h"
+#include "clang/AST/StmtVisitor.h"
 #include "clang/Basic/DiagnosticOptions.h"
 #include "clang/Basic/PartialDiagnostic.h"
 #include "clang/Basic/TargetInfo.h"
@@ -1636,10 +1637,16 @@
 static void markEscapingByrefs(const FunctionScopeInfo , Sema ) {
   // Set the EscapingByref flag of __block variables captured by
   // escaping blocks.
-  for (const BlockDecl *BD : FSI.Blocks) {
-if (BD->doesNotEscape())
+