]> granicus.if.org Git - clang/commitdiff
More synthesis of copy constructors. Work in progress.
authorFariborz Jahanian <fjahanian@apple.com>
Fri, 7 Aug 2009 20:22:40 +0000 (20:22 +0000)
committerFariborz Jahanian <fjahanian@apple.com>
Fri, 7 Aug 2009 20:22:40 +0000 (20:22 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@78402 91177308-0d34-0410-b5e6-96231b3b80d8

lib/CodeGen/CGCXX.cpp
lib/CodeGen/CodeGenFunction.cpp
lib/CodeGen/CodeGenFunction.h
lib/CodeGen/CodeGenModule.cpp
lib/CodeGen/CodeGenModule.h

index d849336ff64d96630fc742d87fce436f4b05dc80..cb6a6f8271051ed4edd0a1314ed9026e2db5196a 100644 (file)
@@ -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<CXXRecordDecl>(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<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->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) {
index 0f155ec648b138349bb776250b7976e52ee0097c..7c9b3af8d3fc3238da68c9371ade6abef82ca4db 100644 (file)
@@ -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 {
index 63632f5f409523aa0bc6987c2c5e2d219ce23c31..b512d3670ba7ee7e9a7757fc350b55c462d7c5a2 100644 (file)
@@ -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.
index 8e53651c8e68a7e74eeeb29c21813e213f69f752..e1cf13c72da38f87cc7805361deffb256aff7e46 100644 (file)
@@ -645,10 +645,8 @@ llvm::Constant *CodeGenModule::GetOrCreateLLVMFunction(const char *MangledName,
     else if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(FD)) {
       const CXXRecordDecl *ClassDecl = 
         cast<CXXRecordDecl>(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<CXXConstructorDecl>(CopyCtorDecl.getDecl());
+  const CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(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<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->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<RecordType>()) {
+      CXXRecordDecl *FieldClassDecl
+      = cast<CXXRecordDecl>(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).
index 7c1108e8014fb7024aca4096222a882ed42ca1c4..3aa015a99f7475c257aac634a223142b9d4735ab 100644 (file)
@@ -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,