From: Douglas Gregor Date: Tue, 6 Sep 2011 16:26:56 +0000 (+0000) Subject: When performing a derived-to-base cast on the right-hand side of the X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=b2b5658a8e4ad566303ec98caceaa3485e7635f7;p=clang When performing a derived-to-base cast on the right-hand side of the 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 --- diff --git a/lib/CodeGen/CGExprAgg.cpp b/lib/CodeGen/CGExprAgg.cpp index b68e3388d6..bd788d0b0a 100644 --- a/lib/CodeGen/CGExprAgg.cpp +++ b/lib/CodeGen/CGExprAgg.cpp @@ -1069,7 +1069,9 @@ void CodeGenFunction::EmitAggregateCopy(llvm::Value *DestPtr, if (const RecordType *RT = Ty->getAs()) { CXXRecordDecl *Record = cast(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++. diff --git a/lib/CodeGen/CGExprCXX.cpp b/lib/CodeGen/CGExprCXX.cpp index acc9a2b036..9f21abd20c 100644 --- a/lib/CodeGen/CGExprCXX.cpp +++ b/lib/CodeGen/CGExprCXX.cpp @@ -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(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); diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 04868cee57..d7db42494f 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -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); diff --git a/test/CXX/special/class.copy/implicit-move-def.cpp b/test/CXX/special/class.copy/implicit-move-def.cpp index 1f91945b4a..fde80fbd7d 100644 --- a/test/CXX/special/class.copy/implicit-move-def.cpp +++ b/test/CXX/special/class.copy/implicit-move-def.cpp @@ -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(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_