@@ -1147,11 +1147,38 @@ void ItaniumVTableBuilder::ComputeThisAdjustments() {
11471147 continue ;
11481148
11491149 // Add it.
1150- VTableThunks[VTableIndex].This = ThisAdjustment;
1150+ auto SetThisAdjustmentThunk = [&](uint64_t Idx) {
1151+ // If a this pointer adjustment is required, record the method that
1152+ // created the vtable entry. MD is not necessarily the method that
1153+ // created the entry since derived classes overwrite base class
1154+ // information in MethodInfoMap, hence findOriginalMethodInMap is called
1155+ // here.
1156+ //
1157+ // For example, in the following class hierarchy, if MD = D1::m and
1158+ // Overrider = D2:m, the original method that created the entry is B0:m,
1159+ // which is what findOriginalMethodInMap(MD) returns:
1160+ //
1161+ // struct B0 { int a; virtual void m(); };
1162+ // struct D0 : B0 { int a; void m() override; };
1163+ // struct D1 : B0 { int a; void m() override; };
1164+ // struct D2 : D0, D1 { int a; void m() override; };
1165+ //
1166+ // We need to record the method because we cannot
1167+ // call findOriginalMethod to find the method that created the entry if
1168+ // the method in the entry requires adjustment.
1169+ //
1170+ // Do not set ThunkInfo::Method if Idx is already in VTableThunks. This
1171+ // can happen when covariant return adjustment is required too.
1172+ if (!VTableThunks.count (Idx))
1173+ VTableThunks[Idx].Method = VTables.findOriginalMethodInMap (MD);
1174+ VTableThunks[Idx].This = ThisAdjustment;
1175+ };
1176+
1177+ SetThisAdjustmentThunk (VTableIndex);
11511178
11521179 if (isa<CXXDestructorDecl>(MD)) {
11531180 // Add an adjustment for the deleting destructor as well.
1154- VTableThunks[ VTableIndex + 1 ]. This = ThisAdjustment ;
1181+ SetThisAdjustmentThunk ( VTableIndex + 1 ) ;
11551182 }
11561183 }
11571184
@@ -1509,6 +1536,8 @@ void ItaniumVTableBuilder::AddMethods(
15091536 FindNearestOverriddenMethod (MD, PrimaryBases)) {
15101537 if (ComputeReturnAdjustmentBaseOffset (Context, MD,
15111538 OverriddenMD).isEmpty ()) {
1539+ VTables.setOriginalMethod (MD, OverriddenMD);
1540+
15121541 // Replace the method info of the overridden method with our own
15131542 // method.
15141543 assert (MethodInfoMap.count (OverriddenMD) &&
@@ -1615,6 +1644,13 @@ void ItaniumVTableBuilder::AddMethods(
16151644 ReturnAdjustment ReturnAdjustment =
16161645 ComputeReturnAdjustment (ReturnAdjustmentOffset);
16171646
1647+ // If a return adjustment is required, record the method that created the
1648+ // vtable entry. We need to record the method because we cannot call
1649+ // findOriginalMethod to find the method that created the entry if the
1650+ // method in the entry requires adjustment.
1651+ if (!ReturnAdjustment.isEmpty ())
1652+ VTableThunks[Components.size ()].Method = MD;
1653+
16181654 AddMethod (Overrider.Method , ReturnAdjustment);
16191655 }
16201656}
@@ -1890,11 +1926,32 @@ void ItaniumVTableBuilder::LayoutVTablesForVirtualBases(
18901926 }
18911927}
18921928
1929+ static void printThunkMethod (const ThunkInfo &Info, raw_ostream &Out) {
1930+ if (Info.Method ) {
1931+ std::string Str =
1932+ PredefinedExpr::ComputeName (PredefinedIdentKind::PrettyFunctionNoVirtual,
1933+ Info.Method );
1934+ Out << " method: " << Str;
1935+ }
1936+ }
1937+
18931938// / dumpLayout - Dump the vtable layout.
18941939void ItaniumVTableBuilder::dumpLayout (raw_ostream &Out) {
18951940 // FIXME: write more tests that actually use the dumpLayout output to prevent
18961941 // ItaniumVTableBuilder regressions.
18971942
1943+ Out << " Original map\n " ;
1944+
1945+ for (const auto &P : VTables.getOriginalMethodMap ()) {
1946+ std::string Str0 =
1947+ PredefinedExpr::ComputeName (PredefinedIdentKind::PrettyFunctionNoVirtual,
1948+ P.first );
1949+ std::string Str1 =
1950+ PredefinedExpr::ComputeName (PredefinedIdentKind::PrettyFunctionNoVirtual,
1951+ P.second );
1952+ Out << " " << Str0 << " -> " << Str1 << " \n " ;
1953+ }
1954+
18981955 if (isBuildingConstructorVTable ()) {
18991956 Out << " Construction vtable for ('" ;
19001957 MostDerivedClass->printQualifiedName (Out);
@@ -1978,6 +2035,7 @@ void ItaniumVTableBuilder::dumpLayout(raw_ostream &Out) {
19782035 }
19792036
19802037 Out << ' ]' ;
2038+ printThunkMethod (Thunk, Out);
19812039 }
19822040
19832041 // If this function pointer has a 'this' pointer adjustment, dump it.
@@ -1991,6 +2049,7 @@ void ItaniumVTableBuilder::dumpLayout(raw_ostream &Out) {
19912049 }
19922050
19932051 Out << ' ]' ;
2052+ printThunkMethod (Thunk, Out);
19942053 }
19952054 }
19962055
@@ -2027,6 +2086,7 @@ void ItaniumVTableBuilder::dumpLayout(raw_ostream &Out) {
20272086
20282087 Out << ' ]' ;
20292088 }
2089+ printThunkMethod (Thunk, Out);
20302090 }
20312091
20322092 break ;
@@ -2125,7 +2185,6 @@ void ItaniumVTableBuilder::dumpLayout(raw_ostream &Out) {
21252185
21262186 ThunkInfoVectorTy ThunksVector = Thunks[MD];
21272187 llvm::sort (ThunksVector, [](const ThunkInfo &LHS, const ThunkInfo &RHS) {
2128- assert (LHS.Method == nullptr && RHS.Method == nullptr );
21292188 return std::tie (LHS.This , LHS.Return ) < std::tie (RHS.This , RHS.Return );
21302189 });
21312190
@@ -2314,6 +2373,35 @@ ItaniumVTableContext::getVirtualBaseOffsetOffset(const CXXRecordDecl *RD,
23142373 return I->second ;
23152374}
23162375
2376+ GlobalDecl ItaniumVTableContext::findOriginalMethod (GlobalDecl GD) {
2377+ const auto *MD = cast<CXXMethodDecl>(GD.getDecl ());
2378+ computeVTableRelatedInformation (MD->getParent ());
2379+ const auto *OriginalMD = findOriginalMethodInMap (MD);
2380+
2381+ if (const auto *DD = dyn_cast<CXXDestructorDecl>(OriginalMD))
2382+ return GlobalDecl (DD, GD.getDtorType ());
2383+ return OriginalMD;
2384+ }
2385+
2386+ const CXXMethodDecl *
2387+ ItaniumVTableContext::findOriginalMethodInMap (const CXXMethodDecl *MD) const {
2388+ // Traverse the chain of virtual methods until we find the method that added
2389+ // the v-table slot.
2390+ while (true ) {
2391+ auto I = OriginalMethodMap.find (MD);
2392+
2393+ // MD doesn't exist in OriginalMethodMap, so it must be the method we are
2394+ // looking for.
2395+ if (I == OriginalMethodMap.end ())
2396+ break ;
2397+
2398+ // Set MD to the overridden method.
2399+ MD = I->second ;
2400+ }
2401+
2402+ return MD;
2403+ }
2404+
23172405static std::unique_ptr<VTableLayout>
23182406CreateVTableLayout (const ItaniumVTableBuilder &Builder) {
23192407 SmallVector<VTableLayout::VTableThunkTy, 1 >
0 commit comments