[clang] 34405b4 - [CodeGen][ObjC] Destroy callee-destroyed arguments in the caller

Akira Hatanaka via cfe-commits cfe-commits at lists.llvm.org
Mon Dec 28 11:52:41 PST 2020


Author: Akira Hatanaka
Date: 2020-12-28T11:52:27-08:00
New Revision: 34405b41d61580ff893057784b1b19f81f66bad3

URL: https://github.com/llvm/llvm-project/commit/34405b41d61580ff893057784b1b19f81f66bad3
DIFF: https://github.com/llvm/llvm-project/commit/34405b41d61580ff893057784b1b19f81f66bad3.diff

LOG: [CodeGen][ObjC] Destroy callee-destroyed arguments in the caller
function when the receiver is nil

Callee-destroyed arguments to a method have to be destroyed in the
caller function when the receiver is nil as the method doesn't get
executed. This fixes PR48207.

rdar://71808391

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

Added: 
    clang/test/CodeGenObjC/objc-dispatch-null-check.m

Modified: 
    clang/include/clang/AST/Decl.h
    clang/lib/AST/Decl.cpp
    clang/lib/CodeGen/CGObjCMac.cpp
    clang/test/CodeGenObjC/strong-in-c-struct.m
    clang/test/CodeGenObjC/weak-in-c-struct.m
    clang/test/CodeGenObjCXX/objc-struct-cxx-abi.mm

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h
index ab24c8779df2..47c282f0a63d 100644
--- a/clang/include/clang/AST/Decl.h
+++ b/clang/include/clang/AST/Decl.h
@@ -1664,6 +1664,9 @@ class ParmVarDecl : public VarDecl {
     return ParmVarDeclBits.IsObjCMethodParam;
   }
 
