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:
parent
2350e0c3ba
commit
84a7e347bf
|
@ -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());
|
||||
|
||||
|
|
|
@ -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).
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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_
|
Loading…
Reference in New Issue