aboutsummaryrefslogtreecommitdiff
path: root/lib/AST/VTableBuilder.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/AST/VTableBuilder.cpp')
-rw-r--r--lib/AST/VTableBuilder.cpp334
1 files changed, 265 insertions, 69 deletions
diff --git a/lib/AST/VTableBuilder.cpp b/lib/AST/VTableBuilder.cpp
index fa1127f58f9b..ddb1f057ac8e 100644
--- a/lib/AST/VTableBuilder.cpp
+++ b/lib/AST/VTableBuilder.cpp
@@ -64,7 +64,7 @@ public:
/// Method - The method decl of the overrider.
const CXXMethodDecl *Method;
- /// VirtualBase - The virtual base class subobject of this overridder.
+ /// VirtualBase - The virtual base class subobject of this overrider.
/// Note that this records the closest derived virtual base class subobject.
const CXXRecordDecl *VirtualBase;
@@ -389,7 +389,7 @@ void FinalOverriders::dump(raw_ostream &Out, BaseSubobject Base,
CharUnits BaseOffset;
if (B.isVirtual()) {
- if (!VisitedVirtualBases.insert(BaseDecl)) {
+ if (!VisitedVirtualBases.insert(BaseDecl).second) {
// We've visited this base before.
continue;
}
@@ -748,7 +748,7 @@ VCallAndVBaseOffsetBuilder::AddVBaseOffsets(const CXXRecordDecl *RD,
const CXXRecordDecl *BaseDecl = B.getType()->getAsCXXRecordDecl();
// Check if this is a virtual base that we haven't visited before.
- if (B.isVirtual() && VisitedVirtualBases.insert(BaseDecl)) {
+ if (B.isVirtual() && VisitedVirtualBases.insert(BaseDecl).second) {
CharUnits Offset =
LayoutClassLayout.getVBaseClassOffset(BaseDecl) - OffsetInLayoutClass;
@@ -1105,7 +1105,7 @@ namespace {
bool visit(const CXXMethodDecl *MD) {
// Don't recurse on this method if we've already collected it.
- return Methods->insert(MD);
+ return Methods->insert(MD).second;
}
};
}
@@ -1842,7 +1842,7 @@ void ItaniumVTableBuilder::DeterminePrimaryVirtualBases(
CharUnits BaseOffsetInLayoutClass;
if (B.isVirtual()) {
- if (!VBases.insert(BaseDecl))
+ if (!VBases.insert(BaseDecl).second)
continue;
const ASTRecordLayout &LayoutClassLayout =
@@ -1870,8 +1870,9 @@ void ItaniumVTableBuilder::LayoutVTablesForVirtualBases(
// Check if this base needs a vtable. (If it's virtual, not a primary base
// of some other class, and we haven't visited it before).
- if (B.isVirtual() && BaseDecl->isDynamicClass() &&
- !PrimaryVirtualBases.count(BaseDecl) && VBases.insert(BaseDecl)) {
+ if (B.isVirtual() && BaseDecl->isDynamicClass() &&
+ !PrimaryVirtualBases.count(BaseDecl) &&
+ VBases.insert(BaseDecl).second) {
const ASTRecordLayout &MostDerivedClassLayout =
Context.getASTRecordLayout(MostDerivedClass);
CharUnits BaseOffset =
@@ -2390,6 +2391,7 @@ namespace {
// first vfptr whose table provides a compatible overridden method. In many
// cases, this permits the original vf-table entry to directly call
// the method instead of passing through a thunk.
+// See example before VFTableBuilder::ComputeThisOffset below.
//
// A compatible overridden method is one which does not have a non-trivial
// covariant-return adjustment.
@@ -2412,6 +2414,9 @@ namespace {
// a) a user-defined ctor/dtor
// and
// b) a method overriding a method in a virtual base.
+//
+// To get a better understanding of this code,
+// you might want to see examples in test/CodeGenCXX/microsoft-abi-vtables-*.cpp
class VFTableBuilder {
public:
@@ -2464,11 +2469,18 @@ private:
/// or used for vcalls in the most derived class.
bool Shadowed;
- MethodInfo(uint64_t VBTableIndex, uint64_t VFTableIndex)
+ /// UsesExtraSlot - Indicates if this vftable slot was created because
+ /// any of the overridden slots required a return adjusting thunk.
+ bool UsesExtraSlot;
+
+ MethodInfo(uint64_t VBTableIndex, uint64_t VFTableIndex,
+ bool UsesExtraSlot = false)
: VBTableIndex(VBTableIndex), VFTableIndex(VFTableIndex),
- Shadowed(false) {}
+ Shadowed(false), UsesExtraSlot(UsesExtraSlot) {}
- MethodInfo() : VBTableIndex(0), VFTableIndex(0), Shadowed(false) {}
+ MethodInfo()
+ : VBTableIndex(0), VFTableIndex(0), Shadowed(false),
+ UsesExtraSlot(false) {}
};
typedef llvm::DenseMap<const CXXMethodDecl *, MethodInfo> MethodInfoMapTy;
@@ -2525,8 +2537,6 @@ private:
}
}
- bool NeedsReturnAdjustingThunk(const CXXMethodDecl *MD);
-
/// AddMethods - Add the methods of this base subobject and the relevant
/// subbases to the vftable we're currently laying out.
void AddMethods(BaseSubobject Base, unsigned BaseDepth,
@@ -2534,13 +2544,15 @@ private:
BasesSetVectorTy &VisitedBases);
void LayoutVFTable() {
- // FIXME: add support for RTTI when we have proper LLVM support for symbols
- // pointing to the middle of a section.
+ // RTTI data goes before all other entries.
+ if (HasRTTIComponent)
+ Components.push_back(VTableComponent::MakeRTTI(MostDerivedClass));
BasesSetVectorTy VisitedBases;
AddMethods(BaseSubobject(MostDerivedClass, CharUnits::Zero()), 0, nullptr,
VisitedBases);
- assert(Components.size() && "vftable can't be empty");
+ assert((HasRTTIComponent ? Components.size() - 1 : Components.size()) &&
+ "vftable can't be empty");
assert(MethodVFTableLocations.empty());
for (MethodInfoMapTy::const_iterator I = MethodInfoMap.begin(),
@@ -2561,13 +2573,6 @@ private:
}
}
- void ErrorUnsupported(StringRef Feature, SourceLocation Location) {
- clang::DiagnosticsEngine &Diags = Context.getDiagnostics();
- unsigned DiagID = Diags.getCustomDiagID(
- DiagnosticsEngine::Error, "v-table layout for %0 is not supported yet");
- Diags.Report(Context.getFullLoc(Location), DiagID) << Feature;
- }
-
public:
VFTableBuilder(MicrosoftVTableContext &VTables,
const CXXRecordDecl *MostDerivedClass, const VPtrInfo *Which)
@@ -2581,8 +2586,6 @@ public:
// definition of the vftable.
HasRTTIComponent = Context.getLangOpts().RTTIData &&
!MostDerivedClass->hasAttr<DLLImportAttr>();
- if (HasRTTIComponent)
- Components.push_back(VTableComponent::MakeRTTI(MostDerivedClass));
LayoutVFTable();
@@ -2634,7 +2637,7 @@ struct InitialOverriddenDefinitionCollector {
if (OverriddenMD->size_overridden_methods() == 0)
Bases.insert(OverriddenMD->getParent());
// Don't recurse on this method if we've already collected it.
- return VisitedOverriddenMethods.insert(OverriddenMD);
+ return VisitedOverriddenMethods.insert(OverriddenMD).second;
}
};
@@ -2644,6 +2647,60 @@ static bool BaseInSet(const CXXBaseSpecifier *Specifier,
return Bases->count(Specifier->getType()->getAsCXXRecordDecl());
}
+// Let's study one class hierarchy as an example:
+// struct A {
+// virtual void f();
+// int x;
+// };
+//
+// struct B : virtual A {
+// virtual void f();
+// };
+//
+// Record layouts:
+// struct A:
+// 0 | (A vftable pointer)
+// 4 | int x
+//
+// struct B:
+// 0 | (B vbtable pointer)
+// 4 | struct A (virtual base)
+// 4 | (A vftable pointer)
+// 8 | int x
+//
+// Let's assume we have a pointer to the A part of an object of dynamic type B:
+// B b;
+// A *a = (A*)&b;
+// a->f();
+//
+// In this hierarchy, f() belongs to the vftable of A, so B::f() expects
+// "this" parameter to point at the A subobject, which is B+4.
+// In the B::f() prologue, it adjusts "this" back to B by subtracting 4,
+// performed as a *static* adjustment.
+//
+// Interesting thing happens when we alter the relative placement of A and B
+// subobjects in a class:
+// struct C : virtual B { };
+//
+// C c;
+// A *a = (A*)&c;
+// a->f();
+//
+// Respective record layout is:
+// 0 | (C vbtable pointer)
+// 4 | struct A (virtual base)
+// 4 | (A vftable pointer)
+// 8 | int x
+// 12 | struct B (virtual base)
+// 12 | (B vbtable pointer)
+//
+// The final overrider of f() in class C is still B::f(), so B+4 should be
+// passed as "this" to that code. However, "a" points at B-8, so the respective
+// vftable entry should hold a thunk that adds 12 to the "this" argument before
+// performing a tail call to B::f().
+//
+// With this example in mind, we can now calculate the 'this' argument offset
+// for the given method, relative to the beginning of the MostDerivedClass.
CharUnits
VFTableBuilder::ComputeThisOffset(FinalOverriders::OverriderInfo Overrider) {
InitialOverriddenDefinitionCollector Collector;
@@ -2723,6 +2780,104 @@ VFTableBuilder::ComputeThisOffset(FinalOverriders::OverriderInfo Overrider) {
return Ret;
}
+// Things are getting even more complex when the "this" adjustment has to
+// use a dynamic offset instead of a static one, or even two dynamic offsets.
+// This is sometimes required when a virtual call happens in the middle of
+// a non-most-derived class construction or destruction.
+//
+// Let's take a look at the following example:
+// struct A {
+// virtual void f();
+// };
+//
+// void foo(A *a) { a->f(); } // Knows nothing about siblings of A.
+//
+// struct B : virtual A {
+// virtual void f();
+// B() {
+// foo(this);
+// }
+// };
+//
+// struct C : virtual B {
+// virtual void f();
+// };
+//
+// Record layouts for these classes are:
+// struct A
+// 0 | (A vftable pointer)
+//
+// struct B
+// 0 | (B vbtable pointer)
+// 4 | (vtordisp for vbase A)
+// 8 | struct A (virtual base)
+// 8 | (A vftable pointer)
+//
+// struct C
+// 0 | (C vbtable pointer)
+// 4 | (vtordisp for vbase A)
+// 8 | struct A (virtual base) // A precedes B!
+// 8 | (A vftable pointer)
+// 12 | struct B (virtual base)
+// 12 | (B vbtable pointer)
+//
+// When one creates an object of type C, the C constructor:
+// - initializes all the vbptrs, then
+// - calls the A subobject constructor
+// (initializes A's vfptr with an address of A vftable), then
+// - calls the B subobject constructor
+// (initializes A's vfptr with an address of B vftable and vtordisp for A),
+// that in turn calls foo(), then
+// - initializes A's vfptr with an address of C vftable and zeroes out the
+// vtordisp
+// FIXME: if a structor knows it belongs to MDC, why doesn't it use a vftable
+// without vtordisp thunks?
+// FIXME: how are vtordisp handled in the presence of nooverride/final?
+//
+// When foo() is called, an object with a layout of class C has a vftable
+// referencing B::f() that assumes a B layout, so the "this" adjustments are
+// incorrect, unless an extra adjustment is done. This adjustment is called
+// "vtordisp adjustment". Vtordisp basically holds the difference between the
+// actual location of a vbase in the layout class and the location assumed by
+// the vftable of the class being constructed/destructed. Vtordisp is only
+// needed if "this" escapes a
+// structor (or we can't prove otherwise).
+// [i.e. vtordisp is a dynamic adjustment for a static adjustment, which is an
+// estimation of a dynamic adjustment]
+//
+// foo() gets a pointer to the A vbase and doesn't know anything about B or C,
+// so it just passes that pointer as "this" in a virtual call.
+// If there was no vtordisp, that would just dispatch to B::f().
+// However, B::f() assumes B+8 is passed as "this",
+// yet the pointer foo() passes along is B-4 (i.e. C+8).
+// An extra adjustment is needed, so we emit a thunk into the B vftable.
+// This vtordisp thunk subtracts the value of vtordisp
+// from the "this" argument (-12) before making a tailcall to B::f().
+//
+// Let's consider an even more complex example:
+// struct D : virtual B, virtual C {
+// D() {
+// foo(this);
+// }
+// };
+//
+// struct D
+// 0 | (D vbtable pointer)
+// 4 | (vtordisp for vbase A)
+// 8 | struct A (virtual base) // A precedes both B and C!
+// 8 | (A vftable pointer)
+// 12 | struct B (virtual base) // B precedes C!
+// 12 | (B vbtable pointer)
+// 16 | struct C (virtual base)
+// 16 | (C vbtable pointer)
+//
+// When D::D() calls foo(), we find ourselves in a thunk that should tailcall
+// to C::f(), which assumes C+8 as its "this" parameter. This time, foo()
+// passes along A, which is C-8. The A vtordisp holds
+// "D.vbptr[index_of_A] - offset_of_A_in_D"
+// and we statically know offset_of_A_in_D, so can get a pointer to D.
+// When we know it, we can make an extra vbtable lookup to locate the C vbase
+// and one extra static adjustment to calculate the expected value of C+8.
void VFTableBuilder::CalculateVtordispAdjustment(
FinalOverriders::OverriderInfo Overrider, CharUnits ThisOffset,
ThisAdjustment &TA) {
@@ -2740,9 +2895,9 @@ void VFTableBuilder::CalculateVtordispAdjustment(
// OK, now we know we need to use a vtordisp thunk.
// The implicit vtordisp field is located right before the vbase.
- CharUnits VFPtrVBaseOffset = VBaseMapEntry->second.VBaseOffset;
+ CharUnits OffsetOfVBaseWithVFPtr = VBaseMapEntry->second.VBaseOffset;
TA.Virtual.Microsoft.VtordispOffset =
- (VFPtrVBaseOffset - WhichVFPtr.FullOffsetInMDC).getQuantity() - 4;
+ (OffsetOfVBaseWithVFPtr - WhichVFPtr.FullOffsetInMDC).getQuantity() - 4;
// A simple vtordisp thunk will suffice if the final overrider is defined
// in either the most derived class or its non-virtual base.
@@ -2753,7 +2908,7 @@ void VFTableBuilder::CalculateVtordispAdjustment(
// Otherwise, we need to do use the dynamic offset of the final overrider
// in order to get "this" adjustment right.
TA.Virtual.Microsoft.VBPtrOffset =
- (VFPtrVBaseOffset + WhichVFPtr.NonVirtualOffset -
+ (OffsetOfVBaseWithVFPtr + WhichVFPtr.NonVirtualOffset -
MostDerivedClassLayout.getVBPtrOffset()).getQuantity();
TA.Virtual.Microsoft.VBOffsetOffset =
Context.getTypeSizeInChars(Context.IntTy).getQuantity() *
@@ -2789,24 +2944,6 @@ static void GroupNewVirtualOverloads(
VirtualMethods.append(Groups[I].rbegin(), Groups[I].rend());
}
-/// We need a return adjusting thunk for this method if its return type is
-/// not trivially convertible to the return type of any of its overridden
-/// methods.
-bool VFTableBuilder::NeedsReturnAdjustingThunk(const CXXMethodDecl *MD) {
- OverriddenMethodsSetTy OverriddenMethods;
- ComputeAllOverriddenMethods(MD, OverriddenMethods);
- for (OverriddenMethodsSetTy::iterator I = OverriddenMethods.begin(),
- E = OverriddenMethods.end();
- I != E; ++I) {
- const CXXMethodDecl *OverriddenMD = *I;
- BaseOffset Adjustment =
- ComputeReturnAdjustmentBaseOffset(Context, MD, OverriddenMD);
- if (!Adjustment.isEmpty())
- return true;
- }
- return false;
-}
-
static bool isDirectVBase(const CXXRecordDecl *Base, const CXXRecordDecl *RD) {
for (const auto &B : RD->bases()) {
if (B.isVirtual() && B.getType()->getAsCXXRecordDecl() == Base)
@@ -2866,20 +3003,21 @@ void VFTableBuilder::AddMethods(BaseSubobject Base, unsigned BaseDepth,
for (unsigned I = 0, E = VirtualMethods.size(); I != E; ++I) {
const CXXMethodDecl *MD = VirtualMethods[I];
- FinalOverriders::OverriderInfo Overrider =
+ FinalOverriders::OverriderInfo FinalOverrider =
Overriders.getOverrider(MD, Base.getBaseOffset());
- const CXXMethodDecl *OverriderMD = Overrider.Method;
+ const CXXMethodDecl *FinalOverriderMD = FinalOverrider.Method;
const CXXMethodDecl *OverriddenMD =
FindNearestOverriddenMethod(MD, VisitedBases);
ThisAdjustment ThisAdjustmentOffset;
- bool ReturnAdjustingThunk = false;
- CharUnits ThisOffset = ComputeThisOffset(Overrider);
+ bool ReturnAdjustingThunk = false, ForceReturnAdjustmentMangling = false;
+ CharUnits ThisOffset = ComputeThisOffset(FinalOverrider);
ThisAdjustmentOffset.NonVirtual =
(ThisOffset - WhichVFPtr.FullOffsetInMDC).getQuantity();
- if ((OverriddenMD || OverriderMD != MD) &&
+ if ((OverriddenMD || FinalOverriderMD != MD) &&
WhichVFPtr.getVBaseWithVPtr())
- CalculateVtordispAdjustment(Overrider, ThisOffset, ThisAdjustmentOffset);
+ CalculateVtordispAdjustment(FinalOverrider, ThisOffset,
+ ThisAdjustmentOffset);
if (OverriddenMD) {
// If MD overrides anything in this vftable, we need to update the entries.
@@ -2892,7 +3030,16 @@ void VFTableBuilder::AddMethods(BaseSubobject Base, unsigned BaseDepth,
MethodInfo &OverriddenMethodInfo = OverriddenMDIterator->second;
- if (!NeedsReturnAdjustingThunk(MD)) {
+ // Let's check if the overrider requires any return adjustments.
+ // We must create a new slot if the MD's return type is not trivially
+ // convertible to the OverriddenMD's one.
+ // Once a chain of method overrides adds a return adjusting vftable slot,
+ // all subsequent overrides will also use an extra method slot.
+ ReturnAdjustingThunk = !ComputeReturnAdjustmentBaseOffset(
+ Context, MD, OverriddenMD).isEmpty() ||
+ OverriddenMethodInfo.UsesExtraSlot;
+
+ if (!ReturnAdjustingThunk) {
// No return adjustment needed - just replace the overridden method info
// with the current info.
MethodInfo MI(OverriddenMethodInfo.VBTableIndex,
@@ -2911,8 +3058,8 @@ void VFTableBuilder::AddMethods(BaseSubobject Base, unsigned BaseDepth,
// Force a special name mangling for a return-adjusting thunk
// unless the method is the final overrider without this adjustment.
- ReturnAdjustingThunk =
- !(MD == OverriderMD && ThisAdjustmentOffset.isEmpty());
+ ForceReturnAdjustmentMangling =
+ !(MD == FinalOverriderMD && ThisAdjustmentOffset.isEmpty());
} else if (Base.getBaseOffset() != WhichVFPtr.FullOffsetInMDC ||
MD->size_overridden_methods()) {
// Skip methods that don't belong to the vftable of the current class,
@@ -2926,7 +3073,8 @@ void VFTableBuilder::AddMethods(BaseSubobject Base, unsigned BaseDepth,
unsigned VBIndex =
LastVBase ? VTables.getVBTableIndex(MostDerivedClass, LastVBase) : 0;
MethodInfo MI(VBIndex,
- HasRTTIComponent ? Components.size() - 1 : Components.size());
+ HasRTTIComponent ? Components.size() - 1 : Components.size(),
+ ReturnAdjustingThunk);
assert(!MethodInfoMap.count(MD) &&
"Should not have method info for this method yet!");
@@ -2936,12 +3084,12 @@ void VFTableBuilder::AddMethods(BaseSubobject Base, unsigned BaseDepth,
// We don't want to do this for pure virtual member functions.
BaseOffset ReturnAdjustmentOffset;
ReturnAdjustment ReturnAdjustment;
- if (!OverriderMD->isPure()) {
+ if (!FinalOverriderMD->isPure()) {
ReturnAdjustmentOffset =
- ComputeReturnAdjustmentBaseOffset(Context, OverriderMD, MD);
+ ComputeReturnAdjustmentBaseOffset(Context, FinalOverriderMD, MD);
}
if (!ReturnAdjustmentOffset.isEmpty()) {
- ReturnAdjustingThunk = true;
+ ForceReturnAdjustmentMangling = true;
ReturnAdjustment.NonVirtual =
ReturnAdjustmentOffset.NonVirtualOffset.getQuantity();
if (ReturnAdjustmentOffset.VirtualBase) {
@@ -2955,8 +3103,9 @@ void VFTableBuilder::AddMethods(BaseSubobject Base, unsigned BaseDepth,
}
}
- AddMethod(OverriderMD, ThunkInfo(ThisAdjustmentOffset, ReturnAdjustment,
- ReturnAdjustingThunk ? MD : nullptr));
+ AddMethod(FinalOverriderMD,
+ ThunkInfo(ThisAdjustmentOffset, ReturnAdjustment,
+ ForceReturnAdjustmentMangling ? MD : nullptr));
}
}
@@ -3039,10 +3188,8 @@ void VFTableBuilder::dumpLayout(raw_ostream &Out) {
if (MD->isPure())
Out << " [pure]";
- if (MD->isDeleted()) {
- ErrorUnsupported("deleted methods", MD->getLocation());
+ if (MD->isDeleted())
Out << " [deleted]";
- }
ThunkInfo Thunk = VTableThunks.lookup(I);
if (!Thunk.isEmpty())
@@ -3131,7 +3278,7 @@ void VFTableBuilder::dumpLayout(raw_ostream &Out) {
}
static bool setsIntersect(const llvm::SmallPtrSet<const CXXRecordDecl *, 4> &A,
- const ArrayRef<const CXXRecordDecl *> &B) {
+ ArrayRef<const CXXRecordDecl *> B) {
for (ArrayRef<const CXXRecordDecl *>::iterator I = B.begin(), E = B.end();
I != E; ++I) {
if (A.count(*I))
@@ -3201,10 +3348,6 @@ void MicrosoftVTableContext::computeVTablePaths(bool ForVBTables,
if (P->MangledPath.empty() || P->MangledPath.back() != Base)
P->NextBaseToMangle = Base;
- // Keep track of the full path.
- // FIXME: Why do we need this?
- P->PathToBaseWithVPtr.insert(P->PathToBaseWithVPtr.begin(), Base);
-
// Keep track of which vtable the derived class is going to extend with
// new methods or bases. We append to either the vftable of our primary
// base, or the first non-virtual base that has a vbtable.
@@ -3292,6 +3435,58 @@ MicrosoftVTableContext::~MicrosoftVTableContext() {
llvm::DeleteContainerSeconds(VBaseInfo);
}
+static bool
+findPathForVPtr(ASTContext &Context, const ASTRecordLayout &MostDerivedLayout,
+ const CXXRecordDecl *RD, CharUnits Offset,
+ llvm::SmallPtrSetImpl<const CXXRecordDecl *> &VBasesSeen,
+ VPtrInfo::BasePath &FullPath, VPtrInfo *Info) {
+ if (RD == Info->BaseWithVPtr && Offset == Info->FullOffsetInMDC) {
+ Info->PathToBaseWithVPtr = FullPath;
+ return true;
+ }
+
+ const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
+
+ // Recurse with non-virtual bases first.
+ // FIXME: Does this need to be in layout order? Virtual bases will be in base
+ // specifier order, which isn't necessarily layout order.
+ SmallVector<CXXBaseSpecifier, 4> Bases(RD->bases_begin(), RD->bases_end());
+ std::stable_partition(Bases.begin(), Bases.end(),
+ [](CXXBaseSpecifier bs) { return !bs.isVirtual(); });
+
+ for (const auto &B : Bases) {
+ const CXXRecordDecl *Base = B.getType()->getAsCXXRecordDecl();
+ CharUnits NewOffset;
+ if (!B.isVirtual())
+ NewOffset = Offset + Layout.getBaseClassOffset(Base);
+ else {
+ if (!VBasesSeen.insert(Base).second)
+ return false;
+ NewOffset = MostDerivedLayout.getVBaseClassOffset(Base);
+ }
+ FullPath.push_back(Base);
+ if (findPathForVPtr(Context, MostDerivedLayout, Base, NewOffset, VBasesSeen,
+ FullPath, Info))
+ return true;
+ FullPath.pop_back();
+ }
+ return false;
+}
+
+static void computeFullPathsForVFTables(ASTContext &Context,
+ const CXXRecordDecl *RD,
+ VPtrInfoVector &Paths) {
+ llvm::SmallPtrSet<const CXXRecordDecl*, 4> VBasesSeen;
+ const ASTRecordLayout &MostDerivedLayout = Context.getASTRecordLayout(RD);
+ VPtrInfo::BasePath FullPath;
+ for (VPtrInfo *Info : Paths) {
+ findPathForVPtr(Context, MostDerivedLayout, RD, CharUnits::Zero(),
+ VBasesSeen, FullPath, Info);
+ VBasesSeen.clear();
+ FullPath.clear();
+ }
+}
+
void MicrosoftVTableContext::computeVTableRelatedInformation(
const CXXRecordDecl *RD) {
assert(RD->isDynamicClass());
@@ -3304,6 +3499,7 @@ void MicrosoftVTableContext::computeVTableRelatedInformation(
VPtrInfoVector *VFPtrs = new VPtrInfoVector();
computeVTablePaths(/*ForVBTables=*/false, RD, *VFPtrs);
+ computeFullPathsForVFTables(Context, RD, *VFPtrs);
VFPtrLocations[RD] = VFPtrs;
MethodVFTableLocationsTy NewMethodLocations;