From 7275da0f2ee24336fe83cb7cfe2ba22f9cefc117 Mon Sep 17 00:00:00 2001 From: Akira Hatanaka Date: Wed, 28 Feb 2018 07:15:55 +0000 Subject: [ObjC] Allow declaring __strong pointer fields in structs in Objective-C ARC mode. Declaring __strong pointer fields in structs was not allowed in Objective-C ARC until now because that would make the struct non-trivial to default-initialize, copy/move, and destroy, which is not something C was designed to do. This patch lifts that restriction. Special functions for non-trivial C structs are synthesized that are needed to default-initialize, copy/move, and destroy the structs and manage the ownership of the objects the __strong pointer fields point to. Non-trivial structs passed to functions are destructed in the callee function. rdar://problem/33599681 Differential Revision: https://reviews.llvm.org/D41228 llvm-svn: 326307 --- clang/lib/CodeGen/CGExprAgg.cpp | 43 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 40 insertions(+), 3 deletions(-) (limited to 'clang/lib/CodeGen/CGExprAgg.cpp') diff --git a/clang/lib/CodeGen/CGExprAgg.cpp b/clang/lib/CodeGen/CGExprAgg.cpp index 34ce0d3398f..394336ee122 100644 --- a/clang/lib/CodeGen/CGExprAgg.cpp +++ b/clang/lib/CodeGen/CGExprAgg.cpp @@ -77,8 +77,15 @@ public: /// then loads the result into DestPtr. void EmitAggLoadOfLValue(const Expr *E); + enum ExprValueKind { + EVK_RValue, + EVK_NonRValue + }; + /// EmitFinalDestCopy - Perform the final copy to DestPtr, if desired. - void EmitFinalDestCopy(QualType type, const LValue &src); + /// SrcIsRValue is true if source comes from an RValue. + void EmitFinalDestCopy(QualType type, const LValue &src, + ExprValueKind SrcValueKind = EVK_NonRValue); void EmitFinalDestCopy(QualType type, RValue src); void EmitCopy(QualType type, const AggValueSlot &dest, const AggValueSlot &src); @@ -246,6 +253,13 @@ bool AggExprEmitter::TypeRequiresGCollection(QualType T) { /// directly into the return value slot. Otherwise, a final move /// will be performed. void AggExprEmitter::EmitMoveFromReturnSlot(const Expr *E, RValue src) { + // Push destructor if the result is ignored and the type is a C struct that + // is non-trivial to destroy. + QualType Ty = E->getType(); + if (Dest.isIgnored() && + Ty.isDestructedType() == QualType::DK_nontrivial_c_struct) + CGF.pushDestroy(Ty.isDestructedType(), src.getAggregateAddress(), Ty); + if (shouldUseDestForReturnSlot()) { // Logically, Dest.getAddr() should equal Src.getAggregateAddr(). // The possibility of undef rvalues complicates that a lot, @@ -262,11 +276,12 @@ void AggExprEmitter::EmitMoveFromReturnSlot(const Expr *E, RValue src) { void AggExprEmitter::EmitFinalDestCopy(QualType type, RValue src) { assert(src.isAggregate() && "value must be aggregate value!"); LValue srcLV = CGF.MakeAddrLValue(src.getAggregateAddress(), type); - EmitFinalDestCopy(type, srcLV); + EmitFinalDestCopy(type, srcLV, EVK_RValue); } /// EmitFinalDestCopy - Perform the final copy to DestPtr, if desired. -void AggExprEmitter::EmitFinalDestCopy(QualType type, const LValue &src) { +void AggExprEmitter::EmitFinalDestCopy(QualType type, const LValue &src, + ExprValueKind SrcValueKind) { // If Dest is ignored, then we're evaluating an aggregate expression // in a context that doesn't care about the result. Note that loads // from volatile l-values force the existence of a non-ignored @@ -274,6 +289,28 @@ void AggExprEmitter::EmitFinalDestCopy(QualType type, const LValue &src) { if (Dest.isIgnored()) return; + // Copy non-trivial C structs here. + LValue DstLV = CGF.MakeAddrLValue( + Dest.getAddress(), Dest.isVolatile() ? type.withVolatile() : type); + + if (SrcValueKind == EVK_RValue) { + if (type.isNonTrivialToPrimitiveDestructiveMove() == QualType::PCK_Struct) { + if (Dest.isPotentiallyAliased()) + CGF.callCStructMoveAssignmentOperator(DstLV, src); + else + CGF.callCStructMoveConstructor(DstLV, src); + return; + } + } else { + if (type.isNonTrivialToPrimitiveCopy() == QualType::PCK_Struct) { + if (Dest.isPotentiallyAliased()) + CGF.callCStructCopyAssignmentOperator(DstLV, src); + else + CGF.callCStructCopyConstructor(DstLV, src); + return; + } + } + AggValueSlot srcAgg = AggValueSlot::forLValue(src, AggValueSlot::IsDestructed, needsGC(type), AggValueSlot::IsAliased); -- cgit v1.2.3