summaryrefslogtreecommitdiffstats
path: root/clang/lib
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib')
-rw-r--r--clang/lib/CodeGen/CGCXXABI.h6
-rw-r--r--clang/lib/CodeGen/CGClass.cpp3
-rw-r--r--clang/lib/CodeGen/MicrosoftCXXABI.cpp58
3 files changed, 67 insertions, 0 deletions
diff --git a/clang/lib/CodeGen/CGCXXABI.h b/clang/lib/CodeGen/CGCXXABI.h
index eaeb971dc42..c76769f4252 100644
--- a/clang/lib/CodeGen/CGCXXABI.h
+++ b/clang/lib/CodeGen/CGCXXABI.h
@@ -234,6 +234,12 @@ public:
virtual llvm::BasicBlock *EmitCtorCompleteObjectHandler(CodeGenFunction &CGF,
const CXXRecordDecl *RD);
+ /// Emit the code to initialize hidden members required
+ /// to handle virtual inheritance, if needed by the ABI.
+ virtual void
+ initializeHiddenVirtualInheritanceMembers(CodeGenFunction &CGF,
+ const CXXRecordDecl *RD) {}
+
/// Emit constructor variants required by this ABI.
virtual void EmitCXXConstructors(const CXXConstructorDecl *D) = 0;
diff --git a/clang/lib/CodeGen/CGClass.cpp b/clang/lib/CodeGen/CGClass.cpp
index 137d793c117..91f42e2f579 100644
--- a/clang/lib/CodeGen/CGClass.cpp
+++ b/clang/lib/CodeGen/CGClass.cpp
@@ -1992,6 +1992,9 @@ void CodeGenFunction::InitializeVTablePointers(const CXXRecordDecl *RD) {
/*NearestVBase=*/0,
/*OffsetFromNearestVBase=*/CharUnits::Zero(),
/*BaseIsNonVirtualPrimaryBase=*/false, RD, VBases);
+
+ if (RD->getNumVBases())
+ CGM.getCXXABI().initializeHiddenVirtualInheritanceMembers(*this, RD);
}
llvm::Value *CodeGenFunction::GetVTablePtr(llvm::Value *This,
diff --git a/clang/lib/CodeGen/MicrosoftCXXABI.cpp b/clang/lib/CodeGen/MicrosoftCXXABI.cpp
index 7452c860d0b..fd677712e78 100644
--- a/clang/lib/CodeGen/MicrosoftCXXABI.cpp
+++ b/clang/lib/CodeGen/MicrosoftCXXABI.cpp
@@ -67,6 +67,9 @@ public:
llvm::BasicBlock *EmitCtorCompleteObjectHandler(CodeGenFunction &CGF,
const CXXRecordDecl *RD);
+ void initializeHiddenVirtualInheritanceMembers(CodeGenFunction &CGF,
+ const CXXRecordDecl *RD);
+
void EmitCXXConstructors(const CXXConstructorDecl *D);
// Background on MSVC destructors
@@ -456,6 +459,61 @@ MicrosoftCXXABI::EmitCtorCompleteObjectHandler(CodeGenFunction &CGF,
return SkipVbaseCtorsBB;
}
+void MicrosoftCXXABI::initializeHiddenVirtualInheritanceMembers(
+ CodeGenFunction &CGF, const CXXRecordDecl *RD) {
+ // In most cases, an override for a vbase virtual method can adjust
+ // the "this" parameter by applying a constant offset.
+ // However, this is not enough while a constructor or a destructor of some
+ // class X is being executed if all the following conditions are met:
+ // - X has virtual bases, (1)
+ // - X overrides a virtual method M of a vbase Y, (2)
+ // - X itself is a vbase of the most derived class.
+ //
+ // If (1) and (2) are true, the vtorDisp for vbase Y is a hidden member of X
+ // which holds the extra amount of "this" adjustment we must do when we use
+ // the X vftables (i.e. during X ctor or dtor).
+ // Outside the ctors and dtors, the values of vtorDisps are zero.
+
+ const ASTRecordLayout &Layout = getContext().getASTRecordLayout(RD);
+ typedef ASTRecordLayout::VBaseOffsetsMapTy VBOffsets;
+ const VBOffsets &VBaseMap = Layout.getVBaseOffsetsMap();
+ CGBuilderTy &Builder = CGF.Builder;
+
+ unsigned AS =
+ cast<llvm::PointerType>(getThisValue(CGF)->getType())->getAddressSpace();
+ llvm::Value *Int8This = 0; // Initialize lazily.
+
+ for (VBOffsets::const_iterator I = VBaseMap.begin(), E = VBaseMap.end();
+ I != E; ++I) {
+ if (!I->second.hasVtorDisp())
+ continue;
+
+ llvm::Value *VBaseOffset = CGM.getCXXABI().GetVirtualBaseClassOffset(
+ CGF, getThisValue(CGF), RD, I->first);
+ // FIXME: it doesn't look right that we SExt in GetVirtualBaseClassOffset()
+ // just to Trunc back immediately.
+ VBaseOffset = Builder.CreateTruncOrBitCast(VBaseOffset, CGF.Int32Ty);
+ uint64_t ConstantVBaseOffset =
+ Layout.getVBaseClassOffset(I->first).getQuantity();
+
+ // vtorDisp_for_vbase = vbptr[vbase_idx] - offsetof(RD, vbase).
+ llvm::Value *VtorDispValue = Builder.CreateSub(
+ VBaseOffset, llvm::ConstantInt::get(CGM.Int32Ty, ConstantVBaseOffset),
+ "vtordisp.value");
+
+ if (!Int8This)
+ Int8This = Builder.CreateBitCast(getThisValue(CGF),
+ CGF.Int8Ty->getPointerTo(AS));
+ llvm::Value *VtorDispPtr = Builder.CreateInBoundsGEP(Int8This, VBaseOffset);
+ // vtorDisp is always the 32-bits before the vbase in the class layout.
+ VtorDispPtr = Builder.CreateConstGEP1_32(VtorDispPtr, -4);
+ VtorDispPtr = Builder.CreateBitCast(
+ VtorDispPtr, CGF.Int32Ty->getPointerTo(AS), "vtordisp.ptr");
+
+ Builder.CreateStore(VtorDispValue, VtorDispPtr);
+ }
+}
+
void MicrosoftCXXABI::EmitCXXConstructors(const CXXConstructorDecl *D) {
// There's only one constructor type in this ABI.
CGM.EmitGlobal(GlobalDecl(D, Ctor_Complete));
OpenPOWER on IntegriCloud