[clang] 28f7087 - [CodeGen][ObjC] Call synthesized copy constructor/assignment operator
Akira Hatanaka via cfe-commits
cfe-commits at lists.llvm.org
Fri Oct 14 10:41:43 PDT 2022
Author: Akira Hatanaka
Date: 2022-10-14T10:40:24-07:00
New Revision: 28f7087c9163f66b07e17bd47a1bfb5d9448467d
URL: https://github.com/llvm/llvm-project/commit/28f7087c9163f66b07e17bd47a1bfb5d9448467d
DIFF: https://github.com/llvm/llvm-project/commit/28f7087c9163f66b07e17bd47a1bfb5d9448467d.diff
LOG: [CodeGen][ObjC] Call synthesized copy constructor/assignment operator
functions in getter/setter functions of non-trivial C struct properties
This fixes a bug where the getter/setter functions were doing a trivial
copy instead of calling the synthesized functions that copy non-trivial
C struct types.
This fixes https://github.com/llvm/llvm-project/issues/56680.
Differential Revision: https://reviews.llvm.org/D131701
Added:
clang/test/CodeGenObjC/nontrivial-c-struct-property.m
Modified:
clang/lib/CodeGen/CGObjC.cpp
Removed:
################################################################################
diff --git a/clang/lib/CodeGen/CGObjC.cpp b/clang/lib/CodeGen/CGObjC.cpp
index 7f23be04b6c5d..5ec2fdb5c1708 100644
--- a/clang/lib/CodeGen/CGObjC.cpp
+++ b/clang/lib/CodeGen/CGObjC.cpp
@@ -22,6 +22,7 @@
#include "clang/AST/StmtObjC.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/CodeGen/CGFunctionInfo.h"
+#include "clang/CodeGen/CodeGenABITypes.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Analysis/ObjCARCUtil.h"
#include "llvm/BinaryFormat/MachO.h"
@@ -1136,6 +1137,23 @@ CodeGenFunction::generateObjCGetterBody(const ObjCImplementationDecl *classImpl,
const ObjCPropertyImplDecl *propImpl,
const ObjCMethodDecl *GetterMethodDecl,
llvm::Constant *AtomicHelperFn) {
+
+ ObjCIvarDecl *ivar = propImpl->getPropertyIvarDecl();
+
+ if (ivar->getType().isNonTrivialToPrimitiveCopy() == QualType::PCK_Struct) {
+ if (!AtomicHelperFn) {
+ LValue Src =
+ EmitLValueForIvar(TypeOfSelfObject(), LoadObjCSelf(), ivar, 0);
+ LValue Dst = MakeAddrLValue(ReturnValue, ivar->getType());
+ callCStructCopyConstructor(Dst, Src);
+ } else {
+ ObjCIvarDecl *ivar = propImpl->getPropertyIvarDecl();
+ emitCPPObjectAtomicGetterCall(*this, ReturnValue.getPointer(), ivar,
+ AtomicHelperFn);
+ }
+ return;
+ }
+
// If there's a non-trivial 'get' expression, we just have to emit that.
if (!hasTrivialGetExpr(propImpl)) {
if (!AtomicHelperFn) {
@@ -1156,8 +1174,6 @@ CodeGenFunction::generateObjCGetterBody(const ObjCImplementationDecl *classImpl,
QualType propType = prop->getType();
ObjCMethodDecl *getterMethod = propImpl->getGetterMethodDecl();
- ObjCIvarDecl *ivar = propImpl->getPropertyIvarDecl();
-
// Pick an implementation strategy.
PropertyImplStrategy strategy(CGM, propImpl);
switch (strategy.getKind()) {
@@ -1424,6 +1440,24 @@ CodeGenFunction::generateObjCSetterBody(const ObjCImplementationDecl *classImpl,
ObjCIvarDecl *ivar = propImpl->getPropertyIvarDecl();
ObjCMethodDecl *setterMethod = propImpl->getSetterMethodDecl();
+ if (ivar->getType().isNonTrivialToPrimitiveCopy() == QualType::PCK_Struct) {
+ ParmVarDecl *PVD = *setterMethod->param_begin();
+ if (!AtomicHelperFn) {
+ // Call the move assignment operator instead of calling the copy
+ // assignment operator and destructor.
+ LValue Dst = EmitLValueForIvar(TypeOfSelfObject(), LoadObjCSelf(), ivar,
+ /*quals*/ 0);
+ LValue Src = MakeAddrLValue(GetAddrOfLocalVar(PVD), ivar->getType());
+ callCStructMoveAssignmentOperator(Dst, Src);
+ } else {
+ // If atomic, assignment is called via a locking api.
+ emitCPPObjectAtomicSetterCall(*this, setterMethod, ivar, AtomicHelperFn);
+ }
+ // Decativate the destructor for the setter parameter.
+ DeactivateCleanupBlock(CalleeDestructedParamCleanups[PVD], AllocaInsertPt);
+ return;
+ }
+
// Just use the setter expression if Sema gave us one and it's
// non-trivial.
if (!hasTrivialSetExpr(propImpl)) {
@@ -3680,15 +3714,27 @@ void CodeGenFunction::EmitExtendGCLifetime(llvm::Value *object) {
llvm::Constant *
CodeGenFunction::GenerateObjCAtomicSetterCopyHelperFunction(
const ObjCPropertyImplDecl *PID) {
+ const ObjCPropertyDecl *PD = PID->getPropertyDecl();
+ if ((!(PD->getPropertyAttributes() & ObjCPropertyAttribute::kind_atomic)))
+ return nullptr;
+
+ QualType Ty = PID->getPropertyIvarDecl()->getType();
+ ASTContext &C = getContext();
+
+ if (Ty.isNonTrivialToPrimitiveCopy() == QualType::PCK_Struct) {
+ // Call the move assignment operator instead of calling the copy assignment
+ // operator and destructor.
+ CharUnits Alignment = C.getTypeAlignInChars(Ty);
+ llvm::Constant *Fn = getNonTrivialCStructMoveAssignmentOperator(
+ CGM, Alignment, Alignment, Ty.isVolatileQualified(), Ty);
+ return llvm::ConstantExpr::getBitCast(Fn, VoidPtrTy);
+ }
+
if (!getLangOpts().CPlusPlus ||
!getLangOpts().ObjCRuntime.hasAtomicCopyHelper())
return nullptr;
- QualType Ty = PID->getPropertyIvarDecl()->getType();
if (!Ty->isRecordType())
return nullptr;
- const ObjCPropertyDecl *PD = PID->getPropertyDecl();
- if ((!(PD->getPropertyAttributes() & ObjCPropertyAttribute::kind_atomic)))
- return nullptr;
llvm::Constant *HelperFn = nullptr;
if (hasTrivialSetExpr(PID))
return nullptr;
@@ -3696,7 +3742,6 @@ CodeGenFunction::GenerateObjCAtomicSetterCopyHelperFunction(
if ((HelperFn = CGM.getAtomicSetterHelperFnMap(Ty)))
return HelperFn;
- ASTContext &C = getContext();
IdentifierInfo *II
= &CGM.getContext().Idents.get("__assign_helper_atomic_property_");
@@ -3767,18 +3812,27 @@ CodeGenFunction::GenerateObjCAtomicSetterCopyHelperFunction(
return HelperFn;
}
-llvm::Constant *
-CodeGenFunction::GenerateObjCAtomicGetterCopyHelperFunction(
- const ObjCPropertyImplDecl *PID) {
+llvm::Constant *CodeGenFunction::GenerateObjCAtomicGetterCopyHelperFunction(
+ const ObjCPropertyImplDecl *PID) {
+ const ObjCPropertyDecl *PD = PID->getPropertyDecl();
+ if ((!(PD->getPropertyAttributes() & ObjCPropertyAttribute::kind_atomic)))
+ return nullptr;
+
+ QualType Ty = PD->getType();
+ ASTContext &C = getContext();
+
+ if (Ty.isNonTrivialToPrimitiveCopy() == QualType::PCK_Struct) {
+ CharUnits Alignment = C.getTypeAlignInChars(Ty);
+ llvm::Constant *Fn = getNonTrivialCStructCopyConstructor(
+ CGM, Alignment, Alignment, Ty.isVolatileQualified(), Ty);
+ return llvm::ConstantExpr::getBitCast(Fn, VoidPtrTy);
+ }
+
if (!getLangOpts().CPlusPlus ||
!getLangOpts().ObjCRuntime.hasAtomicCopyHelper())
return nullptr;
- const ObjCPropertyDecl *PD = PID->getPropertyDecl();
- QualType Ty = PD->getType();
if (!Ty->isRecordType())
return nullptr;
- if ((!(PD->getPropertyAttributes() & ObjCPropertyAttribute::kind_atomic)))
- return nullptr;
llvm::Constant *HelperFn = nullptr;
if (hasTrivialGetExpr(PID))
return nullptr;
@@ -3786,7 +3840,6 @@ CodeGenFunction::GenerateObjCAtomicGetterCopyHelperFunction(
if ((HelperFn = CGM.getAtomicGetterHelperFnMap(Ty)))
return HelperFn;
- ASTContext &C = getContext();
IdentifierInfo *II =
&CGM.getContext().Idents.get("__copy_helper_atomic_property_");
diff --git a/clang/test/CodeGenObjC/nontrivial-c-struct-property.m b/clang/test/CodeGenObjC/nontrivial-c-struct-property.m
new file mode 100644
index 0000000000000..9f907e20331a0
--- /dev/null
+++ b/clang/test/CodeGenObjC/nontrivial-c-struct-property.m
@@ -0,0 +1,70 @@
+// RUN: %clang_cc1 -triple arm64-apple-ios11 -fobjc-arc -emit-llvm -o - %s | FileCheck %s
+
+typedef struct {
+ id x;
+} S0;
+
+ at interface C {
+ S0 _p1;
+}
+ at property(nonatomic) S0 nonatomic;
+ at property S0 atomic0;
+ at property S0 p1;
+-(S0)p1;
+-(void)setP1:(S0)s0;
+ at end
+
+ at implementation C
+-(S0)p1 {
+ return _p1;
+}
+-(void)setP1:(S0)s0 {
+ _p1 = s0;
+}
+ at end
+
+// CHECK: %[[STRUCT_S0:.*]] = type { ptr }
+
+// Check that parameters of user-defined setters are destructed.
+
+// CHECK-LABEL: define internal void @"\01-[C setP1:]"(
+// CHECK: %[[S0:.*]] = alloca %[[STRUCT_S0]], align 8
+// CHECK: call void @__copy_assignment_8_8_s0(ptr %{{.*}}, ptr %[[S0]])
+// CHECK: call void @__destructor_8_s0(ptr %[[S0]])
+
+// CHECK: define internal i64 @"\01-[C nonatomic]"(ptr noundef %[[SELF:.*]], {{.*}})
+// CHECK: %[[RETVAL:.*]] = alloca %[[STRUCT_S0]], align 8
+// CHECK: %[[SELF_ADDR:.*]] = alloca ptr, align 8
+// CHECK: store ptr %[[SELF]], ptr %[[SELF_ADDR]], align 8
+// CHECK: %[[V0:.*]] = load ptr, ptr %[[SELF_ADDR]], align 8
+// CHECK: %[[IVAR:.*]] = load i32, ptr @"OBJC_IVAR_$_C._nonatomic", align 8
+// CHECK: %[[IVAR_CONV:.*]] = sext i32 %[[IVAR]] to i64
+// CHECK: %[[ADD_PTR:.*]] = getelementptr inbounds i8, ptr %[[V0]], i64 %[[IVAR_CONV]]
+// CHECK: call void @__copy_constructor_8_8_s0(ptr %[[RETVAL]], ptr %[[ADD_PTR]])
+// CHECK-NOT: call
+// CHECK: ret i64
+
+// CHECK: define internal void @"\01-[C setNonatomic:]"(ptr noundef %[[SELF:.*]], {{.*}}, i64 %[[NONATOMIC_COERCE:.*]])
+// CHECK: %[[NONATOMIC:.*]] = alloca %[[STRUCT_S0]], align 8
+// CHECK: %[[SELF_ADDR:.*]] = alloca ptr, align 8
+// CHECK: %[[COERCE_DIVE:.*]] = getelementptr inbounds %[[STRUCT_S0]], ptr %[[NONATOMIC]], i32 0, i32 0
+// CHECK: %[[COERCE_VAL_IP:.*]] = inttoptr i64 %[[NONATOMIC_COERCE]] to ptr
+// CHECK: store ptr %[[COERCE_VAL_IP]], ptr %[[COERCE_DIVE]], align 8
+// CHECK: store ptr %[[SELF]], ptr %[[SELF_ADDR]], align 8
+// CHECK: %[[V0:.*]] = load ptr, ptr %[[SELF_ADDR]], align 8
+// CHECK: %[[IVAR:.*]] = load i32, ptr @"OBJC_IVAR_$_C._nonatomic", align 8
+// CHECK: %[[IVAR_CONV:.*]] = sext i32 %[[IVAR]] to i64
+// CHECK: %[[ADD_PTR:.*]] = getelementptr inbounds i8, ptr %[[V0]], i64 %[[IVAR_CONV]]
+// CHECK: call void @__move_assignment_8_8_s0(ptr %[[ADD_PTR]], ptr %[[NONATOMIC]])
+// CHECK-NOT: call
+// CHECK: ret void
+
+// CHECK-LABEL: define internal i64 @"\01-[C atomic0]"(
+// CHECK: call void @objc_copyCppObjectAtomic({{.*}}, {{.*}}, ptr noundef @__copy_constructor_8_8_s0)
+// CHECK-NOT: call
+// CHECK: ret i64
+
+// CHECK-LABEL: define internal void @"\01-[C setAtomic0:]"(
+// CHECK: call void @objc_copyCppObjectAtomic({{.*}}, {{.*}}, ptr noundef @__move_assignment_8_8_s0)
+// CHECK-NOT: call
+// CHECK: ret void
More information about the cfe-commits
mailing list