From: Eli Friedman Date: Thu, 26 Nov 2009 07:40:08 +0000 (+0000) Subject: Simplify and fix up the handling of implicit constructors, copy assignment X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=15233e5a4d98b66b3c6cfcc4e6413ad776a79481;p=clang Simplify and fix up the handling of implicit constructors, copy assignment 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 --- diff --git a/lib/CodeGen/CGCXX.cpp b/lib/CodeGen/CGCXX.cpp index ceff7508b2..3b97fcb117 100644 --- a/lib/CodeGen/CGCXX.cpp +++ b/lib/CodeGen/CGCXX.cpp @@ -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(MD)) - if (Destructor->isTrivial()) - return RValue::get(0); - const FunctionProtoType *FPT = MD->getType()->getAs(); CallArgList Args; @@ -251,6 +246,7 @@ RValue CodeGenFunction::EmitCXXMemberCallExpr(const CXXMemberCallExpr *CE) { const MemberExpr *ME = cast(CE->getCallee()); const CXXMethodDecl *MD = cast(ME->getMemberDecl()); + const CXXRecordDecl *ClassDecl = cast(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(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()); diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp index 6aff0e7476..bbad876575 100644 --- a/lib/CodeGen/CodeGenModule.cpp +++ b/lib/CodeGen/CodeGenModule.cpp @@ -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(FD)) { - const CXXRecordDecl *ClassDecl = - cast(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(FD)) { + if (DD->isImplicit()) + DeferredDeclsToEmit.push_back(D); + } else if (const CXXMethodDecl *MD = dyn_cast(FD)) { + if (MD->isCopyAssignment() && MD->isImplicit()) DeferredDeclsToEmit.push_back(D); } - else if (isa(FD)) - DeferredDestructorToEmit(D); - else if (const CXXMethodDecl *MD = dyn_cast(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(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) { - CXXRecordDecl *BaseClassDecl - = cast(Base->getType()->getAs()->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()) { - if ((*Field)->isAnonymousStructOrUnion()) - continue; - CXXRecordDecl *FieldClassDecl - = cast(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(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->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()) { - if ((*Field)->isAnonymousStructOrUnion()) - continue; - CXXRecordDecl *FieldClassDecl - = cast(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(DtorDecl.getDecl()); - const CXXRecordDecl *ClassDecl = cast(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(Base->getType()->getAs()->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()) { - if ((*Field)->isAnonymousStructOrUnion()) - continue; - CXXRecordDecl *FieldClassDecl - = cast(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). diff --git a/lib/CodeGen/CodeGenModule.h b/lib/CodeGen/CodeGenModule.h index 5c3e633daa..78bc4ed845 100644 --- a/lib/CodeGen/CodeGenModule.h +++ b/lib/CodeGen/CodeGenModule.h @@ -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 index 0000000000..60d52f57de --- /dev/null +++ b/test/CodeGenCXX/copy-assign-synthesis-2.cpp @@ -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_