When we're emitting a constructor or destructor call from a delegating

constructor, retrieve our VTT parameter directly. Fixes PR14588 /
<rdar://problem/12867962>.

llvm-svn: 174042
This commit is contained in:
Douglas Gregor 2013-01-31 05:50:40 +00:00
parent 006039cc74
commit 6153500517
5 changed files with 73 additions and 21 deletions

View File

@ -282,7 +282,8 @@ CodeGenFunction::GetAddressOfDerivedClass(llvm::Value *Value,
/// GetVTTParameter - Return the VTT parameter that should be passed to a /// GetVTTParameter - Return the VTT parameter that should be passed to a
/// base constructor/destructor with virtual bases. /// base constructor/destructor with virtual bases.
static llvm::Value *GetVTTParameter(CodeGenFunction &CGF, GlobalDecl GD, static llvm::Value *GetVTTParameter(CodeGenFunction &CGF, GlobalDecl GD,
bool ForVirtualBase) { bool ForVirtualBase,
bool Delegating) {
if (!CodeGenVTables::needsVTTParameter(GD)) { if (!CodeGenVTables::needsVTTParameter(GD)) {
// This constructor/destructor does not need a VTT parameter. // This constructor/destructor does not need a VTT parameter.
return 0; return 0;
@ -295,9 +296,12 @@ static llvm::Value *GetVTTParameter(CodeGenFunction &CGF, GlobalDecl GD,
uint64_t SubVTTIndex; uint64_t SubVTTIndex;
if (Delegating) {
// If this is a delegating constructor call, just load the VTT.
return CGF.LoadCXXVTT();
} else if (RD == Base) {
// If the record matches the base, this is the complete ctor/dtor // If the record matches the base, this is the complete ctor/dtor
// variant calling the base variant in a class with virtual bases. // variant calling the base variant in a class with virtual bases.
if (RD == Base) {
assert(!CodeGenVTables::needsVTTParameter(CGF.CurGD) && assert(!CodeGenVTables::needsVTTParameter(CGF.CurGD) &&
"doing no-op VTT offset in base dtor/ctor?"); "doing no-op VTT offset in base dtor/ctor?");
assert(!ForVirtualBase && "Can't have same class as virtual base!"); assert(!ForVirtualBase && "Can't have same class as virtual base!");
@ -344,7 +348,8 @@ namespace {
CGF.GetAddressOfDirectBaseInCompleteClass(CGF.LoadCXXThis(), CGF.GetAddressOfDirectBaseInCompleteClass(CGF.LoadCXXThis(),
DerivedClass, BaseClass, DerivedClass, BaseClass,
BaseIsVirtual); BaseIsVirtual);
CGF.EmitCXXDestructorCall(D, Dtor_Base, BaseIsVirtual, Addr); CGF.EmitCXXDestructorCall(D, Dtor_Base, BaseIsVirtual,
/*Delegating=*/false, Addr);
} }
}; };
@ -537,7 +542,7 @@ namespace {
void Emit(CodeGenFunction &CGF, Flags flags) { void Emit(CodeGenFunction &CGF, Flags flags) {
CGF.EmitCXXDestructorCall(Dtor, Dtor_Complete, /*ForVirtualBase=*/false, CGF.EmitCXXDestructorCall(Dtor, Dtor_Complete, /*ForVirtualBase=*/false,
V); /*Delegating=*/false, V);
} }
}; };
} }
@ -893,7 +898,7 @@ void CodeGenFunction::EmitDestructorBody(FunctionArgList &Args) {
if (DtorType == Dtor_Deleting) { if (DtorType == Dtor_Deleting) {
EnterDtorCleanups(Dtor, Dtor_Deleting); EnterDtorCleanups(Dtor, Dtor_Deleting);
EmitCXXDestructorCall(Dtor, Dtor_Complete, /*ForVirtualBase=*/false, EmitCXXDestructorCall(Dtor, Dtor_Complete, /*ForVirtualBase=*/false,
LoadCXXThis()); /*Delegating=*/false, LoadCXXThis());
PopCleanupBlock(); PopCleanupBlock();
return; return;
} }
@ -923,7 +928,7 @@ void CodeGenFunction::EmitDestructorBody(FunctionArgList &Args) {
if (!isTryBody && if (!isTryBody &&
CGM.getContext().getTargetInfo().getCXXABI().hasDestructorVariants()) { CGM.getContext().getTargetInfo().getCXXABI().hasDestructorVariants()) {
EmitCXXDestructorCall(Dtor, Dtor_Base, /*ForVirtualBase=*/false, EmitCXXDestructorCall(Dtor, Dtor_Base, /*ForVirtualBase=*/false,
LoadCXXThis()); /*Delegating=*/false, LoadCXXThis());
break; break;
} }
// Fallthrough: act like we're in the base variant. // Fallthrough: act like we're in the base variant.
@ -1188,7 +1193,7 @@ CodeGenFunction::EmitCXXAggrConstructorCall(const CXXConstructorDecl *ctor,
} }
EmitCXXConstructorCall(ctor, Ctor_Complete, /*ForVirtualBase=*/ false, EmitCXXConstructorCall(ctor, Ctor_Complete, /*ForVirtualBase=*/ false,
cur, argBegin, argEnd); /*Delegating=*/false, cur, argBegin, argEnd);
} }
// Go to the next element. // Go to the next element.
@ -1216,12 +1221,13 @@ void CodeGenFunction::destroyCXXObject(CodeGenFunction &CGF,
const CXXDestructorDecl *dtor = record->getDestructor(); const CXXDestructorDecl *dtor = record->getDestructor();
assert(!dtor->isTrivial()); assert(!dtor->isTrivial());
CGF.EmitCXXDestructorCall(dtor, Dtor_Complete, /*for vbase*/ false, CGF.EmitCXXDestructorCall(dtor, Dtor_Complete, /*for vbase*/ false,
addr); /*Delegating=*/false, addr);
} }
void void
CodeGenFunction::EmitCXXConstructorCall(const CXXConstructorDecl *D, CodeGenFunction::EmitCXXConstructorCall(const CXXConstructorDecl *D,
CXXCtorType Type, bool ForVirtualBase, CXXCtorType Type, bool ForVirtualBase,
bool Delegating,
llvm::Value *This, llvm::Value *This,
CallExpr::const_arg_iterator ArgBeg, CallExpr::const_arg_iterator ArgBeg,
CallExpr::const_arg_iterator ArgEnd) { CallExpr::const_arg_iterator ArgEnd) {
@ -1255,7 +1261,8 @@ CodeGenFunction::EmitCXXConstructorCall(const CXXConstructorDecl *D,
return; return;
} }
llvm::Value *VTT = GetVTTParameter(*this, GlobalDecl(D, Type), ForVirtualBase); llvm::Value *VTT = GetVTTParameter(*this, GlobalDecl(D, Type), ForVirtualBase,
Delegating);
llvm::Value *Callee = CGM.GetAddrOfCXXConstructor(D, Type); llvm::Value *Callee = CGM.GetAddrOfCXXConstructor(D, Type);
// FIXME: Provide a source location here. // FIXME: Provide a source location here.
@ -1331,7 +1338,8 @@ CodeGenFunction::EmitDelegateCXXConstructorCall(const CXXConstructorDecl *Ctor,
// vtt // vtt
if (llvm::Value *VTT = GetVTTParameter(*this, GlobalDecl(Ctor, CtorType), if (llvm::Value *VTT = GetVTTParameter(*this, GlobalDecl(Ctor, CtorType),
/*ForVirtualBase=*/false)) { /*ForVirtualBase=*/false,
/*Delegating=*/true)) {
QualType VoidPP = getContext().getPointerType(getContext().VoidPtrTy); QualType VoidPP = getContext().getPointerType(getContext().VoidPtrTy);
DelegateArgs.add(RValue::get(VTT), VoidPP); DelegateArgs.add(RValue::get(VTT), VoidPP);
@ -1365,7 +1373,7 @@ namespace {
void Emit(CodeGenFunction &CGF, Flags flags) { void Emit(CodeGenFunction &CGF, Flags flags) {
CGF.EmitCXXDestructorCall(Dtor, Type, /*ForVirtualBase=*/false, CGF.EmitCXXDestructorCall(Dtor, Type, /*ForVirtualBase=*/false,
Addr); /*Delegating=*/true, Addr);
} }
}; };
} }
@ -1401,9 +1409,10 @@ CodeGenFunction::EmitDelegatingCXXConstructorCall(const CXXConstructorDecl *Ctor
void CodeGenFunction::EmitCXXDestructorCall(const CXXDestructorDecl *DD, void CodeGenFunction::EmitCXXDestructorCall(const CXXDestructorDecl *DD,
CXXDtorType Type, CXXDtorType Type,
bool ForVirtualBase, bool ForVirtualBase,
bool Delegating,
llvm::Value *This) { llvm::Value *This) {
llvm::Value *VTT = GetVTTParameter(*this, GlobalDecl(DD, Type), llvm::Value *VTT = GetVTTParameter(*this, GlobalDecl(DD, Type),
ForVirtualBase); ForVirtualBase, Delegating);
llvm::Value *Callee = 0; llvm::Value *Callee = 0;
if (getLangOpts().AppleKext) if (getLangOpts().AppleKext)
Callee = BuildAppleKextVirtualDestructorCall(DD, Type, Callee = BuildAppleKextVirtualDestructorCall(DD, Type,
@ -1427,7 +1436,8 @@ namespace {
void Emit(CodeGenFunction &CGF, Flags flags) { void Emit(CodeGenFunction &CGF, Flags flags) {
CGF.EmitCXXDestructorCall(Dtor, Dtor_Complete, CGF.EmitCXXDestructorCall(Dtor, Dtor_Complete,
/*ForVirtualBase=*/false, Addr); /*ForVirtualBase=*/false,
/*Delegating=*/false, Addr);
} }
}; };
} }

View File

@ -386,7 +386,9 @@ namespace {
} }
CGF.EmitCXXDestructorCall(Dtor, Dtor_Complete, CGF.EmitCXXDestructorCall(Dtor, Dtor_Complete,
/*ForVirtualBase=*/false, Loc); /*ForVirtualBase=*/false,
/*Delegating=*/false,
Loc);
if (NRVO) CGF.EmitBlock(SkipDtorBB); if (NRVO) CGF.EmitBlock(SkipDtorBB);
} }

