forked from OSchip/llvm-project
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:
parent
006039cc74
commit
6153500517
|
@ -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);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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()) {
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue