summaryrefslogtreecommitdiffstats
path: root/clang/lib
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib')
-rw-r--r--clang/lib/AST/VTableBuilder.cpp18
-rw-r--r--clang/lib/CodeGen/CGClass.cpp9
-rw-r--r--clang/lib/CodeGen/MicrosoftCXXABI.cpp83
3 files changed, 88 insertions, 22 deletions
diff --git a/clang/lib/AST/VTableBuilder.cpp b/clang/lib/AST/VTableBuilder.cpp
index 045b7f1a42d..2da089186c9 100644
--- a/clang/lib/AST/VTableBuilder.cpp
+++ b/clang/lib/AST/VTableBuilder.cpp
@@ -2668,11 +2668,6 @@ CharUnits
VFTableBuilder::ComputeThisOffset(const CXXMethodDecl *MD,
BaseSubobject Base,
FinalOverriders::OverriderInfo Overrider) {
- // Complete object virtual destructors are always emitted in the most derived
- // class, thus don't have this offset.
- if (isa<CXXDestructorDecl>(MD))
- return CharUnits();
-
InitialOverriddenDefinitionCollector Collector;
visitAllOverriddenMethods(MD, Collector);
@@ -2690,6 +2685,7 @@ VFTableBuilder::ComputeThisOffset(const CXXMethodDecl *MD,
I != E; ++I) {
const CXXBasePath &Path = (*I);
CharUnits ThisOffset = Base.getBaseOffset();
+ bool SeenVBase = false;
// For each path from the overrider to the parents of the overridden methods,
// traverse the path, calculating the this offset in the most derived class.
@@ -2701,6 +2697,7 @@ VFTableBuilder::ComputeThisOffset(const CXXMethodDecl *MD,
const ASTRecordLayout &Layout = Context.getASTRecordLayout(PrevRD);
if (Element.Base->isVirtual()) {
+ SeenVBase = true;
if (Overrider.Method->getParent() == PrevRD) {
// This one's interesting. If the final overrider is in a vbase B of the
// most derived class and it overrides a method of the B's own vbase A,
@@ -2713,11 +2710,22 @@ VFTableBuilder::ComputeThisOffset(const CXXMethodDecl *MD,
} else {
ThisOffset = MostDerivedClassLayout.getVBaseClassOffset(CurRD);
}
+
+ // A virtual destructor of a virtual base takes the address of the
+ // virtual base subobject as the "this" argument.
+ if (isa<CXXDestructorDecl>(MD))
+ break;
} else {
ThisOffset += Layout.getBaseClassOffset(CurRD);
}
}
+ // If a "Base" class has at least one non-virtual base with a virtual
+ // destructor, the "Base" virtual destructor will take the address of the
+ // "Base" subobject as the "this" argument.
+ if (!SeenVBase && isa<CXXDestructorDecl>(MD))
+ return Base.getBaseOffset();
+
if (Ret > ThisOffset || First) {
First = false;
Ret = ThisOffset;
diff --git a/clang/lib/CodeGen/CGClass.cpp b/clang/lib/CodeGen/CGClass.cpp
index 91f42e2f579..d6907840c94 100644
--- a/clang/lib/CodeGen/CGClass.cpp
+++ b/clang/lib/CodeGen/CGClass.cpp
@@ -1829,8 +1829,8 @@ void CodeGenFunction::EmitCXXDestructorCall(const CXXDestructorDecl *DD,
bool ForVirtualBase,
bool Delegating,
llvm::Value *This) {
- llvm::Value *VTT = GetVTTParameter(GlobalDecl(DD, Type),
- ForVirtualBase, Delegating);
+ GlobalDecl GD(DD, Type);
+ llvm::Value *VTT = GetVTTParameter(GD, ForVirtualBase, Delegating);
llvm::Value *Callee = 0;
if (getLangOpts().AppleKext)
Callee = BuildAppleKextVirtualDestructorCall(DD, Type,
@@ -1838,7 +1838,10 @@ void CodeGenFunction::EmitCXXDestructorCall(const CXXDestructorDecl *DD,
if (!Callee)
Callee = CGM.GetAddrOfCXXDestructor(DD, Type);
-
+
+ if (DD->isVirtual())
+ This = CGM.getCXXABI().adjustThisArgumentForVirtualCall(*this, GD, This);
+
// FIXME: Provide a source location here.
EmitCXXMemberCall(DD, SourceLocation(), Callee, ReturnValueSlot(), This,
VTT, getContext().getPointerType(getContext().VoidPtrTy),
diff --git a/clang/lib/CodeGen/MicrosoftCXXABI.cpp b/clang/lib/CodeGen/MicrosoftCXXABI.cpp
index 9d59160cec8..c1ea60d09a4 100644
--- a/clang/lib/CodeGen/MicrosoftCXXABI.cpp
+++ b/clang/lib/CodeGen/MicrosoftCXXABI.cpp
@@ -563,21 +563,65 @@ llvm::Value *MicrosoftCXXABI::adjustThisArgumentForVirtualCall(
CodeGenFunction &CGF, GlobalDecl GD, llvm::Value *This) {
GD = GD.getCanonicalDecl();
const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl());
- if (isa<CXXDestructorDecl>(MD))
- return This;
-
+ // FIXME: consider splitting the vdtor vs regular method code into two
+ // functions.
+
+ GlobalDecl LookupGD = GD;
+ if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) {
+ // Complete dtors take a pointer to the complete object,
+ // thus don't need adjustment.
+ if (GD.getDtorType() == Dtor_Complete)
+ return This;
+
+ // There's only Dtor_Deleting in vftable but it shares the this adjustment
+ // with the base one, so look up the deleting one instead.
+ LookupGD = GlobalDecl(DD, Dtor_Deleting);
+ }
MicrosoftVFTableContext::MethodVFTableLocation ML =
- CGM.getVFTableContext().getMethodVFTableLocation(GD);
+ CGM.getVFTableContext().getMethodVFTableLocation(LookupGD);
unsigned AS = cast<llvm::PointerType>(This->getType())->getAddressSpace();
llvm::Type *charPtrTy = CGF.Int8Ty->getPointerTo(AS);
+ CharUnits StaticOffset = ML.VFTableOffset;
if (ML.VBase) {
- This = CGF.Builder.CreateBitCast(This, charPtrTy);
- llvm::Value *VBaseOffset = CGM.getCXXABI()
- .GetVirtualBaseClassOffset(CGF, This, MD->getParent(), ML.VBase);
- This = CGF.Builder.CreateInBoundsGEP(This, VBaseOffset);
+ bool AvoidVirtualOffset = false;
+ if (isa<CXXDestructorDecl>(MD) && GD.getDtorType() == Dtor_Base) {
+ // A base destructor can only be called from a complete destructor of the
+ // same record type or another destructor of a more derived type.
+ const CXXRecordDecl *CurRD =
+ cast<CXXDestructorDecl>(CGF.CurGD.getDecl())->getParent();
+
+ if (MD->getParent() == CurRD) {
+ assert(CGF.CurGD.getDtorType() == Dtor_Complete);
+ // We're calling the main base dtor from a complete dtor, so we know the
+ // "this" offset statically.
+ AvoidVirtualOffset = true;
+ } else {
+ // Let's see if we try to call a destructor of a non-virtual base.
+ for (CXXRecordDecl::base_class_const_iterator I = CurRD->bases_begin(),
+ E = CurRD->bases_end(); I != E; ++I) {
+ if (I->getType()->getAsCXXRecordDecl() != MD->getParent())
+ continue;
+ // If we call a base destructor for a non-virtual base, we statically
+ // know where it expects the vfptr and "this" to be.
+ AvoidVirtualOffset = true;
+ break;
+ }
+ }
+ }
+
+ if (AvoidVirtualOffset) {
+ const ASTRecordLayout &Layout =
+ CGF.getContext().getASTRecordLayout(MD->getParent());
+ // This reflects the logic from VFTableBuilder::ComputeThisOffset().
+ StaticOffset += Layout.getVBaseClassOffset(ML.VBase);
+ } else {
+ This = CGF.Builder.CreateBitCast(This, charPtrTy);
+ llvm::Value *VBaseOffset = CGM.getCXXABI()
+ .GetVirtualBaseClassOffset(CGF, This, MD->getParent(), ML.VBase);
+ This = CGF.Builder.CreateInBoundsGEP(This, VBaseOffset);
+ }
}
- CharUnits StaticOffset = ML.VFTableOffset;
if (!StaticOffset.isZero()) {
assert(StaticOffset.isPositive());
This = CGF.Builder.CreateBitCast(This, charPtrTy);
@@ -625,8 +669,18 @@ llvm::Value *MicrosoftCXXABI::adjustThisParameterInVirtualFunctionPrologue(
CodeGenFunction &CGF, GlobalDecl GD, llvm::Value *This) {
GD = GD.getCanonicalDecl();
const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl());
- if (isa<CXXDestructorDecl>(MD))
- return This;
+
+ GlobalDecl LookupGD = GD;
+ if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) {
+ // Complete destructors take a pointer to the complete object as a
+ // parameter, thus don't need this adjustment.
+ if (GD.getDtorType() == Dtor_Complete)
+ return This;
+
+ // There's no Dtor_Base in vftable but it shares the this adjustment with
+ // the deleting one, so look it up instead.
+ LookupGD = GlobalDecl(DD, Dtor_Deleting);
+ }
// In this ABI, every virtual function takes a pointer to one of the
// subobjects that first defines it as the 'this' parameter, rather than a
@@ -635,7 +689,7 @@ llvm::Value *MicrosoftCXXABI::adjustThisParameterInVirtualFunctionPrologue(
// See comments in the MicrosoftVFTableContext implementation for the details.
MicrosoftVFTableContext::MethodVFTableLocation ML =
- CGM.getVFTableContext().getMethodVFTableLocation(GD);
+ CGM.getVFTableContext().getMethodVFTableLocation(LookupGD);
CharUnits Adjustment = ML.VFTableOffset;
if (ML.VBase) {
const ASTRecordLayout &DerivedLayout =
@@ -850,17 +904,18 @@ void MicrosoftCXXABI::EmitVirtualDestructorCall(CodeGenFunction &CGF,
// We have only one destructor in the vftable but can get both behaviors
// by passing an implicit int parameter.
+ GlobalDecl GD(Dtor, Dtor_Deleting);
const CGFunctionInfo *FInfo =
&CGM.getTypes().arrangeCXXDestructor(Dtor, Dtor_Deleting);
llvm::Type *Ty = CGF.CGM.getTypes().GetFunctionType(*FInfo);
- llvm::Value *Callee =
- getVirtualFunctionPointer(CGF, GlobalDecl(Dtor, Dtor_Deleting), This, Ty);
+ llvm::Value *Callee = getVirtualFunctionPointer(CGF, GD, This, Ty);
ASTContext &Context = CGF.getContext();
llvm::Value *ImplicitParam =
llvm::ConstantInt::get(llvm::IntegerType::getInt32Ty(CGF.getLLVMContext()),
DtorType == Dtor_Deleting);
+ This = adjustThisArgumentForVirtualCall(CGF, GD, This);
CGF.EmitCXXMemberCall(Dtor, CallLoc, Callee, ReturnValueSlot(), This,
ImplicitParam, Context.IntTy, 0, 0);
}
OpenPOWER on IntegriCloud