]> granicus.if.org Git - clang/commitdiff
Simplify and fix up the handling of implicit constructors, copy assignment
authorEli Friedman <eli.friedman@gmail.com>
Thu, 26 Nov 2009 07:40:08 +0000 (07:40 +0000)
committerEli Friedman <eli.friedman@gmail.com>
Thu, 26 Nov 2009 07:40:08 +0000 (07:40 +0000)
operators, and destructors.  Avoids generating declarations/definitions of
trivial constructors/destructors, and makes sure the trivial copy assignment
operator is generated when necessary.

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

lib/CodeGen/CGCXX.cpp
lib/CodeGen/CodeGenModule.cpp
lib/CodeGen/CodeGenModule.h
test/CodeGenCXX/copy-assign-synthesis-2.cpp [new file with mode: 0644]

index ceff7508b25bdc8df0f747bfb60f01a2ab93cb1c..3b97fcb11715eca281dc86690e5a4d52d2d514ce 100644 (file)
@@ -196,11 +196,6 @@ RValue CodeGenFunction::EmitCXXMemberCall(const CXXMethodDecl *MD,
   assert(MD->isInstance() &&
          "Trying to emit a member call expr on a static method!");
 
-  // A call to a trivial destructor requires no code generation.
-  if (const CXXDestructorDecl *Destructor = dyn_cast<CXXDestructorDecl>(MD))
-    if (Destructor->isTrivial())
-      return RValue::get(0);
-
   const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>();
 
   CallArgList Args;
@@ -251,6 +246,7 @@ RValue CodeGenFunction::EmitCXXMemberCallExpr(const CXXMemberCallExpr *CE) {
       
   const MemberExpr *ME = cast<MemberExpr>(CE->getCallee());
   const CXXMethodDecl *MD = cast<CXXMethodDecl>(ME->getMemberDecl());
+  const CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(MD->getDeclContext());
 
   if (MD->isStatic()) {
     // The method is static, emit it as we would a regular call.
@@ -283,6 +279,8 @@ RValue CodeGenFunction::EmitCXXMemberCallExpr(const CXXMemberCallExpr *CE) {
   llvm::Value *Callee;
   if (const CXXDestructorDecl *Destructor
              = dyn_cast<CXXDestructorDecl>(MD)) {
+    if (Destructor->isTrivial())
+      return RValue::get(0);
     if (MD->isVirtual() && !ME->hasQualifier() && 
         !canDevirtualizeMemberFunctionCalls(ME->getBase())) {
       Callee = BuildVirtualCall(Destructor, Dtor_Complete, This, Ty); 
@@ -684,6 +682,10 @@ CodeGenFunction::EmitCXXConstructorCall(const CXXConstructorDecl *D,
       EmitAggregateCopy(This, Src, Ty);
       return;
     }
+  } else if (D->isTrivial()) {
+    // FIXME: Track down why we're trying to generate calls to the trivial
+    // default constructor!
+    return;
   }
 
   llvm::Value *Callee = CGM.GetAddrOfCXXConstructor(D, Type);
@@ -1327,6 +1329,7 @@ CodeGenFunction::SynthesizeDefaultConstructor(const CXXConstructorDecl *Ctor,
                                               CXXCtorType Type,
                                               llvm::Function *Fn,
                                               const FunctionArgList &Args) {
+  assert(!Ctor->isTrivial() && "shouldn't need to generate trivial ctor");
   StartFunction(GlobalDecl(Ctor, Type), Ctor->getResultType(), Fn, Args, 
                 SourceLocation());
   EmitCtorPrologue(Ctor, Type);
@@ -1356,6 +1359,7 @@ CodeGenFunction::SynthesizeCXXCopyConstructor(const CXXConstructorDecl *Ctor,
   const CXXRecordDecl *ClassDecl = Ctor->getParent();
   assert(!ClassDecl->hasUserDeclaredCopyConstructor() &&
       "SynthesizeCXXCopyConstructor - copy constructor has definition already");
+  assert(!Ctor->isTrivial() && "shouldn't need to generate trivial ctor");
   StartFunction(GlobalDecl(Ctor, Type), Ctor->getResultType(), Fn, Args, 
                 SourceLocation());
 
index 6aff0e7476bc31cc72be54fa0bfcce7a05a35965..bbad876575d150417e74425739eaa8fa8273beb3 100644 (file)
@@ -697,143 +697,20 @@ llvm::Constant *CodeGenModule::GetOrCreateLLVMFunction(const char *MangledName,
     // A called constructor which has no definition or declaration need be
     // synthesized.
     else if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(FD)) {
-      const CXXRecordDecl *ClassDecl =
-        cast<CXXRecordDecl>(CD->getDeclContext());
-      if (CD->isCopyConstructor(getContext()))
-        DeferredCopyConstructorToEmit(D);
-      else if (!ClassDecl->hasUserDeclaredConstructor())
+      if (CD->isImplicit())
+        DeferredDeclsToEmit.push_back(D);
+    } else if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(FD)) {
+      if (DD->isImplicit())
+        DeferredDeclsToEmit.push_back(D);
+    } else if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD)) {
+      if (MD->isCopyAssignment() && MD->isImplicit())
         DeferredDeclsToEmit.push_back(D);
     }
-    else if (isa<CXXDestructorDecl>(FD))
-       DeferredDestructorToEmit(D);
-    else if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD))
-           if (MD->isCopyAssignment())
-             DeferredCopyAssignmentToEmit(D);
   }
 
   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) {
-    CXXRecordDecl *BaseClassDecl
-      = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
-    if (CXXConstructorDecl *BaseCopyCtor =
-        BaseClassDecl->getCopyConstructor(Context, 0))
-      GetAddrOfCXXConstructor(BaseCopyCtor, Ctor_Complete);
-  }
-
-  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<RecordType>()) {
-      if ((*Field)->isAnonymousStructOrUnion())
-        continue;
-      CXXRecordDecl *FieldClassDecl
-        = cast<CXXRecordDecl>(FieldClassType->getDecl());
-      if (CXXConstructorDecl *FieldCopyCtor =
-          FieldClassDecl->getCopyConstructor(Context, 0))
-        GetAddrOfCXXConstructor(FieldCopyCtor, Ctor_Complete);
-    }
-  }
-  DeferredDeclsToEmit.push_back(CopyCtorDecl);
-}
-
-/// Defer definition of copy assignments which need be implicitly defined.
-void CodeGenModule::DeferredCopyAssignmentToEmit(GlobalDecl CopyAssignDecl) {
-  const CXXMethodDecl *CD = cast<CXXMethodDecl>(CopyAssignDecl.getDecl());
-  const CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(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<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
-    const CXXMethodDecl *MD = 0;
-    if (!BaseClassDecl->hasTrivialCopyAssignment() &&
-        !BaseClassDecl->hasUserDeclaredCopyAssignment() &&
-        BaseClassDecl->hasConstCopyAssignment(getContext(), MD))
-      GetAddrOfFunction(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<RecordType>()) {
-      if ((*Field)->isAnonymousStructOrUnion())
-        continue;
-      CXXRecordDecl *FieldClassDecl
-        = cast<CXXRecordDecl>(FieldClassType->getDecl());
-      const CXXMethodDecl *MD = 0;
-      if (!FieldClassDecl->hasTrivialCopyAssignment() &&
-          !FieldClassDecl->hasUserDeclaredCopyAssignment() &&
-          FieldClassDecl->hasConstCopyAssignment(getContext(), MD))
-          GetAddrOfFunction(MD, 0);
-    }
-  }
-  DeferredDeclsToEmit.push_back(CopyAssignDecl);
-}
-
-void CodeGenModule::DeferredDestructorToEmit(GlobalDecl DtorDecl) {
-  const CXXDestructorDecl *DD = cast<CXXDestructorDecl>(DtorDecl.getDecl());
-  const CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(DD->getDeclContext());
-  if (ClassDecl->hasTrivialDestructor() ||
-      ClassDecl->hasUserDeclaredDestructor())
-    return;
-
-  for (CXXRecordDecl::base_class_const_iterator Base = ClassDecl->bases_begin();
-       Base != ClassDecl->bases_end(); ++Base) {
-    CXXRecordDecl *BaseClassDecl
-      = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
-    if (const CXXDestructorDecl *BaseDtor =
-          BaseClassDecl->getDestructor(Context))
-      GetAddrOfCXXDestructor(BaseDtor, Dtor_Complete);
-  }
-
-  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<RecordType>()) {
-      if ((*Field)->isAnonymousStructOrUnion())
-        continue;
-      CXXRecordDecl *FieldClassDecl
-        = cast<CXXRecordDecl>(FieldClassType->getDecl());
-      if (const CXXDestructorDecl *FieldDtor =
-            FieldClassDecl->getDestructor(Context))
-        GetAddrOfCXXDestructor(FieldDtor, Dtor_Complete);
-    }
-  }
-  DeferredDeclsToEmit.push_back(DtorDecl);
-}
-
-
 /// 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 5c3e633daa29760530a966838ecddf635216d19e..78bc4ed845d8c744e71a3d256631848ea2bcd351 100644 (file)
@@ -428,9 +428,6 @@ private:
   llvm::Constant *GetOrCreateLLVMGlobal(const char *MangledName,
                                         const llvm::PointerType *PTy,
                                         const VarDecl *D);
-  void DeferredCopyConstructorToEmit(GlobalDecl D);
-  void DeferredCopyAssignmentToEmit(GlobalDecl D);
-  void DeferredDestructorToEmit(GlobalDecl D);
 
   /// SetCommonAttributes - Set attributes which are common to any
   /// form of a global definition (alias, Objective-C method,
diff --git a/test/CodeGenCXX/copy-assign-synthesis-2.cpp b/test/CodeGenCXX/copy-assign-synthesis-2.cpp
new file mode 100644 (file)
index 0000000..60d52f5
--- /dev/null
@@ -0,0 +1,4 @@
+// RUN: clang-cc -emit-llvm %s -o - | FileCheck %s
+struct A {};
+A& (A::*x)(const A&) = &A::operator=;
+// CHECK: define linkonce_odr %struct.A* @_ZN1AaSERKS_