]> granicus.if.org Git - clang/commitdiff
When performing a derived-to-base cast on the right-hand side of the
authorDouglas Gregor <dgregor@apple.com>
Tue, 6 Sep 2011 16:26:56 +0000 (16:26 +0000)
committerDouglas Gregor <dgregor@apple.com>
Tue, 6 Sep 2011 16:26:56 +0000 (16:26 +0000)
synthesized move assignment within an implicitly-defined move
assignment operator, be sure to treat the derived-to-base cast as an
xvalue (rather than an lvalue). Otherwise, we'll end up getting the
wrong constructor.

Optimize a direct call to a trivial move assignment operator to an
aggregate copy, as we do for trivial copy assignment operators, and
update the the assertion in CodeGenFunction::EmitAggregateCopy() to
cope with this optimization.

Fixes PR10860.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@139143 91177308-0d34-0410-b5e6-96231b3b80d8

lib/CodeGen/CGExprAgg.cpp
lib/CodeGen/CGExprCXX.cpp
lib/Sema/SemaDeclCXX.cpp
test/CXX/special/class.copy/implicit-move-def.cpp

index b68e3388d6fb5bf6b24088237254118b7584b193..bd788d0b0a3b9c7060a2b3d1bcb428f7efcb7edf 100644 (file)
@@ -1069,7 +1069,9 @@ void CodeGenFunction::EmitAggregateCopy(llvm::Value *DestPtr,
     if (const RecordType *RT = Ty->getAs<RecordType>()) {
       CXXRecordDecl *Record = cast<CXXRecordDecl>(RT->getDecl());
       assert((Record->hasTrivialCopyConstructor() || 
-              Record->hasTrivialCopyAssignment()) &&
+              Record->hasTrivialCopyAssignment() ||
+              Record->hasTrivialMoveConstructor() ||
+              Record->hasTrivialMoveAssignment()) &&
              "Trying to aggregate-copy a type without a trivial copy "
              "constructor or assignment operator");
       // Ignore empty classes in C++.
index acc9a2b03608913966549a4f256cdef8d358ad2f..9f21abd20c1e00587d3279e31328a00d308219b2 100644 (file)
@@ -334,16 +334,12 @@ CodeGenFunction::EmitCXXOperatorMemberCallExpr(const CXXOperatorCallExpr *E,
   LValue LV = EmitLValue(E->getArg(0));
   llvm::Value *This = LV.getAddress();
 
-  if (MD->isCopyAssignmentOperator()) {
-    const CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(MD->getDeclContext());
-    if (ClassDecl->hasTrivialCopyAssignment()) {
-      assert(!ClassDecl->hasUserDeclaredCopyAssignment() &&
-             "EmitCXXOperatorMemberCallExpr - user declared copy assignment");
-      llvm::Value *Src = EmitLValue(E->getArg(1)).getAddress();
-      QualType Ty = E->getType();
-      EmitAggregateCopy(This, Src, Ty);
-      return RValue::get(This);
-    }
+  if ((MD->isCopyAssignmentOperator() || MD->isMoveAssignmentOperator()) &&
+      MD->isTrivial()) {
+    llvm::Value *Src = EmitLValue(E->getArg(1)).getAddress();
+    QualType Ty = E->getType();
+    EmitAggregateCopy(This, Src, Ty);
+    return RValue::get(This);
   }
 
   llvm::Value *Callee = EmitCXXOperatorMemberCallee(E, MD, This);
index 04868cee5763e1d8cf6a64ed80b005f9cc622a7b..d7db42494f5a213edad6e902475f2b67901e944e 100644 (file)
@@ -7847,7 +7847,7 @@ void Sema::DefineImplicitMoveAssignment(SourceLocation CurrentLocation,
     // appropriately-qualified base type.
     Expr *From = OtherRef;
     From = ImpCastExprToType(From, BaseType, CK_UncheckedDerivedToBase,
-                             VK_RValue, &BasePath).take();
+                             VK_XValue, &BasePath).take();
 
     // Dereference "this".
     ExprResult To = CreateBuiltinUnaryOp(Loc, UO_Deref, This);
index 1f91945b4a9f76c3fde96516122606e53de39cfb..fde80fbd7de716c9c0fe50c2faae15872e15d53f 100644 (file)
@@ -61,9 +61,25 @@ struct I {
   unsigned var[1];
 };
 
+// CHECK: define void @_Z1hv() nounwind {
 void h() {
   I i;
+  // CHECK: call void @llvm.memcpy.
   i = I();
+  // CHECK-NEXT: ret void
+}
+
+// PR10860
+struct Empty { };
+struct VirtualWithEmptyBase : Empty {
+  virtual void f();
+};
+
+// CHECK: define void @_Z25move_VirtualWithEmptyBaseR20VirtualWithEmptyBaseS0_
+void move_VirtualWithEmptyBase(VirtualWithEmptyBase &x, VirtualWithEmptyBase &y) {
+  // CHECK: call {{.*}} @_ZN20VirtualWithEmptyBaseaSEOS_
+  x = static_cast<VirtualWithEmptyBase&&>(y);
+  // CHECK-NEXT: ret void
 }
 
 // move assignment ops
@@ -76,8 +92,12 @@ void h() {
 // CHECK-ASSIGN: br i1
 // CHECK-ASSIGN: call {{.*}} @_ZN1AaSEOS_
 
-// CHECK-ASSIGN: define linkonce_odr {{.*}} @_ZN1IaSEOS_
-// call void @llvm.memcpy.
+// VirtualWithEmptyBase move assignment operatpr
+// CHECK-ASSIGN: define linkonce_odr {{.*}} @_ZN20VirtualWithEmptyBaseaSEOS_
+// CHECK-ASSIGN: store
+// CHECK-ASSIGN-NEXT: store
+// CHECK-NOT: call
+// CHECK: ret
 
 // CHECK-ASSIGN: define linkonce_odr {{.*}} @_ZN1CaSEOS_
 // CHECK-ASSIGN: call {{.*}} @_ZN1AaSEOS_