ahatanak created this revision. Herald added subscribers: kristof.beyls, aemerson.
The assertion failure occurs when a setter is called using the dot syntax to set a property of a class type that doesn't have trivial copy/move constructors or assignment operators. It happens only when clang is compiling for c++1z and copy elision allows avoiding copying a temporary to the argument passed to the setter method in Sema. For example: struct S2 { id f1; }; @interface C @property S2 f; @end @implementation C @end void test(C *c) { c.f = S2(); } When IRGen visits the ObjCMessageExpr for the call to the setter, it tries to emit a copy of an S2 object that has been constructed (this happens in AggExprEmitter::VisitOpaqueValueExpr) and the assertion in CodeGenFunction::EmitAggregateCopy fails because S2 doesn't have the trivial special functions needed to do the copy. This is the AST of the ObjCMessageExpr: `-ObjCMessageExpr 0x7fe03c06b730 <col:5> 'void' selector=setF: | |-OpaqueValueExpr 0x7fe03c06b698 <col:3> 'C *' | | `-ImplicitCastExpr 0x7fe03c06b5e0 <col:3> 'C *' <LValueToRValue> | | `-DeclRefExpr 0x7fe03c06b5b8 <col:3> 'C *__strong' lvalue ParmVar 0x7fe03c06b408 'c' 'C *__strong' | `-OpaqueValueExpr 0x7fe03c06b6e8 <col:9, col:12> 'struct S2' | `-CXXBindTemporaryExpr 0x7fe03c06b678 <col:9, col:12> 'struct S2' (CXXTemporary 0x7fe03c06b670) | `-CXXTemporaryObjectExpr 0x7fe03c06b638 <col:9, col:12> 'struct S2' 'void (void)' To avoid the crash, I modified CodeGenFunction::EmitAnyExprToTemp to return the value for the OpaqueValueExpr (which must have already been evaluated when it's visited, I think) so that it doesn't have to call EmitAggregateCopy to make a copy. I'm actually unsure whether we should fix Sema and change the AST representation or fix IRGen as I did in this patch. I'm open to suggestions if anyone has a better idea to fix the crash. https://reviews.llvm.org/D39562 Files: lib/CodeGen/CGExpr.cpp test/CodeGenObjCXX/property-dot-copy-elision.mm test/CodeGenObjCXX/property-objects.mm
Index: test/CodeGenObjCXX/property-objects.mm =================================================================== --- test/CodeGenObjCXX/property-objects.mm +++ test/CodeGenObjCXX/property-objects.mm @@ -125,8 +125,6 @@ // CHECK-NEXT: [[T1:%.*]] = sext i32 [[T0]] to i64 // CHECK-NEXT: store i64 [[T1]], i64* [[X]], align 8 // CHECK-NOT: call -// CHECK: call void @llvm.memcpy -// CHECK-NOT: call // CHECK: call void bitcast {{.*}} @objc_msgSend // CHECK-NOT: call // CHECK: ret void @@ -147,8 +145,6 @@ // CHECK-NOT: call // CHECK: store i64 [[T0]], // CHECK-NOT: call -// CHECK: call void @llvm.memcpy -// CHECK-NOT: call // CHECK: call void bitcast {{.*}} @objc_msgSend // CHECK-NOT: call // CHECK: ret void @@ -168,8 +164,6 @@ // CHECK-NOT: call // CHECK: store i64 [[T0]], // CHECK-NOT: call -// CHECK: call void @llvm.memcpy -// CHECK-NOT: call // CHECK: call void bitcast {{.*}} @objc_msgSend // CHECK-NOT: call // CHECK: ret void @@ -216,8 +210,6 @@ // CHECK-NOT: call // CHECK: store i32 [[T0]], // CHECK-NOT: call -// CHECK: call void @llvm.memcpy -// CHECK-NOT: call // CHECK: call void bitcast {{.*}} @objc_msgSend // CHECK-NOT: call // CHECK: ret void Index: test/CodeGenObjCXX/property-dot-copy-elision.mm =================================================================== --- /dev/null +++ test/CodeGenObjCXX/property-dot-copy-elision.mm @@ -0,0 +1,39 @@ +// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -std=c++1z -fobjc-arc -o - %s | FileCheck %s + +struct S0 { + id f; +}; + +struct S1 { + S1(); + S1(S0); + id f; +}; + +@interface C +@property S1 f; +@end +@implementation C +@end + +// CHECK-LABEL: define void @_Z5test0P1C( +// CHECK: %{{.*}} = alloca % +// CHECK: %[[TEMP_LVALUE:.*]] = alloca %[[STRUCT_S0:.*]], align +// CHECK: %[[AGG_TMP:.*]] = alloca %[[STRUCT_S1:.*]], align +// CHECK: call void @_ZN2S0C1Ev(%[[STRUCT_S0]]* %[[TEMP_LVALUE]]) +// CHECK: call void @_ZN2S1C1E2S0(%[[STRUCT_S1]]* %[[AGG_TMP]], %[[STRUCT_S0]]* %[[TEMP_LVALUE]]) +// CHECK: call void bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to void (i8*, i8*, %[[STRUCT_S1]]*)*)(i8* %{{.*}}, i8* %{{.*}}, %[[STRUCT_S1]]* %[[AGG_TMP]]) + +void test0(C *c) { + c.f = S0(); +} + +// CHECK: define void @_Z5test1P1C( +// CHECK: %{{.*}} = alloca % +// CHECK: %[[TEMP_LVALUE:.*]] = alloca %[[STRUCT_S1:.*]], align +// CHECK: call void @_ZN2S1C1Ev(%[[STRUCT_S1]]* %[[TEMP_LVALUE]]) +// CHECK: call void bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to void (i8*, i8*, %[[STRUCT_S1]]*)*)(i8* %{{.*}}, i8* %{{.*}}, %[[STRUCT_S1]]* %[[TEMP_LVALUE]]) + +void test1(C *c) { + c.f = S1(); +} Index: lib/CodeGen/CGExpr.cpp =================================================================== --- lib/CodeGen/CGExpr.cpp +++ lib/CodeGen/CGExpr.cpp @@ -192,8 +192,12 @@ RValue CodeGenFunction::EmitAnyExprToTemp(const Expr *E) { AggValueSlot AggSlot = AggValueSlot::ignored(); - if (hasAggregateEvaluationKind(E->getType())) + if (hasAggregateEvaluationKind(E->getType())) { + if (const auto *OVE = dyn_cast<OpaqueValueExpr>(E)) + return getOpaqueLValueMapping(OVE).asAggregateRValue(); AggSlot = CreateAggTemp(E->getType(), "agg.tmp"); + } + return EmitAnyExpr(E, AggSlot); }
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits