[clang] 2e1d9eb - [ObjC][ARC] Don't enter the cleanup scope if the initializer expression

Akira Hatanaka via cfe-commits cfe-commits at lists.llvm.org
Thu Apr 29 16:07:30 PDT 2021


Author: Akira Hatanaka
Date: 2021-04-29T16:04:30-07:00
New Revision: 2e1d9ebd46b826b06f0a5882e992e3d84335f268

URL: https://github.com/llvm/llvm-project/commit/2e1d9ebd46b826b06f0a5882e992e3d84335f268
DIFF: https://github.com/llvm/llvm-project/commit/2e1d9ebd46b826b06f0a5882e992e3d84335f268.diff

LOG: [ObjC][ARC] Don't enter the cleanup scope if the initializer expression
isn't an ExprWithCleanups

This patch fixes a bug where a temporary ObjC pointer is released before
the end of the full expression.

This fixes PR50043.

rdar://77030453

Differential Revision: https://reviews.llvm.org/D101502

Added: 
    

Modified: 
    clang/lib/CodeGen/CGDecl.cpp
    clang/test/CodeGenObjCXX/arc-blocks.mm
    clang/test/CodeGenObjCXX/arc.mm

Removed: 
    


################################################################################
diff  --git a/clang/lib/CodeGen/CGDecl.cpp b/clang/lib/CodeGen/CGDecl.cpp
index 5bab185976886..7b89f5dfc9ba5 100644
--- a/clang/lib/CodeGen/CGDecl.cpp
+++ b/clang/lib/CodeGen/CGDecl.cpp
@@ -772,9 +772,10 @@ void CodeGenFunction::EmitScalarInit(const Expr *init, const ValueDecl *D,
 
   // If we're emitting a value with lifetime, we have to do the
   // initialization *before* we leave the cleanup scopes.
-  if (const ExprWithCleanups *EWC = dyn_cast<ExprWithCleanups>(init))
-    init = EWC->getSubExpr();
-  CodeGenFunction::RunCleanupsScope Scope(*this);
+  if (auto *EWC = dyn_cast<ExprWithCleanups>(init)) {
+    CodeGenFunction::RunCleanupsScope Scope(*this);
+    return EmitScalarInit(EWC->getSubExpr(), D, lvalue, capturedByInit);
+  }
 
   // We have to maintain the illusion that the variable is
   // zero-initialized.  If the variable might be accessed in its

diff  --git a/clang/test/CodeGenObjCXX/arc-blocks.mm b/clang/test/CodeGenObjCXX/arc-blocks.mm
index f0d3b8eefa535..2b06bf0fffebe 100644
--- a/clang/test/CodeGenObjCXX/arc-blocks.mm
+++ b/clang/test/CodeGenObjCXX/arc-blocks.mm
@@ -204,10 +204,10 @@ void foo1() {
 
 // Test that calls to @llvm.objc.retainBlock aren't emitted in some cases.
 
-namespace test_block_retain {
-  typedef void (^BlockTy)();
+typedef void (^BlockTy)();
+void foo1(id);
 
-  void foo1(id);
+namespace test_block_retain {
 
 // CHECK-LABEL: define{{.*}} void @_ZN17test_block_retain14initializationEP11objc_object(
 // CHECK-NOT: @llvm.objc.retainBlock(
@@ -321,3 +321,24 @@ void assignmentObjCPtr(id a) {
     ((BlockTy)b1)();
   }
 }
+
+// Check that the block capture is released after the full expression.
+
+// CHECK-LABEL: define void @_ZN13test_rval_ref4testEP11objc_object(
+// CHECK: %[[BLOCK:.*]] = alloca <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8* }>, align 8
+// CHECK: %[[BLOCK_CAPTURED:.*]] = getelementptr inbounds <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8* }>, <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8* }>* %[[BLOCK]], i32 0, i32 5
+// CHECK: %[[V1:.*]] = call i8* @llvm.objc.retain(
+// CHECK: store i8* %[[V1]], i8** %[[BLOCK_CAPTURED]], align 8
+// CHECK: invoke void @_ZN13test_rval_ref17callTemplateBlockEOU15__autoreleasingU13block_pointerFvvE(
+
+// CHECK: call void @llvm.objc.storeStrong(i8** %[[BLOCK_CAPTURED]], i8* null)
+
+namespace test_rval_ref {
+  void callTemplateBlock(BlockTy &&func);
+
+  void test(id str) {
+    return callTemplateBlock(^void() {
+      foo1(str);
+    });
+  }
+}

diff  --git a/clang/test/CodeGenObjCXX/arc.mm b/clang/test/CodeGenObjCXX/arc.mm
index 5b45cae1f8cae..bb576b051161d 100644
--- a/clang/test/CodeGenObjCXX/arc.mm
+++ b/clang/test/CodeGenObjCXX/arc.mm
@@ -334,3 +334,17 @@ void test41(__weak id &&x) {
 // CHECK:      [[T0:%.*]] = load i8**, i8*** [[X]]
 // CHECK-NEXT: call void @llvm.objc.moveWeak(i8** [[Y]], i8** [[T0]])
 // CHECK-NEXT: call void @llvm.objc.destroyWeak(i8** [[Y]])
+
+void test42() {
+  __attribute__((ns_returns_retained)) id test42_0();
+  id test42_1(id);
+  void test42_2(id &&);
+  test42_2(test42_1(test42_0()));
+}
+
+// Check that the pointer returned by test42_0 is released after the full expression.
+
+// CHECK-LABEL: define void @_Z6test42v()
+// CHECK: %[[CALL:.*]] = call i8* @_Z8test42_0v()
+// CHECK: call void @_Z8test42_2OU15__autoreleasingP11objc_object(
+// CHECK: call void @llvm.objc.release(i8* %[[CALL]])


        


More information about the cfe-commits mailing list