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
  • [PATCH] D39562: [CodeGen][O... Akira Hatanaka via Phabricator via cfe-commits

Reply via email to