From: Fariborz Jahanian Date: Thu, 13 Aug 2009 21:09:41 +0000 (+0000) Subject: Patch to force synthesis of copy assignment operator X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=ad25883a644dd6b52c7923dd128a7d05fb26213c;p=clang Patch to force synthesis of copy assignment operator function in the order according to c++03. ir-gen for copy assignment in the trivial case and the first test case. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@78938 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/CodeGen/CGCXX.cpp b/lib/CodeGen/CGCXX.cpp index 0f33c7b6fd..d1e8556160 100644 --- a/lib/CodeGen/CGCXX.cpp +++ b/lib/CodeGen/CGCXX.cpp @@ -228,6 +228,18 @@ CodeGenFunction::EmitCXXOperatorMemberCallExpr(const CXXOperatorCallExpr *E, assert(MD->isInstance() && "Trying to emit a member call expr on a static method!"); + if (MD->isCopyAssignment()) { + const CXXRecordDecl *ClassDecl = cast(MD->getDeclContext()); + if (ClassDecl->hasTrivialCopyAssignment()) { + assert(!ClassDecl->hasUserDeclaredCopyAssignment() && + "EmitCXXOperatorMemberCallExpr - user declared copy assignment"); + llvm::Value *This = EmitLValue(E->getArg(0)).getAddress(); + llvm::Value *Src = EmitLValue(E->getArg(1)).getAddress(); + QualType Ty = E->getType(); + EmitAggregateCopy(This, Src, Ty); + return RValue::get(This); + } + } const FunctionProtoType *FPT = MD->getType()->getAsFunctionProtoType(); const llvm::Type *Ty = diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp index 22737a4d93..a99bae1799 100644 --- a/lib/CodeGen/CodeGenModule.cpp +++ b/lib/CodeGen/CodeGenModule.cpp @@ -653,11 +653,9 @@ llvm::Constant *CodeGenModule::GetOrCreateLLVMFunction(const char *MangledName, else if (!ClassDecl->hasUserDeclaredConstructor()) DeferredDeclsToEmit.push_back(D); } - else - if (const CXXMethodDecl *MD = dyn_cast(FD)) - if (MD->isCopyAssignment()) { - DeferredDeclsToEmit.push_back(D); - } + else if (const CXXMethodDecl *MD = dyn_cast(FD)) + if (MD->isCopyAssignment()) + DeferredCopyAssignmentToEmit(D); } // This function doesn't have a complete type (for example, the return @@ -718,7 +716,46 @@ void CodeGenModule::DeferredCopyConstructorToEmit(GlobalDecl CopyCtorDecl) { } } DeferredDeclsToEmit.push_back(CopyCtorDecl); +} + +/// Defer definition of copy assignments which need be implicitly defined. +void CodeGenModule::DeferredCopyAssignmentToEmit(GlobalDecl CopyAssignDecl) { + const CXXMethodDecl *CD = cast(CopyAssignDecl.getDecl()); + const CXXRecordDecl *ClassDecl = cast(CD->getDeclContext()); + if (ClassDecl->hasTrivialCopyAssignment() || + ClassDecl->hasUserDeclaredCopyAssignment()) + return; + + // First make sure all direct base classes and virtual bases and non-static + // data mebers which need to have their copy assignments implicitly defined + // are defined. 12.8.p12 + for (CXXRecordDecl::base_class_const_iterator Base = ClassDecl->bases_begin(); + Base != ClassDecl->bases_end(); ++Base) { + CXXRecordDecl *BaseClassDecl + = cast(Base->getType()->getAs()->getDecl()); + const CXXMethodDecl *MD = 0; + if (BaseClassDecl->hasConstCopyAssignment(getContext(), MD)) + GetAddrOfFunction(GlobalDecl(MD), 0); + } + + for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(), + FieldEnd = ClassDecl->field_end(); + Field != FieldEnd; ++Field) { + QualType FieldType = Context.getCanonicalType((*Field)->getType()); + if (const ArrayType *Array = Context.getAsArrayType(FieldType)) + FieldType = Array->getElementType(); + if (const RecordType *FieldClassType = FieldType->getAs()) { + if ((*Field)->isAnonymousStructOrUnion()) + continue; + CXXRecordDecl *FieldClassDecl + = cast(FieldClassType->getDecl()); + const CXXMethodDecl *MD = 0; + if (FieldClassDecl->hasConstCopyAssignment(getContext(), MD)) + GetAddrOfFunction(GlobalDecl(MD), 0); + } + } + DeferredDeclsToEmit.push_back(CopyAssignDecl); } /// GetAddrOfFunction - Return the address of the given function. If Ty is diff --git a/lib/CodeGen/CodeGenModule.h b/lib/CodeGen/CodeGenModule.h index 449d29cc0d..8f69df51a5 100644 --- a/lib/CodeGen/CodeGenModule.h +++ b/lib/CodeGen/CodeGenModule.h @@ -398,6 +398,7 @@ private: const llvm::PointerType *PTy, const VarDecl *D); void DeferredCopyConstructorToEmit(GlobalDecl D); + void DeferredCopyAssignmentToEmit(GlobalDecl D); /// SetCommonAttributes - Set attributes which are common to any /// form of a global definition (alias, Objective-C method, diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 2bc70f4a52..c452c05f0f 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -3128,6 +3128,7 @@ bool Sema::CheckOverloadedOperatorDeclaration(FunctionDecl *FnDecl) { assert(isa(FnDecl) && "Overloaded = not member, but not filtered."); CXXMethodDecl *Method = cast(FnDecl); + Method->setCopyAssignment(true); Method->getParent()->addedAssignmentOperator(Context, Method); } diff --git a/test/CodeGenCXX/copy-assign-synthesis.cpp b/test/CodeGenCXX/copy-assign-synthesis.cpp new file mode 100644 index 0000000000..0677ac9bbb --- /dev/null +++ b/test/CodeGenCXX/copy-assign-synthesis.cpp @@ -0,0 +1,28 @@ +// RUN: clang-cc -emit-llvm -o %t %s && +// RUN: grep "_ZN1XaSERK1X" %t | count 0 + +extern "C" int printf(...); + +struct X { + X() : d(0.0), d1(1.1), d2(1.2), d3(1.3) {} + double d; + double d1; + double d2; + double d3; + void pr() { + printf("d = %f d1 = %f d2 = %f d3 = %f\n", d, d1,d2,d3); + } +}; + + +X srcX; +X dstX; +X dstY; + +int main() { + dstY = dstX = srcX; + srcX.pr(); + dstX.pr(); + dstY.pr(); +} +