From: Fariborz Jahanian Date: Fri, 7 Aug 2009 20:22:40 +0000 (+0000) Subject: More synthesis of copy constructors. Work in progress. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=97a937532c24a8ea44317d4fdee26d9701a1e83c;p=clang More synthesis of copy constructors. Work in progress. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@78402 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/CodeGen/CGCXX.cpp b/lib/CodeGen/CGCXX.cpp index d849336ff6..cb6a6f8271 100644 --- a/lib/CodeGen/CGCXX.cpp +++ b/lib/CodeGen/CGCXX.cpp @@ -652,6 +652,53 @@ llvm::Value *CodeGenFunction::GenerateVtable(const CXXRecordDecl *RD) { return vtable; } +/// EmitCopyCtorBody - This routine implicitly defines body of a copy +/// constructor, in accordance with section 12.8 (p7 and p8) of C++03 +/// The implicitly-defined copy constructor for class X performs a memberwise +/// copy of its subobjects. The order of copying is the same as the order +/// of initialization of bases and members in a user-defined constructor +/// Each subobject is copied in the manner appropriate to its type: +/// if the subobject is of class type, the copy constructor for the class is +/// used; +/// if the subobject is an array, each element is copied, in the manner +/// appropriate to the element type; +/// if the subobject is of scalar type, the built-in assignment operator is +/// used. +/// Virtual base class subobjects shall be copied only once by the +/// implicitly-defined copy constructor + +void CodeGenFunction::EmitCopyCtorBody(const CXXConstructorDecl *CD) { + const CXXRecordDecl *ClassDecl = cast(CD->getDeclContext()); + assert(!ClassDecl->hasUserDeclaredCopyConstructor() && + "EmitCopyCtorBody - copy constructor has definition already"); + + for (CXXRecordDecl::base_class_const_iterator Base = ClassDecl->bases_begin(); + Base != ClassDecl->bases_end(); ++Base) { + // FIXME. copy constrution of virtual base NYI + if (Base->isVirtual()) + continue; +#if 0 + unsigned TypeQuals; + CXXRecordDecl *BaseClassDecl + = cast(Base->getType()->getAs()->getDecl()); + if (CXXConstructorDecl *BaseCopyCtor = + BaseClassDecl->getCopyConstructor(getContext(), TypeQuals)) { + + llvm::Value *LoadOfThis = LoadCXXThis(); + llvm::Value *V = AddressCXXOfBaseClass(LoadOfThis, ClassDecl, + BaseClassDecl); + EmitCXXConstructorCall(BaseCopyCtor, + Ctor_Complete, V, + Member->const_arg_begin(), + Member->const_arg_end()); + + } +#endif + } + +} + + /// EmitCtorPrologue - This routine generates necessary code to initialize /// base classes and non-static data members belonging to this constructor. void CodeGenFunction::EmitCtorPrologue(const CXXConstructorDecl *CD) { diff --git a/lib/CodeGen/CodeGenFunction.cpp b/lib/CodeGen/CodeGenFunction.cpp index 0f155ec648..7c9b3af8d3 100644 --- a/lib/CodeGen/CodeGenFunction.cpp +++ b/lib/CodeGen/CodeGenFunction.cpp @@ -247,6 +247,7 @@ void CodeGenFunction::GenerateCode(const FunctionDecl *FD, assert(!ClassDecl->hasUserDeclaredCopyConstructor() && "bogus constructor is being synthesize"); StartFunction(FD, FD->getResultType(), Fn, Args, SourceLocation()); + EmitCopyCtorBody(CD); FinishFunction(); } else { diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h index 63632f5f40..b512d3670b 100644 --- a/lib/CodeGen/CodeGenFunction.h +++ b/lib/CodeGen/CodeGenFunction.h @@ -369,6 +369,8 @@ public: void EmitCtorPrologue(const CXXConstructorDecl *CD); + void EmitCopyCtorBody(const CXXConstructorDecl *CD); + /// EmitDtorEpilogue - Emit all code that comes at the end of class's /// destructor. This is to call destructors on members and base classes /// in reverse order of their construction. diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp index 8e53651c8e..e1cf13c72d 100644 --- a/lib/CodeGen/CodeGenModule.cpp +++ b/lib/CodeGen/CodeGenModule.cpp @@ -645,10 +645,8 @@ llvm::Constant *CodeGenModule::GetOrCreateLLVMFunction(const char *MangledName, else if (const CXXConstructorDecl *CD = dyn_cast(FD)) { const CXXRecordDecl *ClassDecl = cast(CD->getDeclContext()); - if (CD->isCopyConstructor(getContext())) { - if (!ClassDecl->hasUserDeclaredCopyConstructor()) - DeferredDeclsToEmit.push_back(D); - } + if (CD->isCopyConstructor(getContext())) + DeferredCopyConstructorToEmit(D); else if (!ClassDecl->hasUserDeclaredConstructor()) DeferredDeclsToEmit.push_back(D); } @@ -674,6 +672,47 @@ llvm::Constant *CodeGenModule::GetOrCreateLLVMFunction(const char *MangledName, return F; } +/// Defer definition of copy constructor(s) which need be implicitly defined. +void CodeGenModule::DeferredCopyConstructorToEmit(GlobalDecl CopyCtorDecl) { + const CXXConstructorDecl *CD = + cast(CopyCtorDecl.getDecl()); + const CXXRecordDecl *ClassDecl = cast(CD->getDeclContext()); + if (ClassDecl->hasTrivialCopyConstructor() || + ClassDecl->hasUserDeclaredCopyConstructor()) + return; + + // First make sure all direct base classes and virtual bases and non-static + // data mebers which need to have their copy constructors implicitly defined + // are defined. 12.8.p7 + for (CXXRecordDecl::base_class_const_iterator Base = ClassDecl->bases_begin(); + Base != ClassDecl->bases_end(); ++Base) { + unsigned TypeQuals; + CXXRecordDecl *BaseClassDecl + = cast(Base->getType()->getAs()->getDecl()); + if (CXXConstructorDecl *BaseCopyCtor = + BaseClassDecl->getCopyConstructor(Context, TypeQuals)) + GetAddrOfCXXConstructor(BaseCopyCtor, Ctor_Complete); + } + + for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(), + FieldEnd = ClassDecl->field_end(); + Field != FieldEnd; ++Field) { + unsigned TypeQuals; + QualType FieldType = Context.getCanonicalType((*Field)->getType()); + if (const ArrayType *Array = Context.getAsArrayType(FieldType)) + FieldType = Array->getElementType(); + if (const RecordType *FieldClassType = FieldType->getAs()) { + CXXRecordDecl *FieldClassDecl + = cast(FieldClassType->getDecl()); + if (CXXConstructorDecl *FieldCopyCtor = + FieldClassDecl->getCopyConstructor(Context, TypeQuals)) + GetAddrOfCXXConstructor(FieldCopyCtor, Ctor_Complete); + } + } + DeferredDeclsToEmit.push_back(CopyCtorDecl); + +} + /// GetAddrOfFunction - Return the address of the given function. If Ty is /// non-null, then this function will use the specified type if it has to /// create it (this occurs when we see a definition of the function). diff --git a/lib/CodeGen/CodeGenModule.h b/lib/CodeGen/CodeGenModule.h index 7c1108e801..3aa015a99f 100644 --- a/lib/CodeGen/CodeGenModule.h +++ b/lib/CodeGen/CodeGenModule.h @@ -393,6 +393,7 @@ private: llvm::Constant *GetOrCreateLLVMGlobal(const char *MangledName, const llvm::PointerType *PTy, const VarDecl *D); + void DeferredCopyConstructorToEmit(GlobalDecl D); /// SetCommonAttributes - Set attributes which are common to any /// form of a global definition (alias, Objective-C method,