+  /// Determines whether this parameter is destroyed in the callee function.
+  bool isDestroyedInCallee() const;
+
   unsigned getFunctionScopeDepth() const {
     if (ParmVarDeclBits.IsObjCMethodParam) return 0;
     return ParmVarDeclBits.ScopeDepthOrObjCQuals;

diff  --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp
index f0c925f9cdf9..3cea3c23b527 100644
--- a/clang/lib/AST/Decl.cpp
+++ b/clang/lib/AST/Decl.cpp
@@ -2738,6 +2738,17 @@ SourceRange ParmVarDecl::getSourceRange() const {
   return DeclaratorDecl::getSourceRange();
 }
 
+bool ParmVarDecl::isDestroyedInCallee() const {
+  if (hasAttr<NSConsumedAttr>())
+    return true;
+
+  auto *RT = getType()->getAs<RecordType>();
+  if (RT && RT->getDecl()->isParamDestroyedInCallee())
+    return true;
+
+  return false;
+}
+
 Expr *ParmVarDecl::getDefaultArg() {
   assert(!hasUnparsedDefaultArg() && "Default argument is not yet parsed!");
   assert(!hasUninstantiatedDefaultArg() &&

diff  --git a/clang/lib/CodeGen/CGObjCMac.cpp b/clang/lib/CodeGen/CGObjCMac.cpp
index dff86744698d..465d2c5449d5 100644
--- a/clang/lib/CodeGen/CGObjCMac.cpp
+++ b/clang/lib/CodeGen/CGObjCMac.cpp
@@ -1765,6 +1765,24 @@ struct NullReturnState {
           assert(RV.isScalar() &&
                  "NullReturnState::complete - arg not on object");
           CGF.EmitARCRelease(RV.getScalarVal(), ARCImpreciseLifetime);
+        } else {
+          QualType QT = ParamDecl->getType();
+          auto *RT = QT->getAs<RecordType>();
+          if (RT && RT->getDecl()->isParamDestroyedInCallee()) {
+            RValue RV = I->getRValue(CGF);
+            QualType::DestructionKind DtorKind = QT.isDestructedType();
+            switch (DtorKind) {
+            case QualType::DK_cxx_destructor:
+              CGF.destroyCXXObject(CGF, RV.getAggregateAddress(), QT);
+              break;
+            case QualType::DK_nontrivial_c_struct:
+              CGF.destroyNonTrivialCStruct(CGF, RV.getAggregateAddress(), QT);
+              break;
+            default:
+              llvm_unreachable("unexpected dtor kind");
+              break;
+            }
+          }
         }
       }
     }
@@ -2241,7 +2259,7 @@ CGObjCCommonMac::EmitMessageSend(CodeGen::CodeGenFunction &CGF,
   // Emit a null-check if there's a consumed argument other than the receiver.
   if (!RequiresNullCheck && CGM.getLangOpts().ObjCAutoRefCount && Method) {
     for (const auto *ParamDecl : Method->parameters()) {
-      if (ParamDecl->hasAttr<NSConsumedAttr>()) {
+      if (ParamDecl->isDestroyedInCallee()) {
         RequiresNullCheck = true;
         break;
       }
@@ -7350,7 +7368,7 @@ CGObjCNonFragileABIMac::EmitVTableMessageSend(CodeGenFunction &CGF,
   bool requiresnullCheck = false;
   if (CGM.getLangOpts().ObjCAutoRefCount && method)
     for (const auto *ParamDecl : method->parameters()) {
-      if (ParamDecl->hasAttr<NSConsumedAttr>()) {
+      if (ParamDecl->isDestroyedInCallee()) {
         if (!nullReturn.NullBB)
           nullReturn.init(CGF, arg0);
         requiresnullCheck = true;

diff  --git a/clang/test/CodeGenObjC/objc-dispatch-null-check.m b/clang/test/CodeGenObjC/objc-dispatch-null-check.m
new file mode 100644
index 000000000000..0c43955db2fa
--- /dev/null
+++ b/clang/test/CodeGenObjC/objc-dispatch-null-check.m
@@ -0,0 +1,34 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -fobjc-dispatch-method=non-legacy -fobjc-arc -emit-llvm -o - %s | FileCheck %s
+
+// CHECK: %[[STRUCT_STRONG:.*]] = type { i8* }
+
+typedef struct {
+  id x;
+} Strong;
+
+Strong getStrong(void);
+
+ at interface I0
+- (void)passStrong:(Strong)a;
+ at end
+
+// CHECK-LABEL: define void @test0(
+// CHECK: %[[AGG_TMP:.*]] = alloca %[[STRUCT_STRONG]], align 8
+// CHECK: %[[CALL:.*]] = call i8* @getStrong()
+// CHECK-NEXT: %[[COERCE_DIVE:.*]] = getelementptr inbounds %[[STRUCT_STRONG]], %[[STRUCT_STRONG]]* %[[AGG_TMP]], i32 0, i32 0
+// CHECK-NEXT: store i8* %[[CALL]], i8** %[[COERCE_DIVE]], align 8
+
+// CHECK: %[[MSGSEND_FN:.*]] = load i8*, i8**
+// CHECK: %[[V5:.*]] = bitcast i8* %[[MSGSEND_FN]] to void (i8*, i8*, i8*)*
+// CHECK: %[[COERCE_DIVE1:.*]] = getelementptr inbounds %[[STRUCT_STRONG]], %[[STRUCT_STRONG]]* %[[AGG_TMP]], i32 0, i32 0
+// CHECK: %[[V6:.*]] = load i8*, i8** %[[COERCE_DIVE1]], align 8
+// CHECK: call void %[[V5]]({{.*}}, i8* %[[V6]])
+// CHECK: br
+
+// CHECK: %[[V7:.*]] = bitcast %[[STRUCT_STRONG]]* %[[AGG_TMP]] to i8**
+// CHECK: call void @__destructor_8_s0(i8** %[[V7]])
+// CHECK: br
+
+void test0(I0 *a) {
+  [a passStrong:getStrong()];
+}

diff  --git a/clang/test/CodeGenObjC/strong-in-c-struct.m b/clang/test/CodeGenObjC/strong-in-c-struct.m
index 4e098c352ab5..d9e503feafd2 100644
--- a/clang/test/CodeGenObjC/strong-in-c-struct.m
+++ b/clang/test/CodeGenObjC/strong-in-c-struct.m
@@ -91,6 +91,7 @@
 
 @interface C
 - (StrongSmall)getStrongSmall;
+- (void)m:(StrongSmall)s;
 + (StrongSmall)getStrongSmallClass;
 @end
 
@@ -944,4 +945,21 @@ id test_assignment1(void) {
   calleeStrongSmall(g2 = g1);
 }
 
+// CHECK-LABEL: define void @test_null_reveiver(
+// CHECK: %[[AGG_TMP:.*]] = alloca %[[STRUCT_STRONGSMALL]], align 8
+// CHECK: br i1
+
+// CHECK: %[[V7:.*]] = bitcast %[[STRUCT_STRONGSMALL]]* %[[AGG_TMP]] to [2 x i64]*
+// CHECK: %[[V8:.*]] = load [2 x i64], [2 x i64]* %[[V7]], align 8
+// CHECK: call void bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to void ({{.*}}, [2 x i64] %[[V8]])
+// CHECK: br
+
+// CHECK: %[[V9:.*]] = bitcast %[[STRUCT_STRONGSMALL]]* %[[AGG_TMP]] to i8**
+// CHECK: call void @__destructor_8_s8(i8** %[[V9]]) #4
+// CHECK: br
+
+void test_null_reveiver(C *c) {
+  [c m:getStrongSmall()];
+}
+
 #endif /* USESTRUCT */

diff  --git a/clang/test/CodeGenObjC/weak-in-c-struct.m b/clang/test/CodeGenObjC/weak-in-c-struct.m
index 4bebc20625eb..ac844a8a8935 100644
--- a/clang/test/CodeGenObjC/weak-in-c-struct.m
+++ b/clang/test/CodeGenObjC/weak-in-c-struct.m
@@ -42,6 +42,10 @@
 // ARM64: %[[V3:.*]] = bitcast i8* %[[V2]] to i8**
 // ARM64: call void @llvm.objc.destroyWeak(i8** %[[V3]])
 
+ at interface C
+- (void)m:(Weak)a;
+ at end
+
 void test_constructor_destructor_Weak(void) {
   Weak t;
 }
@@ -191,3 +195,18 @@ void test_argument_Weak(Weak *a) {
 Weak test_return_Weak(Weak *a) {
   return *a;
 }
+
+// COMMON-LABEL: define void @test_null_receiver(
+// COMMON: %[[AGG_TMP:.*]] = alloca %[[STRUCT_WEAK]]
+// COMMON: br i1
+
+// COMMON: call void bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to void (i8*, i8*, %[[STRUCT_WEAK]]*)*)({{.*}}, %[[STRUCT_WEAK]]* %[[AGG_TMP]])
+// COMMON: br
+
+// COMMON: %[[V6:.*]] = bitcast %[[STRUCT_WEAK]]* %[[AGG_TMP]] to i8**
+// COMMON: call void @__destructor_{{.*}}(i8** %[[V6]])
+// COMMON: br
+
+void test_null_receiver(C *c) {
+  [c m:getWeak()];
+}

diff  --git a/clang/test/CodeGenObjCXX/objc-struct-cxx-abi.mm b/clang/test/CodeGenObjCXX/objc-struct-cxx-abi.mm
index bd89c8629a7c..efaced63aa42 100644
--- a/clang/test/CodeGenObjCXX/objc-struct-cxx-abi.mm
+++ b/clang/test/CodeGenObjCXX/objc-struct-cxx-abi.mm
@@ -13,6 +13,7 @@
 // CHECK: %[[STRUCT_STRONG:.*]] = type { i8* }
 // CHECK: %[[STRUCT_S:.*]] = type { i8* }
 // CHECK: %[[STRUCT_CONTAINSNONTRIVIAL:.*]] = type { %{{.*}}, i8* }
+// CHECK: %[[STRUCT_NONTRIVIAL:.*]] = type { i32* }
 
 #ifdef TRIVIALABI
 struct __attribute__((trivial_abi)) StrongWeak {
@@ -69,6 +70,12 @@ struct __attribute__((trivial_abi)) S {
   id f1;
 };
 
+ at interface C
+- (void)passStrong:(Strong)a;
+- (void)passStrongWeak:(StrongWeak)a;
+- (void)passNonTrivial:(NonTrivial)a;
+ at end
+
 // CHECK: define void @_Z19testParamStrongWeak10StrongWeak(%[[STRUCT_STRONGWEAK]]* %{{.*}})
 // CHECK: call %struct.StrongWeak* @_ZN10StrongWeakD1Ev(
 // CHECK-NEXT: ret void
@@ -207,3 +214,49 @@ void testCallContainsNonTrivial(ContainsNonTrivial *a) {
 Strong D0::m0() { return {}; }
 
 }
+
+namespace testNullReceiver {
+
+// CHECK-LABEL: define void @_ZN16testNullReceiver5test0EP1C(
+// CHECK: %[[AGG_TMP:.*]] = alloca %[[STRUCT_STRONG]], align 8
+// CHECK: br i1
+
+// CHECK: %[[COERCE_DIVE:.*]] = getelementptr inbounds %[[STRUCT_STRONG]], %[[STRUCT_STRONG]]* %[[AGG_TMP]], i32 0, i32 0
+// CHECK: %[[V7:.*]] = load i8*, i8** %[[COERCE_DIVE]], align 8
+// CHECK: %[[COERCE_VAL_PI:.*]] = ptrtoint i8* %[[V7]] to i64
+// CHECK: call void bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to void (i8*, i8*, i64)*)({{.*}}, i64 %[[COERCE_VAL_PI]])
+// CHECK: br
+
+// CHECK: %[[CALL1:.*]] = call %[[STRUCT_STRONG]]* @_ZN6StrongD1Ev(%[[STRUCT_STRONG]]* nonnull dereferenceable(8) %[[AGG_TMP]])
+// CHECK: br
+
+void test0(C *c) {
+  [c passStrong:Strong()];
+}
+
+// CHECK-LABEL: define void @_ZN16testNullReceiver5test1EP1C(
+// CHECK: %[[AGG_TMP:.*]] = alloca %[[STRUCT_STRONGWEAK]], align 8
+// CHECK: br i1
+
+// CHECK: call void bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to void ({{.*}}, %[[STRUCT_STRONGWEAK]]* %[[AGG_TMP]])
+// CHECK: br
+
+// CHECK: %[[CALL1:.*]] = call %[[STRUCT_STRONGWEAK]]* @_ZN10StrongWeakD1Ev(%[[STRUCT_STRONGWEAK]]* nonnull dereferenceable(16) %[[AGG_TMP]])
+// CHECK: br
+
+void test1(C *c) {
+  [c passStrongWeak:StrongWeak()];
+}
+
+// No null check needed.
+
+// CHECK-LABEL: define void @_ZN16testNullReceiver5test2EP1C(
+// CHECK: %[[AGG_TMP:.*]] = alloca %[[STRUCT_NONTRIVIAL]], align 8
+// CHECK: call void bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to void (i8*, i8*, %[[STRUCT_NONTRIVIAL]]*)*)({{.*}}, %[[STRUCT_NONTRIVIAL]]* %[[AGG_TMP]])
+// CHECK-NEXT: call %[[STRUCT_NONTRIVIAL]]* @_ZN10NonTrivialD1Ev(%[[STRUCT_NONTRIVIAL]]* nonnull dereferenceable(8) %[[AGG_TMP]])
+
+void test2(C *c) {
+  [c passNonTrivial:NonTrivial()];
+}
+
+}


        


More information about the cfe-commits mailing list