[llvm-branch-commits] [clang] 34405b4 - [CodeGen][ObjC] Destroy callee-destroyed arguments in the caller
Akira Hatanaka via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Mon Dec 28 11:56:44 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 llvm-branch-commits
mailing list