r220590 - CodeGen: correct materialize temporary aggregates in ARC mode

Saleem Abdulrasool compnerd at compnerd.org
Fri Oct 24 13:23:44 PDT 2014


Author: compnerd
Date: Fri Oct 24 15:23:43 2014
New Revision: 220590

URL: http://llvm.org/viewvc/llvm-project?rev=220590&view=rev
Log:
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.

Added:
    cfe/trunk/test/CodeGenObjCXX/arc-cxx11-init-list.mm
Modified:
    cfe/trunk/lib/CodeGen/CGExpr.cpp

Modified: cfe/trunk/lib/CodeGen/CGExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExpr.cpp?rev=220590&r1=220589&r2=220590&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGExpr.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGExpr.cpp Fri Oct 24 15:23:43 2014
@@ -210,7 +210,6 @@ pushTemporaryCleanup(CodeGenFunction &CG
 
       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 Mater
       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;

Added: cfe/trunk/test/CodeGenObjCXX/arc-cxx11-init-list.mm
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenObjCXX/arc-cxx11-init-list.mm?rev=220590&view=auto
==============================================================================
--- cfe/trunk/test/CodeGenObjCXX/arc-cxx11-init-list.mm (added)
+++ cfe/trunk/test/CodeGenObjCXX/arc-cxx11-init-list.mm Fri Oct 24 15:23:43 2014
@@ -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 <typename _Ep>
+class initializer_list {
+  const _Ep* __begin_;
+  size_t __size_;
+
+  initializer_list(const _Ep* __b, size_t __s);
+};
+}
+
+ at interface I
++ (instancetype) new;
+ at end
+
+void function(std::initializer_list<I *>);
+
+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<I *> 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]])
+





More information about the cfe-commits mailing list