summaryrefslogtreecommitdiff
path: root/clang/lib/AST/VTableBuilder.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib/AST/VTableBuilder.cpp')
-rw-r--r--clang/lib/AST/VTableBuilder.cpp154
1 files changed, 101 insertions, 53 deletions
diff --git a/clang/lib/AST/VTableBuilder.cpp b/clang/lib/AST/VTableBuilder.cpp
index 2b5b74be5961c..f5865ce96b647 100644
--- a/clang/lib/AST/VTableBuilder.cpp
+++ b/clang/lib/AST/VTableBuilder.cpp
@@ -408,7 +408,7 @@ void FinalOverriders::dump(raw_ostream &Out, BaseSubobject Base,
// Now dump the overriders for this base subobject.
for (const auto *MD : RD->methods()) {
- if (!MD->isVirtual())
+ if (!VTableContextBase::hasVtableSlot(MD))
continue;
MD = MD->getCanonicalDecl();
@@ -486,8 +486,8 @@ static bool HasSameVirtualSignature(const CXXMethodDecl *LHS,
bool VCallOffsetMap::MethodsCanShareVCallOffset(const CXXMethodDecl *LHS,
const CXXMethodDecl *RHS) {
- assert(LHS->isVirtual() && "LHS must be virtual!");
- assert(RHS->isVirtual() && "LHS must be virtual!");
+ assert(VTableContextBase::hasVtableSlot(LHS) && "LHS must be virtual!");
+ assert(VTableContextBase::hasVtableSlot(RHS) && "LHS must be virtual!");
// A destructor can share a vcall offset with another destructor.
if (isa<CXXDestructorDecl>(LHS))
@@ -535,6 +535,8 @@ public:
VBaseOffsetOffsetsMapTy;
private:
+ const ItaniumVTableContext &VTables;
+
/// MostDerivedClass - The most derived class for which we're building vcall
/// and vbase offsets.
const CXXRecordDecl *MostDerivedClass;
@@ -583,13 +585,15 @@ private:
CharUnits getCurrentOffsetOffset() const;
public:
- VCallAndVBaseOffsetBuilder(const CXXRecordDecl *MostDerivedClass,
+ VCallAndVBaseOffsetBuilder(const ItaniumVTableContext &VTables,
+ const CXXRecordDecl *MostDerivedClass,
const CXXRecordDecl *LayoutClass,
const FinalOverriders *Overriders,
BaseSubobject Base, bool BaseIsVirtual,
CharUnits OffsetInLayoutClass)
- : MostDerivedClass(MostDerivedClass), LayoutClass(LayoutClass),
- Context(MostDerivedClass->getASTContext()), Overriders(Overriders) {
+ : VTables(VTables), MostDerivedClass(MostDerivedClass),
+ LayoutClass(LayoutClass), Context(MostDerivedClass->getASTContext()),
+ Overriders(Overriders) {
// Add vcall and vbase offsets.
AddVCallAndVBaseOffsets(Base, BaseIsVirtual, OffsetInLayoutClass);
@@ -662,9 +666,13 @@ CharUnits VCallAndVBaseOffsetBuilder::getCurrentOffsetOffset() const {
// vcall offset itself).
int64_t OffsetIndex = -(int64_t)(3 + Components.size());
- CharUnits PointerWidth =
- Context.toCharUnitsFromBits(Context.getTargetInfo().getPointerWidth(0));
- CharUnits OffsetOffset = PointerWidth * OffsetIndex;
+ // Under the relative ABI, the offset widths are 32-bit ints instead of
+ // pointer widths.
+ CharUnits OffsetWidth = Context.toCharUnitsFromBits(
+ VTables.isRelativeLayout() ? 32
+ : Context.getTargetInfo().getPointerWidth(0));
+ CharUnits OffsetOffset = OffsetWidth * OffsetIndex;
+
return OffsetOffset;
}
@@ -689,7 +697,7 @@ void VCallAndVBaseOffsetBuilder::AddVCallOffsets(BaseSubobject Base,
// Add the vcall offsets.
for (const auto *MD : RD->methods()) {
- if (!MD->isVirtual())
+ if (!VTableContextBase::hasVtableSlot(MD))
continue;
MD = MD->getCanonicalDecl();
@@ -1077,7 +1085,7 @@ typedef llvm::SmallPtrSet<const CXXMethodDecl *, 8> OverriddenMethodsSetTy;
template <class VisitorTy>
static void
visitAllOverriddenMethods(const CXXMethodDecl *MD, VisitorTy &Visitor) {
- assert(MD->isVirtual() && "Method is not virtual!");
+ assert(VTableContextBase::hasVtableSlot(MD) && "Method is not virtual!");
for (const CXXMethodDecl *OverriddenMD : MD->overridden_methods()) {
if (!Visitor(OverriddenMD))
@@ -1271,13 +1279,13 @@ ThisAdjustment ItaniumVTableBuilder::ComputeThisAdjustment(
if (VCallOffsets.empty()) {
// We don't have vcall offsets for this virtual base, go ahead and
// build them.
- VCallAndVBaseOffsetBuilder Builder(MostDerivedClass, MostDerivedClass,
- /*Overriders=*/nullptr,
- BaseSubobject(Offset.VirtualBase,
- CharUnits::Zero()),
- /*BaseIsVirtual=*/true,
- /*OffsetInLayoutClass=*/
- CharUnits::Zero());
+ VCallAndVBaseOffsetBuilder Builder(
+ VTables, MostDerivedClass, MostDerivedClass,
+ /*Overriders=*/nullptr,
+ BaseSubobject(Offset.VirtualBase, CharUnits::Zero()),
+ /*BaseIsVirtual=*/true,
+ /*OffsetInLayoutClass=*/
+ CharUnits::Zero());
VCallOffsets = Builder.getVCallOffsets();
}
@@ -1474,14 +1482,14 @@ void ItaniumVTableBuilder::AddMethods(
llvm_unreachable("Found a duplicate primary base!");
}
- const CXXDestructorDecl *ImplicitVirtualDtor = nullptr;
-
typedef llvm::SmallVector<const CXXMethodDecl *, 8> NewVirtualFunctionsTy;
NewVirtualFunctionsTy NewVirtualFunctions;
+ llvm::SmallVector<const CXXMethodDecl*, 4> NewImplicitVirtualFunctions;
+
// Now go through all virtual member functions and add them.
for (const auto *MD : RD->methods()) {
- if (!MD->isVirtual())
+ if (!ItaniumVTableContext::hasVtableSlot(MD))
continue;
MD = MD->getCanonicalDecl();
@@ -1542,24 +1550,30 @@ void ItaniumVTableBuilder::AddMethods(
}
}
- 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.push_back(MD);
- }
-
- if (ImplicitVirtualDtor)
- NewVirtualFunctions.push_back(ImplicitVirtualDtor);
+ if (MD->isImplicit())
+ NewImplicitVirtualFunctions.push_back(MD);
+ else
+ NewVirtualFunctions.push_back(MD);
+ }
+
+ std::stable_sort(
+ NewImplicitVirtualFunctions.begin(), NewImplicitVirtualFunctions.end(),
+ [](const CXXMethodDecl *A, const CXXMethodDecl *B) {
+ if (A->isCopyAssignmentOperator() != B->isCopyAssignmentOperator())
+ return A->isCopyAssignmentOperator();
+ if (A->isMoveAssignmentOperator() != B->isMoveAssignmentOperator())
+ return A->isMoveAssignmentOperator();
+ if (isa<CXXDestructorDecl>(A) != isa<CXXDestructorDecl>(B))
+ return isa<CXXDestructorDecl>(A);
+ assert(A->getOverloadedOperator() == OO_EqualEqual &&
+ B->getOverloadedOperator() == OO_EqualEqual &&
+ "unexpected or duplicate implicit virtual function");
+ // We rely on Sema to have declared the operator== members in the
+ // same order as the corresponding operator<=> members.
+ return false;
+ });
+ NewVirtualFunctions.append(NewImplicitVirtualFunctions.begin(),
+ NewImplicitVirtualFunctions.end());
for (const CXXMethodDecl *MD : NewVirtualFunctions) {
// Get the final overrider.
@@ -1629,9 +1643,9 @@ void ItaniumVTableBuilder::LayoutPrimaryAndSecondaryVTables(
VTableIndices.push_back(VTableIndex);
// Add vcall and vbase offsets for this vtable.
- VCallAndVBaseOffsetBuilder Builder(MostDerivedClass, LayoutClass, &Overriders,
- Base, BaseIsVirtualInLayoutClass,
- OffsetInLayoutClass);
+ VCallAndVBaseOffsetBuilder Builder(
+ VTables, MostDerivedClass, LayoutClass, &Overriders, Base,
+ BaseIsVirtualInLayoutClass, OffsetInLayoutClass);
Components.append(Builder.components_begin(), Builder.components_end());
// Check if we need to add these vcall offsets.
@@ -2155,7 +2169,7 @@ void ItaniumVTableBuilder::dumpLayout(raw_ostream &Out) {
for (const auto *MD : MostDerivedClass->methods()) {
// We only want virtual member functions.
- if (!MD->isVirtual())
+ if (!ItaniumVTableContext::hasVtableSlot(MD))
continue;
MD = MD->getCanonicalDecl();
@@ -2194,12 +2208,40 @@ void ItaniumVTableBuilder::dumpLayout(raw_ostream &Out) {
}
}
+static VTableLayout::AddressPointsIndexMapTy
+MakeAddressPointIndices(const VTableLayout::AddressPointsMapTy &addressPoints,
+ unsigned numVTables) {
+ VTableLayout::AddressPointsIndexMapTy indexMap(numVTables);
+
+ for (auto it = addressPoints.begin(); it != addressPoints.end(); ++it) {
+ const auto &addressPointLoc = it->second;
+ unsigned vtableIndex = addressPointLoc.VTableIndex;
+ unsigned addressPoint = addressPointLoc.AddressPointIndex;
+ if (indexMap[vtableIndex]) {
+ // Multiple BaseSubobjects can map to the same AddressPointLocation, but
+ // every vtable index should have a unique address point.
+ assert(indexMap[vtableIndex] == addressPoint &&
+ "Every vtable index should have a unique address point. Found a "
+ "vtable that has two different address points.");
+ } else {
+ indexMap[vtableIndex] = addressPoint;
+ }
+ }
+
+ // Note that by this point, not all the address may be initialized if the
+ // AddressPoints map is empty. This is ok if the map isn't needed. See
+ // MicrosoftVTableContext::computeVTableRelatedInformation() which uses an
+ // emprt map.
+ return indexMap;
+}
+
VTableLayout::VTableLayout(ArrayRef<size_t> VTableIndices,
ArrayRef<VTableComponent> VTableComponents,
ArrayRef<VTableThunkTy> VTableThunks,
const AddressPointsMapTy &AddressPoints)
: VTableComponents(VTableComponents), VTableThunks(VTableThunks),
- AddressPoints(AddressPoints) {
+ AddressPoints(AddressPoints), AddressPointIndices(MakeAddressPointIndices(
+ AddressPoints, VTableIndices.size())) {
if (VTableIndices.size() <= 1)
assert(VTableIndices.size() == 1 && VTableIndices[0] == 0);
else
@@ -2215,8 +2257,13 @@ VTableLayout::VTableLayout(ArrayRef<size_t> VTableIndices,
VTableLayout::~VTableLayout() { }
-ItaniumVTableContext::ItaniumVTableContext(ASTContext &Context)
- : VTableContextBase(/*MS=*/false) {}
+bool VTableContextBase::hasVtableSlot(const CXXMethodDecl *MD) {
+ return MD->isVirtual() && !MD->isConsteval();
+}
+
+ItaniumVTableContext::ItaniumVTableContext(
+ ASTContext &Context, VTableComponentLayout ComponentLayout)
+ : VTableContextBase(/*MS=*/false), ComponentLayout(ComponentLayout) {}
ItaniumVTableContext::~ItaniumVTableContext() {}
@@ -2245,7 +2292,7 @@ ItaniumVTableContext::getVirtualBaseOffsetOffset(const CXXRecordDecl *RD,
if (I != VirtualBaseClassOffsetOffsets.end())
return I->second;
- VCallAndVBaseOffsetBuilder Builder(RD, RD, /*Overriders=*/nullptr,
+ VCallAndVBaseOffsetBuilder Builder(*this, RD, RD, /*Overriders=*/nullptr,
BaseSubobject(RD, CharUnits::Zero()),
/*BaseIsVirtual=*/false,
/*OffsetInLayoutClass=*/CharUnits::Zero());
@@ -2494,8 +2541,9 @@ private:
BasesSetVectorTy VisitedBases;
AddMethods(BaseSubobject(MostDerivedClass, CharUnits::Zero()), 0, nullptr,
VisitedBases);
- assert((HasRTTIComponent ? Components.size() - 1 : Components.size()) &&
- "vftable can't be empty");
+ // Note that it is possible for the vftable to contain only an RTTI
+ // pointer, if all virtual functions are constewval.
+ assert(!Components.empty() && "vftable can't be empty");
assert(MethodVFTableLocations.empty());
for (const auto &I : MethodInfoMap) {
@@ -2874,7 +2922,7 @@ static void GroupNewVirtualOverloads(
if (Inserted)
Groups.push_back(MethodGroup());
if (const auto *MD = dyn_cast<CXXMethodDecl>(ND))
- if (MD->isVirtual())
+ if (MicrosoftVTableContext::hasVtableSlot(MD))
Groups[J->second].push_back(MD->getCanonicalDecl());
}
@@ -3470,7 +3518,7 @@ static const FullPathTy *selectBestPath(ASTContext &Context,
getOffsetOfFullPath(Context, TopLevelRD, SpecificPath);
FinalOverriders Overriders(TopLevelRD, CharUnits::Zero(), TopLevelRD);
for (const CXXMethodDecl *MD : Info.IntroducingObject->methods()) {
- if (!MD->isVirtual())
+ if (!MicrosoftVTableContext::hasVtableSlot(MD))
continue;
FinalOverriders::OverriderInfo OI =
Overriders.getOverrider(MD->getCanonicalDecl(), BaseOffset);
@@ -3609,7 +3657,7 @@ void MicrosoftVTableContext::dumpMethodLocations(
for (const auto &I : NewMethods) {
const CXXMethodDecl *MD = cast<const CXXMethodDecl>(I.first.getDecl());
- assert(MD->isVirtual());
+ assert(hasVtableSlot(MD));
std::string MethodName = PredefinedExpr::ComputeName(
PredefinedExpr::PrettyFunctionNoVirtual, MD);
@@ -3729,7 +3777,7 @@ MicrosoftVTableContext::getVFTableLayout(const CXXRecordDecl *RD,
MethodVFTableLocation
MicrosoftVTableContext::getMethodVFTableLocation(GlobalDecl GD) {
- assert(cast<CXXMethodDecl>(GD.getDecl())->isVirtual() &&
+ assert(hasVtableSlot(cast<CXXMethodDecl>(GD.getDecl())) &&
"Only use this method for virtual methods or dtors");
if (isa<CXXDestructorDecl>(GD.getDecl()))
assert(GD.getDtorType() == Dtor_Deleting);