View File

@ -485,11 +485,13 @@ CodeGenFunction::EmitCXXConstructExpr(const CXXConstructExpr *E,
} else { } else {
CXXCtorType Type = Ctor_Complete; CXXCtorType Type = Ctor_Complete;
bool ForVirtualBase = false; bool ForVirtualBase = false;
bool Delegating = false;
switch (E->getConstructionKind()) { switch (E->getConstructionKind()) {
case CXXConstructExpr::CK_Delegating: case CXXConstructExpr::CK_Delegating:
// We should be emitting a constructor; GlobalDecl will assert this // We should be emitting a constructor; GlobalDecl will assert this
Type = CurGD.getCtorType(); Type = CurGD.getCtorType();
Delegating = true;
break; break;
case CXXConstructExpr::CK_Complete: case CXXConstructExpr::CK_Complete:
@ -505,7 +507,7 @@ CodeGenFunction::EmitCXXConstructExpr(const CXXConstructExpr *E,
} }
// Call the constructor. // Call the constructor.
EmitCXXConstructorCall(CD, Type, ForVirtualBase, Dest.getAddr(), EmitCXXConstructorCall(CD, Type, ForVirtualBase, Delegating, Dest.getAddr(),
E->arg_begin(), E->arg_end()); E->arg_begin(), E->arg_end());
} }
} }
@ -1425,7 +1427,9 @@ static void EmitObjectDelete(CodeGenFunction &CGF,
if (Dtor) if (Dtor)
CGF.EmitCXXDestructorCall(Dtor, Dtor_Complete, CGF.EmitCXXDestructorCall(Dtor, Dtor_Complete,
/*ForVirtualBase=*/false, Ptr); /*ForVirtualBase=*/false,
/*Delegating=*/false,
Ptr);
else if (CGF.getLangOpts().ObjCAutoRefCount && else if (CGF.getLangOpts().ObjCAutoRefCount &&
ElementType->isObjCLifetimeType()) { ElementType->isObjCLifetimeType()) {
switch (ElementType.getObjCLifetime()) { switch (ElementType.getObjCLifetime()) {

View File

@ -1816,7 +1816,8 @@ public:
void EmitDelegatingCXXConstructorCall(const CXXConstructorDecl *Ctor, void EmitDelegatingCXXConstructorCall(const CXXConstructorDecl *Ctor,
const FunctionArgList &Args); const FunctionArgList &Args);
void EmitCXXConstructorCall(const CXXConstructorDecl *D, CXXCtorType Type, void EmitCXXConstructorCall(const CXXConstructorDecl *D, CXXCtorType Type,
bool ForVirtualBase, llvm::Value *This, bool ForVirtualBase, bool Delegating,
llvm::Value *This,
CallExpr::const_arg_iterator ArgBeg, CallExpr::const_arg_iterator ArgBeg,
CallExpr::const_arg_iterator ArgEnd); CallExpr::const_arg_iterator ArgEnd);
@ -1842,7 +1843,8 @@ public:
static Destroyer destroyCXXObject; static Destroyer destroyCXXObject;
void EmitCXXDestructorCall(const CXXDestructorDecl *D, CXXDtorType Type, void EmitCXXDestructorCall(const CXXDestructorDecl *D, CXXDtorType Type,
bool ForVirtualBase, llvm::Value *This); bool ForVirtualBase, bool Delegating,
llvm::Value *This);
void EmitNewArrayInitializer(const CXXNewExpr *E, QualType elementType, void EmitNewArrayInitializer(const CXXNewExpr *E, QualType elementType,
llvm::Value *NewPtr, llvm::Value *NumElements); llvm::Value *NewPtr, llvm::Value *NumElements);

View File

@ -65,3 +65,37 @@ namespace PR12890 {
} }
// CHECK: define {{.*}} @_ZN7PR128901XC1Ei(%"class.PR12890::X"* %this, i32) // CHECK: define {{.*}} @_ZN7PR128901XC1Ei(%"class.PR12890::X"* %this, i32)
// CHECK: call void @llvm.memset.p0i8.{{i32|i64}}(i8* {{.*}}, i8 0, {{i32|i64}} 4, i32 4, i1 false) // CHECK: call void @llvm.memset.p0i8.{{i32|i64}}(i8* {{.*}}, i8 0, {{i32|i64}} 4, i32 4, i1 false)
namespace PR14588 {
void other();
class Base {
public:
Base() { squawk(); }
virtual ~Base() {}
virtual void squawk() { other(); }
};
class Foo : public virtual Base {
public:
Foo();
Foo(const void * inVoid);
virtual ~Foo() {}
virtual void squawk() { other(); }
};
// CHECK: define void @_ZN7PR145883FooC1Ev(%"class.PR14588::Foo"*
// CHECK: call void @_ZN7PR145883FooC1EPKv(
// CHECK: invoke void @_ZN7PR145885otherEv()
// CHECK: call void @_ZN7PR145883FooD1Ev
// CHECK: resume
Foo::Foo() : Foo(__null) { other(); }
Foo::Foo(const void *inVoid) {
squawk();
}
}