From d18dc4d8975eff2593f61ca51a6b7c4e3386a751 Mon Sep 17 00:00:00 2001 From: Saleem Abdulrasool Date: Fri, 24 Oct 2014 20:23:43 +0000 Subject: [PATCH] CodeGen: correct materialize temporary aggregates in ARC mode Avoid an assertion when materializing a lifetime type aggregate temporary. When performing CodeGen for ObjC++, we could generate a lifetime-only aggregate temporary by using an initializer list (which is effectively an array). We would reach through the temporary expression, fishing out the inner expression. If this expression was a lifetime expression, we would attempt to emit this as a scalar. This would eventually result in an assertion as the emission would eventually assert that the expression being emitted has a scalar evaluation kind. Add a case to handle the aggregate expressions. Use the EmitAggExpr to emit the aggregate expression rather than the EmitScalarInit. Addresses PR21347. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@220590 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/CodeGen/CGExpr.cpp | 20 ++++++-- test/CodeGenObjCXX/arc-cxx11-init-list.mm | 57 +++++++++++++++++++++++ 2 files changed, 74 insertions(+), 3 deletions(-) create mode 100644 test/CodeGenObjCXX/arc-cxx11-init-list.mm diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp index cabedc3857..08ee37b435 100644 --- a/lib/CodeGen/CGExpr.cpp +++ b/lib/CodeGen/CGExpr.cpp @@ -210,7 +210,6 @@ pushTemporaryCleanup(CodeGenFunction &CGF, const MaterializeTemporaryExpr *M, case SD_Automatic: case SD_FullExpression: - assert(!ObjCARCReferenceLifetimeType->isArrayType()); CodeGenFunction::Destroyer *Destroy; CleanupKind CleanupKind; if (Lifetime == Qualifiers::OCL_Strong) { @@ -317,11 +316,12 @@ LValue CodeGenFunction:: EmitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *M) { const Expr *E = M->GetTemporaryExpr(); + // FIXME: ideally this would use EmitAnyExprToMem, however, we cannot do so + // as that will cause the lifetime adjustment to be lost for ARC if (getLangOpts().ObjCAutoRefCount && M->getType()->isObjCLifetimeType() && M->getType().getObjCLifetime() != Qualifiers::OCL_None && M->getType().getObjCLifetime() != Qualifiers::OCL_ExplicitNone) { - // FIXME: Fold this into the general case below. llvm::Value *Object = createReferenceTemporary(*this, M, E); LValue RefTempDst = MakeAddrLValue(Object, M->getType()); @@ -332,7 +332,21 @@ EmitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *M) { Var->setInitializer(CGM.EmitNullConstant(E->getType())); } - EmitScalarInit(E, M->getExtendingDecl(), RefTempDst, false); + switch (getEvaluationKind(E->getType())) { + default: llvm_unreachable("expected scalar or aggregate expression"); + case TEK_Scalar: + EmitScalarInit(E, M->getExtendingDecl(), RefTempDst, false); + break; + case TEK_Aggregate: { + CharUnits Alignment = getContext().getTypeAlignInChars(E->getType()); + EmitAggExpr(E, AggValueSlot::forAddr(Object, Alignment, + E->getType().getQualifiers(), + AggValueSlot::IsDestructed, + AggValueSlot::DoesNotNeedGCBarriers, + AggValueSlot::IsNotAliased)); + break; + } + } pushTemporaryCleanup(*this, M, E, Object); return RefTempDst; diff --git a/test/CodeGenObjCXX/arc-cxx11-init-list.mm b/test/CodeGenObjCXX/arc-cxx11-init-list.mm new file mode 100644 index 0000000000..c3df97d00e --- /dev/null +++ b/test/CodeGenObjCXX/arc-cxx11-init-list.mm @@ -0,0 +1,57 @@ +// RUN: %clang_cc1 -triple armv7-ios5.0 -std=c++11 -fobjc-arc -Os -emit-llvm -o - %s \ +// RUN: | FileCheck %s + +typedef __SIZE_TYPE__ size_t; + +namespace std { +template +class initializer_list { + const _Ep* __begin_; + size_t __size_; + + initializer_list(const _Ep* __b, size_t __s); +}; +} + +@interface I ++ (instancetype) new; +@end + +void function(std::initializer_list); + +extern "C" void single() { function({ [I new] }); } + +// CHECK: [[INSTANCE:%.*]] = {{.*}} call {{.*}} i8* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to i8* (i8*, i8*)*)(i8* {{.*}}, i8* {{.*}}) +// CHECK-NEXT: [[CAST:%.*]] = bitcast i8* [[INSTANCE]] to %0* +// CHECK-NEXT: store %0* [[CAST]], %0** [[ARRAY:%.*]], +// CHECK: call {{.*}} void @objc_release(i8* {{.*}}) + +extern "C" void multiple() { function({ [I new], [I new] }); } + +// CHECK: [[INSTANCE:%.*]] = {{.*}} call {{.*}} i8* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to i8* (i8*, i8*)*)(i8* {{.*}}, i8* {{.*}}) +// CHECK-NEXT: [[CAST:%.*]] = bitcast i8* [[INSTANCE]] to %0* +// CHECK-NEXT: store %0* [[CAST]], %0** [[ARRAY:%.*]], +// CHECK: call {{.*}} void @objc_release(i8* {{.*}}) +// CHECK-NEXT: icmp eq + +void external(); + +extern "C" void extended() { + const auto && temporary = { [I new] }; + external(); +} + +// CHECK: [[INSTANCE:%.*]] = {{.*}} call {{.*}} i8* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to i8* (i8*, i8*)*)(i8* {{.*}}, i8* {{.*}}) +// CHECK-NEXT: [[CAST:%.*]] = bitcast i8* [[INSTANCE:%.*]] to {{.*}}* +// CHECK-NEXT: store {{.*}}* [[CAST]], {{.*}}** {{.*}} +// CHECK: {{.*}} call {{.*}} void @_Z8externalv() +// CHECK: {{.*}} call {{.*}} void @objc_release(i8* {{.*}}) + +std::initializer_list il = { [I new] }; + +// CHECK: [[POOL:%.*]] = {{.*}} call {{.*}} i8* @objc_autoreleasePoolPush() +// CHECK: [[INSTANCE:%.*]] = {{.*}} call {{.*}} i8* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to i8* (i8*, i8*)*)(i8* {{.*}}, i8* {{.*}}) +// CHECK-NEXT: [[CAST:%.*]] = bitcast i8* [[INSTANCE]] to [[POOL]]* +// CHECK-NEXT: store [[POOL]]* [[CAST]], [[POOL]]** getelementptr inbounds ([1 x [[POOL]]*]* @_ZGR2il_, i32 0, i32 0) +// CHECK: {{.*}} call {{.*}} void @objc_autoreleasePoolPop(i8* [[POOL]]) + -- 2.50.1