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.

llvm-svn: 89943
This commit is contained in:
Eli Friedman 2009-11-26 07:40:08 +00:00
parent 2350e0c3ba
commit 84a7e347bf
4 changed files with 20 additions and 138 deletions

View 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());

View 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).

View 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,

View File

@ -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_