typedef llvm::DenseMap<BaseSubobject, uint64_t>
AddressPointsMapTy;
- typedef llvm::DenseMap<GlobalDecl, int64_t> MethodVTableIndicesTy;
-
private:
/// VTables - Global vtable information.
VTableContext &VTables;
/// MethodInfoMap - The information for all methods in the vtable we're
/// currently building.
MethodInfoMapTy MethodInfoMap;
-
- /// MethodVTableIndices - Contains the index (relative to the vtable address
- /// point) where the function pointer for a virtual function is stored.
- MethodVTableIndicesTy MethodVTableIndices;
-
+
typedef llvm::DenseMap<uint64_t, ThunkInfo> VTableThunksMapTy;
/// VTableThunks - The thunks by vtable index in the vtable currently being
return AddressPoints;
}
- MethodVTableIndicesTy::const_iterator vtable_indices_begin() const {
- return MethodVTableIndices.begin();
- }
-
- MethodVTableIndicesTy::const_iterator vtable_indices_end() const {
- return MethodVTableIndices.end();
- }
-
/// getNumVTableComponents - Return the number of components in the vtable
/// currently built.
uint64_t getNumVTableComponents() const {
const CXXRecordDecl *FirstBaseInPrimaryBaseChain,
CharUnits FirstBaseOffsetInLayoutClass,
PrimaryBasesSetVectorTy &PrimaryBases) {
- // Itanium C++ ABI 2.5.2:
- // The order of the virtual function pointers in a virtual table is the
- // order of declaration of the corresponding member functions in the class.
- //
- // There is an entry for any virtual function declared in a class,
- // whether it is a new function or overrides a base class function,
- // unless it overrides a function from the primary base, and conversion
- // between their return types does not require an adjustment.
-
const CXXRecordDecl *RD = Base.getBase();
const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
llvm_unreachable("Found a duplicate primary base!");
}
- const CXXDestructorDecl *ImplicitVirtualDtor = 0;
-
- typedef llvm::SmallPtrSet<const CXXMethodDecl *, 8> NewVirtualFunctionsSetTy;
- NewVirtualFunctionsSetTy NewVirtualFunctions;
-
// Now go through all virtual member functions and add them.
for (CXXRecordDecl::method_iterator I = RD->method_begin(),
E = RD->method_end(); I != E; ++I) {
}
}
- if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) {
- if (MD->isImplicit()) {
- // Itanium C++ ABI 2.5.2:
- // If a class has an implicitly-defined virtual destructor,
- // its entries come after the declared virtual function pointers.
-
- assert(!ImplicitVirtualDtor &&
- "Did already see an implicit virtual dtor!");
- ImplicitVirtualDtor = DD;
- continue;
- }
- }
-
- NewVirtualFunctions.insert(MD);
- }
-
- if (ImplicitVirtualDtor)
- NewVirtualFunctions.insert(ImplicitVirtualDtor);
-
- for (NewVirtualFunctionsSetTy::const_iterator I = NewVirtualFunctions.begin(),
- E = NewVirtualFunctions.end(); I != E; ++I) {
- const CXXMethodDecl *MD = *I;
-
- // Get the final overrider.
- FinalOverriders::OverriderInfo Overrider =
- Overriders.getOverrider(MD, Base.getBaseOffset());
-
// Insert the method info for this method.
MethodInfo MethodInfo(Base.getBaseOffset(), BaseOffsetInLayoutClass,
Components.size());
Components.push_back(VTableComponent::MakeUnusedFunction(OverriderMD));
continue;
}
-
+
// Check if this overrider needs a return adjustment.
// We don't want to do this for pure virtual member functions.
BaseOffset ReturnAdjustmentOffset;
Base.getBase(), OffsetInLayoutClass,
PrimaryBases);
- const CXXRecordDecl *RD = Base.getBase();
- if (RD == MostDerivedClass) {
- assert(MethodVTableIndices.empty());
- for (MethodInfoMapTy::const_iterator I = MethodInfoMap.begin(),
- E = MethodInfoMap.end(); I != E; ++I) {
- const CXXMethodDecl *MD = I->first;
- const MethodInfo &MI = I->second;
- if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) {
- // FIXME: Should probably add a layer of abstraction for vtable generation.
- if (!isMicrosoftABI()) {
- MethodVTableIndices[GlobalDecl(DD, Dtor_Complete)]
- = MI.VTableIndex - AddressPoint;
- MethodVTableIndices[GlobalDecl(DD, Dtor_Deleting)]
- = MI.VTableIndex + 1 - AddressPoint;
- } else {
- MethodVTableIndices[GlobalDecl(DD, Dtor_Deleting)]
- = MI.VTableIndex - AddressPoint;
- }
- } else {
- MethodVTableIndices[MD] = MI.VTableIndex - AddressPoint;
- }
- }
- }
-
// Compute 'this' pointer adjustments.
ComputeThisAdjustments();
// Add all address points.
+ const CXXRecordDecl *RD = Base.getBase();
while (true) {
AddressPoints.insert(std::make_pair(
BaseSubobject(RD, OffsetInLayoutClass),
if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) {
// FIXME: Should add a layer of abstraction for vtable generation.
if (!isMicrosoftABI()) {
- GlobalDecl GD(DD, Dtor_Complete);
- assert(MethodVTableIndices.count(GD));
- uint64_t VTableIndex = MethodVTableIndices[GD];
- IndicesMap[VTableIndex] = MethodName + " [complete]";
- IndicesMap[VTableIndex + 1] = MethodName + " [deleting]";
+ IndicesMap[VTables.getMethodVTableIndex(GlobalDecl(DD, Dtor_Complete))]
+ = MethodName + " [complete]";
+ IndicesMap[VTables.getMethodVTableIndex(GlobalDecl(DD, Dtor_Deleting))]
+ = MethodName + " [deleting]";
} else {
- GlobalDecl GD(DD, Dtor_Deleting);
- assert(MethodVTableIndices.count(GD));
- IndicesMap[MethodVTableIndices[GD]] = MethodName + " [scalar deleting]";
+ IndicesMap[VTables.getMethodVTableIndex(GlobalDecl(DD, Dtor_Deleting))]
+ = MethodName + " [scalar deleting]";
}
} else {
- assert(MethodVTableIndices.count(MD));
- IndicesMap[MethodVTableIndices[MD]] = MethodName;
+ IndicesMap[VTables.getMethodVTableIndex(MD)] = MethodName;
}
}
uint64_t VTableIndex = I->first;
const std::string &MethodName = I->second;
- Out << llvm::format("%4" PRIu64 " | ", VTableIndex) << MethodName
+ Out << llvm::format(" %4" PRIu64 " | ", VTableIndex) << MethodName
<< '\n';
}
}
llvm::DeleteContainerSeconds(VTableLayouts);
}
+static void
+CollectPrimaryBases(const CXXRecordDecl *RD, ASTContext &Context,
+ VTableBuilder::PrimaryBasesSetVectorTy &PrimaryBases) {
+ const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
+ const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase();
+
+ if (!PrimaryBase)
+ return;
+
+ CollectPrimaryBases(PrimaryBase, Context, PrimaryBases);
+
+ if (!PrimaryBases.insert(PrimaryBase))
+ llvm_unreachable("Found a duplicate primary base!");
+}
+
+void VTableContext::ComputeMethodVTableIndices(const CXXRecordDecl *RD) {
+
+ // Itanium C++ ABI 2.5.2:
+ // The order of the virtual function pointers in a virtual table is the
+ // order of declaration of the corresponding member functions in the class.
+ //
+ // There is an entry for any virtual function declared in a class,
+ // whether it is a new function or overrides a base class function,
+ // unless it overrides a function from the primary base, and conversion
+ // between their return types does not require an adjustment.
+
+ int64_t CurrentIndex = 0;
+
+ const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
+ const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase();
+
+ if (PrimaryBase) {
+ assert(PrimaryBase->isCompleteDefinition() &&
+ "Should have the definition decl of the primary base!");
+
+ // Since the record decl shares its vtable pointer with the primary base
+ // we need to start counting at the end of the primary base's vtable.
+ CurrentIndex = getNumVirtualFunctionPointers(PrimaryBase);
+ }
+
+ // Collect all the primary bases, so we can check whether methods override
+ // a method from the base.
+ VTableBuilder::PrimaryBasesSetVectorTy PrimaryBases;
+ CollectPrimaryBases(RD, Context, PrimaryBases);
+
+ const CXXDestructorDecl *ImplicitVirtualDtor = 0;
+
+ for (CXXRecordDecl::method_iterator i = RD->method_begin(),
+ e = RD->method_end(); i != e; ++i) {
+ const CXXMethodDecl *MD = *i;
+
+ // We only want virtual methods.
+ if (!MD->isVirtual())
+ continue;
+
+ // Check if this method overrides a method in the primary base.
+ if (const CXXMethodDecl *OverriddenMD =
+ FindNearestOverriddenMethod(MD, PrimaryBases)) {
+ // Check if converting from the return type of the method to the
+ // return type of the overridden method requires conversion.
+ if (ComputeReturnAdjustmentBaseOffset(Context, MD,
+ OverriddenMD).isEmpty()) {
+ // This index is shared between the index in the vtable of the primary
+ // base class.
+ if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) {
+ const CXXDestructorDecl *OverriddenDD =
+ cast<CXXDestructorDecl>(OverriddenMD);
+
+ if (!isMicrosoftABI()) {
+ // Add both the complete and deleting entries.
+ MethodVTableIndices[GlobalDecl(DD, Dtor_Complete)] =
+ getMethodVTableIndex(GlobalDecl(OverriddenDD, Dtor_Complete));
+ MethodVTableIndices[GlobalDecl(DD, Dtor_Deleting)] =
+ getMethodVTableIndex(GlobalDecl(OverriddenDD, Dtor_Deleting));
+ } else {
+ // Add the scalar deleting destructor.
+ MethodVTableIndices[GlobalDecl(DD, Dtor_Deleting)] =
+ getMethodVTableIndex(GlobalDecl(OverriddenDD, Dtor_Deleting));
+ }
+ } else {
+ MethodVTableIndices[MD] = getMethodVTableIndex(OverriddenMD);
+ }
+
+ // We don't need to add an entry for this method.
+ continue;
+ }
+ }
+
+ if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) {
+ if (MD->isImplicit()) {
+ assert(!ImplicitVirtualDtor &&
+ "Did already see an implicit virtual dtor!");
+ ImplicitVirtualDtor = DD;
+ continue;
+ }
+
+ if (!isMicrosoftABI()) {
+ // Add the complete dtor.
+ MethodVTableIndices[GlobalDecl(DD, Dtor_Complete)] = CurrentIndex++;
+
+ // Add the deleting dtor.
+ MethodVTableIndices[GlobalDecl(DD, Dtor_Deleting)] = CurrentIndex++;
+ } else {
+ // Add the scalar deleting dtor.
+ MethodVTableIndices[GlobalDecl(DD, Dtor_Deleting)] = CurrentIndex++;
+ }
+ } else {
+ // Add the entry.
+ MethodVTableIndices[MD] = CurrentIndex++;
+ }
+ }
+
+ if (ImplicitVirtualDtor) {
+ // Itanium C++ ABI 2.5.2:
+ // If a class has an implicitly-defined virtual destructor,
+ // its entries come after the declared virtual function pointers.
+
+ if (isMicrosoftABI()) {
+ ErrorUnsupported("implicit virtual destructor in the Microsoft ABI",
+ ImplicitVirtualDtor->getLocation());
+ }
+
+ // Add the complete dtor.
+ MethodVTableIndices[GlobalDecl(ImplicitVirtualDtor, Dtor_Complete)] =
+ CurrentIndex++;
+
+ // Add the deleting dtor.
+ MethodVTableIndices[GlobalDecl(ImplicitVirtualDtor, Dtor_Deleting)] =
+ CurrentIndex++;
+ }
+
+ NumVirtualFunctionPointers[RD] = CurrentIndex;
+}
+
+uint64_t VTableContext::getNumVirtualFunctionPointers(const CXXRecordDecl *RD) {
+ llvm::DenseMap<const CXXRecordDecl *, uint64_t>::iterator I =
+ NumVirtualFunctionPointers.find(RD);
+ if (I != NumVirtualFunctionPointers.end())
+ return I->second;
+
+ ComputeMethodVTableIndices(RD);
+
+ I = NumVirtualFunctionPointers.find(RD);
+ assert(I != NumVirtualFunctionPointers.end() && "Did not find entry!");
+ return I->second;
+}
+
uint64_t VTableContext::getMethodVTableIndex(GlobalDecl GD) {
MethodVTableIndicesTy::iterator I = MethodVTableIndices.find(GD);
if (I != MethodVTableIndices.end())
const CXXRecordDecl *RD = cast<CXXMethodDecl>(GD.getDecl())->getParent();
- ComputeVTableRelatedInformation(RD);
+ ComputeMethodVTableIndices(RD);
I = MethodVTableIndices.find(GD);
assert(I != MethodVTableIndices.end() && "Did not find index!");
/*MostDerivedClassIsVirtual=*/0, RD);
Entry = CreateVTableLayout(Builder);
- MethodVTableIndices.insert(Builder.vtable_indices_begin(),
- Builder.vtable_indices_end());
-
// Add the known thunks.
Thunks.insert(Builder.thunks_begin(), Builder.thunks_end());
// CHECK-1-NEXT: 1 | Test1::A RTTI
// CHECK-1-NEXT: -- (Test1::A, 0) vtable address --
// CHECK-1-NEXT: 2 | void Test1::A::f()
-//
-// CHECK-1: VTable indices for 'Test1::A' (1 entries).
-// CHECK-1-NEXT: 0 | void Test1::A::f()
struct A {
virtual void f();
};
// CHECK-2-NEXT: 6 | Test2::A::~A() [deleting]
// CHECK-2-NEXT: 7 | void Test2::A::h()
// CHECK-2-NEXT: 8 | Test2::A &Test2::A::operator=(const Test2::A &)
-//
-// CHECK-2: VTable indices for 'Test2::A' (7 entries).
-// CHECK-2-NEXT: 0 | void Test2::A::f()
-// CHECK-2-NEXT: 1 | void Test2::A::f() const
-// CHECK-2-NEXT: 2 | Test2::A *Test2::A::g(int)
-// CHECK-2-NEXT: 3 | Test2::A::~A() [complete]
-// CHECK-2-NEXT: 4 | Test2::A::~A() [deleting]
-// CHECK-2-NEXT: 5 | void Test2::A::h()
-// CHECK-2-NEXT: 6 | Test2::A &Test2::A::operator=(const Test2::A &)
struct A {
virtual void f();
virtual void f() const;
// CHECK-3-NEXT: 3 | void Test2::B::g() [pure]
// CHECK-3-NEXT: 4 | Test2::B::~B() [complete] [pure]
// CHECK-3-NEXT: 5 | Test2::B::~B() [deleting] [pure]
-//
-// CHECK-3: VTable indices for 'Test2::B' (4 entries).
-// CHECK-3-NEXT: 0 | void Test2::B::f()
-// CHECK-3-NEXT: 1 | void Test2::B::g()
-// CHECK-3-NEXT: 2 | Test2::B::~B() [complete]
-// CHECK-3-NEXT: 3 | Test2::B::~B() [deleting]
struct B {
virtual void f();
virtual void g() = 0;
// CHECK-4-NEXT: 1 | Test3::A RTTI
// CHECK-4-NEXT: -- (Test3::A, 0) vtable address --
// CHECK-4-NEXT: 2 | void Test3::A::f()
-//
-// CHECK-4: VTable indices for 'Test3::A' (1 entries).
-// CHECK-4-NEXT: 0 | void Test3::A::f()
struct A {
virtual void f();
};
// CHECK-5-NEXT: -- (Test3::B, 0) vtable address --
// CHECK-5-NEXT: 2 | void Test3::B::f()
// CHECK-5-NEXT: 3 | void Test3::B::g()
-//
-// CHECK-5: VTable indices for 'Test3::B' (2 entries).
-// CHECK-5-NEXT: 0 | void Test3::B::f()
-// CHECK-5-NEXT: 1 | void Test3::B::g()
struct B : A {
virtual void f();
virtual void g();
// CHECK-6-NEXT: 2 | void Test3::A::f()
// CHECK-6-NEXT: 3 | void Test3::C::g()
// CHECK-6-NEXT: 4 | void Test3::C::h()
-//
-// CHECK-6: VTable indices for 'Test3::C' (2 entries).
-// CHECK-6-NEXT: 1 | void Test3::C::g()
-// CHECK-6-NEXT: 2 | void Test3::C::h()
struct C : A {
virtual void g();
virtual void h();
// CHECK-7-NEXT: 2 | void Test3::D::f()
// CHECK-7-NEXT: 3 | void Test3::D::g()
// CHECK-7-NEXT: 4 | void Test3::D::h()
-//
-// CHECK-7: VTable indices for 'Test3::D' (3 entries).
-// CHECK-7-NEXT: 0 | void Test3::D::f()
-// CHECK-7-NEXT: 1 | void Test3::D::g()
-// CHECK-7-NEXT: 2 | void Test3::D::h()
struct D : B {
virtual void f();
virtual void g();
// CHECK-8-NEXT: 2 | Test4::R3 *Test4::B::f()
// CHECK-8-NEXT: [return adjustment: 4 non-virtual]
// CHECK-8-NEXT: 3 | Test4::R3 *Test4::B::f()
-//
-// CHECK-8: VTable indices for 'Test4::B' (1 entries).
-// CHECK-8-NEXT: 1 | Test4::R3 *Test4::B::f()
+
struct B : A {
virtual R3 *f();
};
// CHECK-9-NEXT: 2 | Test4::V2 *Test4::D::f()
// CHECK-9-NEXT: [return adjustment: 0 non-virtual, -24 vbase offset offset]
// CHECK-9-NEXT: 3 | Test4::V2 *Test4::D::f()
-//
-// CHECK-9: VTable indices for 'Test4::D' (1 entries).
-// CHECK-9-NEXT: 1 | Test4::V2 *Test4::D::f()
struct D : C {
virtual V2 *f();
};
// CHECK-10-NEXT: 2 | Test4::V3 *Test4::E::f()
// CHECK-10-NEXT: [return adjustment: 4 non-virtual, -24 vbase offset offset]
// CHECK-10-NEXT: 3 | Test4::V3 *Test4::E::f()
-//
-// CHECK-10: VTable indices for 'Test4::E' (1 entries).
-// CHECK-10-NEXT: 1 | Test4::V3 *Test4::E::f()
+
struct E : A {
virtual V3 *f();
};
// CHECK-11-NEXT: 2 | Test4::R3 *Test4::F::f() [pure]
// CHECK-11-NEXT: 3 | void Test4::F::g()
// CHECK-11-NEXT: 4 | Test4::R3 *Test4::F::f() [pure]
-//
-// CHECK-11: VTable indices for 'Test4::F' (2 entries).
-// CHECK-11-NEXT: 1 | void Test4::F::g()
-// CHECK-11-NEXT: 2 | Test4::R3 *Test4::F::f()
struct F : A {
virtual void g();
virtual R3 *f() = 0;
// CHECK-12-NEXT: -- (Test5::B2, 16) vtable address --
// CHECK-12-NEXT: 7 | void Test5::A::f()
// CHECK-12-NEXT: 8 | void Test5::B2::g()
-//
-// CHECK-12: VTable indices for 'Test5::C' (1 entries).
-// CHECK-12-NEXT: 2 | void Test5::C::h()
struct C : B1, B2 {
virtual void h();
};
// CHECK-13-NEXT: -- (Test6::A2, 16) vtable address --
// CHECK-13-NEXT: 5 | void Test6::C::f()
// CHECK-13-NEXT: [this adjustment: -16 non-virtual]
-//
-// CHECK-13: VTable indices for 'Test6::C' (1 entries).
-// CHECK-13-NEXT: 0 | void Test6::C::f()
struct C : A1, A2 {
virtual void f();
};
// CHECK-14-NEXT: -- (Test7::B2, 24) vtable address --
// CHECK-14-NEXT: 9 | void Test7::D::f()
// CHECK-14-NEXT: [this adjustment: -24 non-virtual]
-//
-// CHECK-14: VTable indices for 'Test7::D' (1 entries).
-// CHECK-14-NEXT: 1 | void Test7::D::f()
struct D : C, B1, B2 {
virtual void f();
};
// CHECK-15-NEXT: 1 | Test8::B RTTI
// CHECK-15-NEXT: -- (Test8::B, 0) vtable address --
// CHECK-15-NEXT: 2 | void Test8::B::f()
-//
-// CHECK-15: VTable indices for 'Test8::B' (1 entries).
-// CHECK-15-NEXT: 0 | void Test8::B::f()
-struct B : A {
+struct B : A {
virtual void f();
};
void B::f() { }
// CHECK-16-NEXT: 3 | Test9::B RTTI
// CHECK-16-NEXT: -- (Test9::B, 0) vtable address --
// CHECK-16-NEXT: 4 | void Test9::B::f()
-//
-// CHECK-16: VTable indices for 'Test9::B' (1 entries).
-// CHECK-16-NEXT: 0 | void Test9::B::f()
struct B : virtual A1, virtual A2 {
int b;
// CHECK-17-NEXT: 5 | Test10::C RTTI
// CHECK-17-NEXT: -- (Test10::A2, 8) vtable address --
// CHECK-17-NEXT: 6 | void Test10::A2::a2()
-//
-// CHECK-17: VTable indices for 'Test10::C' (1 entries).
-// CHECK-17-NEXT: 1 | void Test10::C::f()
struct B : A1, A2 {
int b;
};
// CHECK-18-NEXT: 5 | vbase_offset (16)
// CHECK-18-NEXT: 6 | offset_to_top (-8)
// CHECK-18-NEXT: 7 | Test11::C RTTI
-//
-// CHECK-18: VTable indices for 'Test11::C' (1 entries).
-// CHECK-18-NEXT: 0 | void Test11::C::f()
struct C : virtual B {
virtual void f();
};
// CHECK-19-NEXT: 17 | Test12::B RTTI
// CHECK-19-NEXT: -- (Test12::A3, 40) vtable address --
// CHECK-19-NEXT: 18 | void Test12::A3::a3()
-//
-// CHECK-19: VTable indices for 'Test12::B' (2 entries).
-// CHECK-19-NEXT: 0 | void Test12::B::f()
-// CHECK-19-NEXT: 1 | void Test12::B::a()
struct A1 {
virtual void a1();
int a;
// CHECK-20-NEXT: -- (Test13::B, 0) vtable address --
// CHECK-20-NEXT: -- (Test13::C, 0) vtable address --
// CHECK-20-NEXT: 5 | void Test13::C::f()
-//
-// CHECK-20: VTable indices for 'Test13::C' (1 entries).
-// CHECK-20-NEXT: 0 | void Test13::C::f()
struct C : virtual B, virtual A {
virtual void f();
};
// CHECK-21-NEXT: -- (Test14::C, 0) vtable address --
// CHECK-21-NEXT: -- (Test14::D, 0) vtable address --
// CHECK-21-NEXT: 4 | void Test14::D::f()
-//
-// CHECK-21: VTable indices for 'Test14::D' (1 entries).
-// CHECK-21-NEXT: 0 | void Test14::D::f()
struct D : C, virtual B {
virtual void f();
};
// CHECK-22-NEXT: -- (Test15::B, 8) vtable address --
// CHECK-22-NEXT: -- (Test15::C, 8) vtable address --
// CHECK-22-NEXT: 10 | void Test15::B::b()
-//
-// CHECK-22: VTable indices for 'Test15::D' (1 entries).
-// CHECK-22-NEXT: 1 | void Test15::D::f()
struct D : A, virtual B, virtual C {
virtual void f();
};
// CHECK-23-NEXT: [this adjustment: -8 non-virtual, -24 vcall offset offset]
// CHECK-23-NEXT: 14 | Test16::D::~D() [deleting]
// CHECK-23-NEXT: [this adjustment: -8 non-virtual, -24 vcall offset offset]
-//
-// CHECK-23: VTable indices for 'Test16::D' (3 entries).
-// CHECK-23-NEXT: 0 | void Test16::D::f()
-// CHECK-23-NEXT: 1 | Test16::D::~D() [complete]
-// CHECK-23-NEXT: 2 | Test16::D::~D() [deleting]
struct D : virtual C {
virtual void f();
};
// CHECK-24-NEXT: -- (Test17::C, 8) vtable address --
// CHECK-24-NEXT: 12 | void Test17::E::f()
// CHECK-24-NEXT: [this adjustment: 0 non-virtual, -24 vcall offset offset]
-//
-// CHECK-24: VTable indices for 'Test17::E' (1 entries).
-// CHECK-24-NEXT: 0 | void Test17::E::f()
class E : virtual D {
virtual void f();
};
// CHECK-25-NEXT: 22 | void Test18::D::f()
// CHECK-25-NEXT: [this adjustment: -8 non-virtual, -32 vcall offset offset]
// CHECK-25-NEXT: 23 | [unused] void Test18::C::g()
-//
-// CHECK-25: VTable indices for 'Test18::D' (2 entries).
-// CHECK-25-NEXT: 0 | void Test18::D::f()
-// CHECK-25-NEXT: 2 | void Test18::D::h()
// CHECK-25: Construction vtable for ('Test18::B', 0) in 'Test18::D' (7 entries).
// CHECK-25-NEXT: 0 | vbase_offset (0)
// CHECK-26-NEXT: -- (Test19::A, 24) vtable address --
// CHECK-26-NEXT: 12 | void Test19::D::f()
// CHECK-26-NEXT: [this adjustment: 0 non-virtual, -24 vcall offset offset]
-//
-// CHECK-26: VTable indices for 'Test19::D' (1 entries).
-// CHECK-26-NEXT: 1 | void Test19::D::f()
struct D : C, B, virtual A {
virtual void f();
};
// CHECK-27-NEXT: -- (Test20::B, 8) vtable address --
// CHECK-27-NEXT: 7 | void Test20::C::f() [pure]
// CHECK-27-NEXT: 8 | void Test20::A::g()
-//
-// CHECK-27: VTable indices for 'Test20::C' (2 entries).
-// CHECK-27-NEXT: 0 | void Test20::C::f()
-// CHECK-27-NEXT: 2 | void Test20::C::h()
-struct C : A, B {
+struct C : A, B {
virtual void f() = 0;
virtual void h();
};
// CHECK-28-NEXT: Test21::C | -48
// CHECK-28-NEXT: Test21::D | -56
// CHECK-28-NEXT: Test21::E | -64
-//
-// CHECK-28: VTable indices for 'Test21::F' (1 entries).
-// CHECK-28-NEXT: 0 | void Test21::F::f()
class F : virtual D, virtual E {
virtual void f();
};
// CHECK-29-NEXT: 6 | offset_to_top (-16)
// CHECK-29-NEXT: 7 | Test22::C RTTI
// CHECK-29-NEXT: -- (Test22::V2, 16) vtable address --
-//
-// CHECK-29: VTable indices for 'Test22::C' (1 entries).
-// CHECK-29-NEXT: 0 | void Test22::C::f()
// CHECK-29: Construction vtable for ('Test22::V2', 16) in 'Test22::C' (3 entries).
// CHECK-29-NEXT: 0 | vbase_offset (-4)
// CHECK-31-NEXT: 8 | Test24::D RTTI
// CHECK-31-NEXT: -- (Test24::C, 8) vtable address --
// CHECK-31-NEXT: 9 | [unused] void Test24::D::f()
-//
-// CHECK-31: VTable indices for 'Test24::D' (1 entries).
-// CHECK-31-NEXT: 0 | void Test24::D::f()
// CHECK-31: Construction vtable for ('Test24::B', 0) in 'Test24::D' (5 entries).
// CHECK-31-NEXT: 0 | vbase_offset (0)
// CHECK-32-NEXT: 9 | Test25::C RTTI
// CHECK-32-NEXT: -- (Test25::B, 8) vtable address --
// CHECK-32-NEXT: 10 | [unused] void Test25::V::f()
-//
-// CHECK-32: VTable indices for 'Test25::C' (1 entries).
-// CHECK-32-NEXT: 1 | void Test25::C::g()
// CHECK-32: Construction vtable for ('Test25::A', 0) in 'Test25::C' (5 entries).
// CHECK-32-NEXT: 0 | vbase_offset (0)
// CHECK-33-NEXT: -- (Test26::C, 8) vtable address --
// CHECK-33-NEXT: 13 | void Test26::A::a()
// CHECK-33-NEXT: 14 | void Test26::C::b()
-//
-// CHECK-33: VTable indices for 'Test26::D' (1 entries).
-// CHECK-33-NEXT: 1 | void Test26::D::d()
// CHECK-33: Construction vtable for ('Test26::C', 8) in 'Test26::D' (7 entries).
// CHECK-33-NEXT: 0 | vcall_offset (0)
// CHECK-34-NEXT: 11 | Test27::E RTTI
// CHECK-34-NEXT: -- (Test27::B, 16) vtable address --
// CHECK-34-NEXT: 12 | void Test27::B::b()
-//
-// CHECK-34: VTable indices for 'Test27::E' (1 entries).
-// CHECK-34-NEXT: 2 | void Test27::E::e()
// CHECK-34: Construction vtable for ('Test27::D', 0) in 'Test27::E' (9 entries).
// CHECK-34-NEXT: 0 | vbase_offset (16)
// CHECK-35-NEXT: 12 | Test28::E RTTI
// CHECK-35-NEXT: -- (Test28::B, 16) vtable address --
// CHECK-35-NEXT: 13 | void Test28::B::b()
-//
-// CHECK-35: VTable indices for 'Test28::E' (1 entries).
-// CHECK-35-NEXT : 0 | void Test28::E::e()
// CHECK-35: Construction vtable for ('Test28::D', 0) in 'Test28::E' (13 entries).
// CHECK-35-NEXT: 0 | vbase_offset (8)
// CHECK-36-NEXT: [return adjustment: 0 non-virtual, -24 vbase offset offset]
// CHECK-36-NEXT: [this adjustment: 0 non-virtual, -24 vcall offset offset]
// CHECK-36-NEXT: 5 | Test29::V2 *Test29::B::f()
-//
-// CHECK-36: VTable indices for 'Test29::B' (1 entries).
-// CHECK-36-NEXT: 1 | Test29::V2 *Test29::B::f()
struct B : virtual A {
virtual V2 *f();
};
// CHECK-37-NEXT: -- (Test31::C, 8) vtable address --
// CHECK-37-NEXT: 10 | void Test31::D::f()
// CHECK-37-NEXT: [this adjustment: 0 non-virtual, -24 vcall offset offset]
-//
-// CHECK-37: VTable indices for 'Test31::D' (1 entries).
-// CHECK-37-NEXT: 0 | void Test31::D::f()
struct D : virtual C {
virtual void f();
};
// CHECK-39-NEXT: 28 | Test33::F RTTI
// CHECK-39-NEXT: -- (Test33::B, 24) vtable address --
// CHECK-39-NEXT: 29 | void Test33::B::b()
-//
-// CHECK-39: VTable indices for 'Test33::F' (1 entries).
-// CHECK-39-NEXT: 1 | void Test33::F::f()
struct F : virtual E, A {
virtual void f();
};
// CHECK-41-NEXT: 29 | void Test35::C::c()
// CHECK-41-NEXT: 30 | void Test35::D::d()
// CHECK-41-NEXT: 31 | void Test35::E::e()
-//
+
// CHECK-41: Virtual base offset offsets for 'Test35::H' (4 entries).
// CHECK-41-NEXT: Test35::A | -32
// CHECK-41-NEXT: Test35::B | -24
// CHECK-41-NEXT: Test35::D | -56
// CHECK-41-NEXT: Test35::E | -64
-//
-// CHECK-41: VTable indices for 'Test35::H' (1 entries).
-// CHECK-41-NEXT: 2 | void Test35::H::h()
struct H : F, G {
virtual void h();
};
// CHECK-42-NEXT: -- (Test36::B, 8) vtable address --
// CHECK-42-NEXT: 11 | void Test36::C::f()
// CHECK-42-NEXT: [this adjustment: 0 non-virtual, -24 vcall offset offset]
-//
-// CHECK-42: VTable indices for 'Test36::D' (1 entries).
-// CHECK-42-NEXT: 1 | void Test36::D::g()
struct D : virtual B, C {
virtual void g();
};
// CHECK-44-NEXT: -- (Test38::B, 0) vtable address --
// CHECK-44-NEXT: 5 | void *Test38::B::foo()
// CHECK-44-NEXT: 6 | const void *Test38::B::foo() const
- //
- // CHECK-44: VTable indices for 'Test38::B' (2 entries).
- // CHECK-44-NEXT: 0 | void *Test38::B::foo()
- // CHECK-44-NEXT: 1 | const void *Test38::B::foo() const
class B : virtual public A {
void *foo();
const void *foo() const;
// CHECK-45-NEXT: -- (Test39::B, 0) vtable address --
// CHECK-45-NEXT: 2 | void Test39::A::foo() [deleted]
// CHECK-45-NEXT: 3 | void Test39::B::foo2()
- //
- // CHECK-45: VTable indices for 'Test39::B' (1 entries).
- // CHECK-45-NEXT: 1 | void Test39::B::foo2()
struct B: A {
virtual void foo2();
};