[clang] [CIR] Add support for emitting vtables (PR #154808)
via cfe-commits
cfe-commits at lists.llvm.org
Thu Aug 21 10:58:34 PDT 2025
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clangir
Author: Andy Kaylor (andykaylor)
<details>
<summary>Changes</summary>
This adds a simplified version of the code to emit vtables. It does not yet handle RTTI or cases that require multiple vtables.
---
Patch is 27.15 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/154808.diff
12 Files Affected:
- (modified) clang/include/clang/CIR/MissingFeatures.h (+1)
- (modified) clang/lib/CIR/CodeGen/CIRGenCXXABI.h (+4)
- (modified) clang/lib/CIR/CodeGen/CIRGenCall.cpp (+15)
- (modified) clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp (+63)
- (modified) clang/lib/CIR/CodeGen/CIRGenModule.cpp (+13-1)
- (modified) clang/lib/CIR/CodeGen/CIRGenModule.h (+17)
- (modified) clang/lib/CIR/CodeGen/CIRGenTypes.h (+7)
- (modified) clang/lib/CIR/CodeGen/CIRGenVTables.cpp (+206-2)
- (modified) clang/lib/CIR/CodeGen/CIRGenVTables.h (+22-1)
- (modified) clang/lib/CIR/CodeGen/CIRGenerator.cpp (+1-1)
- (modified) clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp (+23-4)
- (added) clang/test/CIR/CodeGen/vtable-emission.cpp (+38)
``````````diff
diff --git a/clang/include/clang/CIR/MissingFeatures.h b/clang/include/clang/CIR/MissingFeatures.h
index 49c66a40e47b6..e2326b1031765 100644
--- a/clang/include/clang/CIR/MissingFeatures.h
+++ b/clang/include/clang/CIR/MissingFeatures.h
@@ -279,6 +279,7 @@ struct MissingFeatures {
static bool appleKext() { return false; }
static bool dtorCleanups() { return false; }
static bool vtableInitialization() { return false; }
+ static bool vtableEmitMetadata() { return false; }
static bool vtableRelativeLayout() { return false; }
static bool msvcBuiltins() { return false; }
static bool vaArgABILowering() { return false; }
diff --git a/clang/lib/CIR/CodeGen/CIRGenCXXABI.h b/clang/lib/CIR/CodeGen/CIRGenCXXABI.h
index 3f1cb8363a556..b5f2e1a067274 100644
--- a/clang/lib/CIR/CodeGen/CIRGenCXXABI.h
+++ b/clang/lib/CIR/CodeGen/CIRGenCXXABI.h
@@ -95,6 +95,10 @@ class CIRGenCXXABI {
isVirtualOffsetNeededForVTableField(CIRGenFunction &cgf,
CIRGenFunction::VPtr vptr) = 0;
+ /// Emits the VTable definitions required for the given record type.
+ virtual void emitVTableDefinitions(CIRGenVTables &cgvt,
+ const CXXRecordDecl *rd) = 0;
+
/// Returns true if the given destructor type should be emitted as a linkonce
/// delegating thunk, regardless of whether the dtor is defined in this TU or
/// not.
diff --git a/clang/lib/CIR/CodeGen/CIRGenCall.cpp b/clang/lib/CIR/CodeGen/CIRGenCall.cpp
index 6d749940fa128..8a15e5f96aea2 100644
--- a/clang/lib/CIR/CodeGen/CIRGenCall.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenCall.cpp
@@ -42,6 +42,11 @@ CIRGenFunctionInfo::create(CanQualType resultType,
return fi;
}
+cir::FuncType CIRGenTypes::getFunctionType(GlobalDecl gd) {
+ const CIRGenFunctionInfo &fi = arrangeGlobalDeclaration(gd);
+ return getFunctionType(fi);
+}
+
cir::FuncType CIRGenTypes::getFunctionType(const CIRGenFunctionInfo &info) {
mlir::Type resultType = convertType(info.getReturnType());
SmallVector<mlir::Type, 8> argTypes;
@@ -55,6 +60,16 @@ cir::FuncType CIRGenTypes::getFunctionType(const CIRGenFunctionInfo &info) {
info.isVariadic());
}
+cir::FuncType CIRGenTypes::getFunctionTypeForVTable(GlobalDecl gd) {
+ const CXXMethodDecl *md = cast<CXXMethodDecl>(gd.getDecl());
+ const FunctionProtoType *fpt = md->getType()->getAs<FunctionProtoType>();
+
+ if (!isFuncTypeConvertible(fpt))
+ cgm.errorNYI("getFunctionTypeForVTable: non-convertible function type");
+
+ return getFunctionType(gd);
+}
+
CIRGenCallee CIRGenCallee::prepareConcreteCallee(CIRGenFunction &cgf) const {
if (isVirtual()) {
const CallExpr *ce = getVirtualCallExpr();
diff --git a/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp b/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp
index 347656b5f6488..aaf7dc767d888 100644
--- a/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp
@@ -81,6 +81,8 @@ class CIRGenItaniumCXXABI : public CIRGenCXXABI {
CIRGenFunction &cgf, const clang::CXXRecordDecl *vtableClass,
clang::BaseSubobject base,
const clang::CXXRecordDecl *nearestVBase) override;
+ void emitVTableDefinitions(CIRGenVTables &cgvt,
+ const CXXRecordDecl *rd) override;
bool doStructorsInitializeVPtrs(const CXXRecordDecl *vtableClass) override {
return true;
@@ -270,6 +272,67 @@ bool CIRGenItaniumCXXABI::needsVTTParameter(GlobalDecl gd) {
return false;
}
+void CIRGenItaniumCXXABI::emitVTableDefinitions(CIRGenVTables &cgvt,
+ const CXXRecordDecl *rd) {
+ cir::GlobalOp vtable = getAddrOfVTable(rd, CharUnits());
+ if (vtable.hasInitializer())
+ return;
+
+ ItaniumVTableContext &vtContext = cgm.getItaniumVTableContext();
+ const VTableLayout &vtLayout = vtContext.getVTableLayout(rd);
+ cir::GlobalLinkageKind linkage = cgm.getVTableLinkage(rd);
+ mlir::Attribute rtti =
+ cgm.getAddrOfRTTIDescriptor(cgm.getLoc(rd->getBeginLoc()),
+ cgm.getASTContext().getCanonicalTagType(rd));
+
+ // Classic codegen uses ConstantInitBuilder here, which is a very general
+ // and feature-rich class to generate initializers for global values.
+ // For now, this is using a simpler approach to create the initializer in CIR.
+ cgvt.createVTableInitializer(vtable, vtLayout, rtti,
+ cir::isLocalLinkage(linkage));
+
+ // Set the correct linkage.
+ vtable.setLinkage(linkage);
+
+ if (cgm.supportsCOMDAT() && cir::isWeakForLinker(linkage))
+ vtable.setComdat(true);
+
+ // Set the right visibility.
+ cgm.setGVProperties(vtable, rd);
+
+ // If this is the magic class __cxxabiv1::__fundamental_type_info,
+ // we will emit the typeinfo for the fundamental types. This is the
+ // same behaviour as GCC.
+ const DeclContext *DC = rd->getDeclContext();
+ if (rd->getIdentifier() &&
+ rd->getIdentifier()->isStr("__fundamental_type_info") &&
+ isa<NamespaceDecl>(DC) && cast<NamespaceDecl>(DC)->getIdentifier() &&
+ cast<NamespaceDecl>(DC)->getIdentifier()->isStr("__cxxabiv1") &&
+ DC->getParent()->isTranslationUnit()) {
+ cgm.errorNYI(rd->getSourceRange(),
+ "emitVTableDefinitions: __fundamental_type_info");
+ }
+
+ auto vtableAsGlobalValue = dyn_cast<cir::CIRGlobalValueInterface>(*vtable);
+ assert(vtableAsGlobalValue && "VTable must support CIRGlobalValueInterface");
+ // Always emit type metadata on non-available_externally definitions, and on
+ // available_externally definitions if we are performing whole program
+ // devirtualization. For WPD we need the type metadata on all vtable
+ // definitions to ensure we associate derived classes with base classes
+ // defined in headers but with a strong definition only in a shared
+ // library.
+ assert(!cir::MissingFeatures::vtableEmitMetadata());
+ if (cgm.getCodeGenOpts().WholeProgramVTables) {
+ cgm.errorNYI(rd->getSourceRange(),
+ "emitVTableDefinitions: WholeProgramVTables");
+ }
+
+ assert(!cir::MissingFeatures::vtableRelativeLayout());
+ if (vtContext.isRelativeLayout()) {
+ cgm.errorNYI(rd->getSourceRange(), "vtableRelativeLayout");
+ }
+}
+
void CIRGenItaniumCXXABI::emitDestructorCall(
CIRGenFunction &cgf, const CXXDestructorDecl *dd, CXXDtorType type,
bool forVirtualBase, bool delegating, Address thisAddr, QualType thisTy) {
diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.cpp b/clang/lib/CIR/CodeGen/CIRGenModule.cpp
index a557d2aae9dd9..46bca51767c02 100644
--- a/clang/lib/CIR/CodeGen/CIRGenModule.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenModule.cpp
@@ -845,7 +845,7 @@ void CIRGenModule::emitGlobalDefinition(clang::GlobalDecl gd,
emitGlobalFunctionDefinition(gd, op);
if (method->isVirtual())
- errorNYI(method->getSourceRange(), "virtual member function");
+ getVTables().emitThunks(gd);
return;
}
@@ -2151,6 +2151,18 @@ bool CIRGenModule::verifyModule() const {
return mlir::verify(theModule).succeeded();
}
+mlir::Attribute CIRGenModule::getAddrOfRTTIDescriptor(mlir::Location loc,
+ QualType ty, bool forEh) {
+ // Return a bogus pointer if RTTI is disabled, unless it's for EH.
+ // FIXME: should we even be calling this method if RTTI is disabled
+ // and it's not for EH?
+ if (!shouldEmitRTTI(forEh))
+ return builder.getConstNullPtrAttr(builder.getUInt8PtrTy());
+
+ errorNYI(loc, "getAddrOfRTTIDescriptor");
+ return mlir::Attribute();
+}
+
// TODO(cir): this can be shared with LLVM codegen.
CharUnits CIRGenModule::computeNonVirtualBaseClassOffset(
const CXXRecordDecl *derivedClass,
diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.h b/clang/lib/CIR/CodeGen/CIRGenModule.h
index 128e2af5e1126..d90baa55d0b5c 100644
--- a/clang/lib/CIR/CodeGen/CIRGenModule.h
+++ b/clang/lib/CIR/CodeGen/CIRGenModule.h
@@ -190,6 +190,16 @@ class CIRGenModule : public CIRGenTypeCache {
mlir::Location loc, llvm::StringRef name, mlir::Type ty,
cir::GlobalLinkageKind linkage, clang::CharUnits alignment);
+ void emitVTable(const CXXRecordDecl *rd);
+
+ /// Return the appropriate linkage for the vtable, VTT, and type information
+ /// of the given class.
+ cir::GlobalLinkageKind getVTableLinkage(const CXXRecordDecl *rd);
+
+ /// Get the address of the RTTI descriptor for the given type.
+ mlir::Attribute getAddrOfRTTIDescriptor(mlir::Location loc, QualType ty,
+ bool forEH = false);
+
/// Return a constant array for the given string.
mlir::Attribute getConstantArrayFromStringLiteral(const StringLiteral *e);
@@ -290,6 +300,13 @@ class CIRGenModule : public CIRGenTypeCache {
getAddrOfGlobal(clang::GlobalDecl gd,
ForDefinition_t isForDefinition = NotForDefinition);
+ // Return whether RTTI information should be emitted for this target.
+ bool shouldEmitRTTI(bool forEH = false) {
+ return (forEH || getLangOpts().RTTI) && !getLangOpts().CUDAIsDevice &&
+ !(getLangOpts().OpenMP && getLangOpts().OpenMPIsTargetDevice &&
+ getTriple().isNVPTX());
+ }
+
/// Emit type info if type of an expression is a variably modified
/// type. Also emit proper debug info for cast types.
void emitExplicitCastExprType(const ExplicitCastExpr *e,
diff --git a/clang/lib/CIR/CodeGen/CIRGenTypes.h b/clang/lib/CIR/CodeGen/CIRGenTypes.h
index c2813d79bf63b..7af0d956e7d56 100644
--- a/clang/lib/CIR/CodeGen/CIRGenTypes.h
+++ b/clang/lib/CIR/CodeGen/CIRGenTypes.h
@@ -130,6 +130,13 @@ class CIRGenTypes {
/// Get the CIR function type for \arg Info.
cir::FuncType getFunctionType(const CIRGenFunctionInfo &info);
+ cir::FuncType getFunctionType(clang::GlobalDecl gd);
+
+ /// Get the CIR function type for use in a vtable, given a CXXMethodDecl. If
+ /// the method has an incomplete return type, and/or incomplete argument
+ /// types, this will return the opaque type.
+ cir::FuncType getFunctionTypeForVTable(clang::GlobalDecl gd);
+
// The arrangement methods are split into three families:
// - those meant to drive the signature and prologue/epilogue
// of a function declaration or definition,
diff --git a/clang/lib/CIR/CodeGen/CIRGenVTables.cpp b/clang/lib/CIR/CodeGen/CIRGenVTables.cpp
index fdd1a6e3f57ef..dec73ba793b1d 100644
--- a/clang/lib/CIR/CodeGen/CIRGenVTables.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenVTables.cpp
@@ -11,6 +11,8 @@
//===----------------------------------------------------------------------===//
#include "CIRGenVTables.h"
+
+#include "CIRGenCXXABI.h"
#include "CIRGenModule.h"
#include "mlir/IR/Types.h"
#include "clang/AST/VTableBuilder.h"
@@ -33,9 +35,9 @@ mlir::Type CIRGenVTables::getVTableComponentType() {
return cgm.getVTableComponentType();
}
-mlir::Type CIRGenVTables::getVTableType(const VTableLayout &layout) {
+cir::RecordType CIRGenVTables::getVTableType(const VTableLayout &layout) {
SmallVector<mlir::Type, 4> tys;
- auto componentType = getVTableComponentType();
+ mlir::Type componentType = getVTableComponentType();
for (unsigned i = 0, e = layout.getNumVTables(); i != e; ++i)
tys.push_back(cir::ArrayType::get(componentType, layout.getVTableSize(i)));
@@ -43,3 +45,205 @@ mlir::Type CIRGenVTables::getVTableType(const VTableLayout &layout) {
// AST nodes?
return cgm.getBuilder().getAnonRecordTy(tys, /*incomplete=*/false);
}
+
+/// This is a callback from Sema to tell us that a particular vtable is
+/// required to be emitted in this translation unit.
+///
+/// This is only called for vtables that _must_ be emitted (mainly due to key
+/// functions). For weak vtables, CodeGen tracks when they are needed and
+/// emits them as-needed.
+void CIRGenModule::emitVTable(const CXXRecordDecl *rd) {
+ vtables.generateClassData(rd);
+}
+
+void CIRGenVTables::generateClassData(const CXXRecordDecl *rd) {
+ assert(!cir::MissingFeatures::generateDebugInfo());
+
+ if (rd->getNumVBases())
+ cgm.errorNYI(rd->getSourceRange(), "emitVirtualInheritanceTables");
+
+ cgm.getCXXABI().emitVTableDefinitions(*this, rd);
+}
+
+mlir::Attribute CIRGenVTables::getVTableComponent(
+ const VTableLayout &layout, unsigned componentIndex, mlir::Attribute rtti,
+ unsigned &nextVTableThunkIndex, unsigned vtableAddressPoint,
+ bool vtableHasLocalLinkage) {
+ auto &component = layout.vtable_components()[componentIndex];
+
+ CIRGenBuilderTy builder = cgm.getBuilder();
+
+ assert(!cir::MissingFeatures::vtableRelativeLayout());
+
+ switch (component.getKind()) {
+ case VTableComponent::CK_VCallOffset:
+ cgm.errorNYI("getVTableComponent: VCallOffset");
+ return mlir::Attribute();
+ case VTableComponent::CK_VBaseOffset:
+ cgm.errorNYI("getVTableComponent: VBaseOffset");
+ return mlir::Attribute();
+ case VTableComponent::CK_CompleteDtorPointer:
+ cgm.errorNYI("getVTableComponent: CompleteDtorPointer");
+ return mlir::Attribute();
+ case VTableComponent::CK_DeletingDtorPointer:
+ cgm.errorNYI("getVTableComponent: DeletingDtorPointer");
+ return mlir::Attribute();
+ case VTableComponent::CK_UnusedFunctionPointer:
+ cgm.errorNYI("getVTableComponent: UnusedFunctionPointer");
+ return mlir::Attribute();
+
+ case VTableComponent::CK_OffsetToTop:
+ return builder.getConstPtrAttr(builder.getUInt8PtrTy(),
+ component.getOffsetToTop().getQuantity());
+
+ case VTableComponent::CK_RTTI:
+ assert((mlir::isa<cir::GlobalViewAttr>(rtti) ||
+ mlir::isa<cir::ConstPtrAttr>(rtti)) &&
+ "expected GlobalViewAttr or ConstPtrAttr");
+ return rtti;
+
+ case VTableComponent::CK_FunctionPointer: {
+ GlobalDecl gd = component.getGlobalDecl();
+
+ assert(!cir::MissingFeatures::cudaSupport());
+
+ cir::FuncOp fnPtr;
+ if (cast<CXXMethodDecl>(gd.getDecl())->isPureVirtual()) {
+ cgm.errorNYI("getVTableComponent: CK_FunctionPointer: pure virtual");
+ return mlir::Attribute();
+ } else if (cast<CXXMethodDecl>(gd.getDecl())->isDeleted()) {
+ cgm.errorNYI("getVTableComponent: CK_FunctionPointer: deleted virtual");
+ return mlir::Attribute();
+ } else if (nextVTableThunkIndex < layout.vtable_thunks().size() &&
+ layout.vtable_thunks()[nextVTableThunkIndex].first ==
+ componentIndex) {
+ cgm.errorNYI("getVTableComponent: CK_FunctionPointer: thunk");
+ return mlir::Attribute();
+ } else {
+ // Otherwise we can use the method definition directly.
+ cir::FuncType fnTy = cgm.getTypes().getFunctionTypeForVTable(gd);
+ fnPtr = cgm.getAddrOfFunction(gd, fnTy, /*ForVTable=*/true);
+ }
+
+ return cir::GlobalViewAttr::get(
+ builder.getUInt8PtrTy(),
+ mlir::FlatSymbolRefAttr::get(fnPtr.getSymNameAttr()));
+ }
+ }
+
+ llvm_unreachable("Unexpected vtable component kind");
+}
+
+void CIRGenVTables::createVTableInitializer(cir::GlobalOp &vtableOp,
+ const clang::VTableLayout &layout,
+ mlir::Attribute rtti,
+ bool vtableHasLocalLinkage) {
+ mlir::Type componentType = getVTableComponentType();
+
+ const llvm::SmallVector<unsigned, 4> &addressPoints =
+ layout.getAddressPointIndices();
+ unsigned nextVTableThunkIndex = 0;
+
+ if (layout.getNumVTables() > 1)
+ cgm.errorNYI("emitVTableDefinitions: multiple vtables");
+
+ // We'll need a loop here to handle multiple vtables, but for now we only
+ // support one.
+ unsigned vtableIndex = 0;
+ size_t vtableStart = layout.getVTableOffset(vtableIndex);
+ size_t vtableEnd = vtableStart + layout.getVTableSize(vtableIndex);
+
+ // Build a ConstArrayAttr of the vtable components.
+ llvm::SmallVector<mlir::Attribute, 4> components;
+ for (size_t componentIndex = vtableStart; componentIndex < vtableEnd;
+ ++componentIndex) {
+ components.push_back(
+ getVTableComponent(layout, componentIndex, rtti, nextVTableThunkIndex,
+ addressPoints[vtableIndex], vtableHasLocalLinkage));
+ }
+
+ mlir::MLIRContext *mlirContext = &cgm.getMLIRContext();
+
+ // Create a ConstArrayAttr to hold the components.
+ auto arr = cir::ConstArrayAttr::get(
+ cir::ArrayType::get(componentType, components.size()),
+ mlir::ArrayAttr::get(mlirContext, components));
+
+ // Create a ConstRecordAttr to hold the component array.
+ const auto members = mlir::ArrayAttr::get(mlirContext, {arr});
+ cir::ConstRecordAttr record = cgm.getBuilder().getAnonConstRecord(members);
+
+ // Create a VTableAttr
+ auto vtableAttr = cir::VTableAttr::get(record.getType(), record.getMembers());
+
+ // Add the vtable initializer to the vtable global op.
+ cgm.setInitializer(vtableOp, vtableAttr);
+}
+
+/// Compute the required linkage of the vtable for the given class.
+///
+/// Note that we only call this at the end of the translation unit.
+cir::GlobalLinkageKind CIRGenModule::getVTableLinkage(const CXXRecordDecl *rd) {
+ if (!rd->isExternallyVisible())
+ return cir::GlobalLinkageKind::InternalLinkage;
+
+ // We're at the end of the translation unit, so the current key
+ // function is fully correct.
+ const CXXMethodDecl *keyFunction = astContext.getCurrentKeyFunction(rd);
+ if (keyFunction && !rd->hasAttr<DLLImportAttr>()) {
+ // If this class has a key function, use that to determine the
+ // linkage of the vtable.
+ const FunctionDecl *def = nullptr;
+ if (keyFunction->hasBody(def))
+ keyFunction = cast<CXXMethodDecl>(def);
+
+ // All of the cases below do something different with AppleKext enabled.
+ assert(!cir::MissingFeatures::appleKext());
+ switch (keyFunction->getTemplateSpecializationKind()) {
+ case TSK_Undeclared:
+ case TSK_ExplicitSpecialization:
+ assert(
+ (def || codeGenOpts.OptimizationLevel > 0 ||
+ codeGenOpts.getDebugInfo() != llvm::codegenoptions::NoDebugInfo) &&
+ "Shouldn't query vtable linkage without key function, "
+ "optimizations, or debug info");
+ if (!def && codeGenOpts.OptimizationLevel > 0)
+ return cir::GlobalLinkageKind::AvailableExternallyLinkage;
+
+ if (keyFunction->isInlined())
+ return !astContext.getLangOpts().AppleKext
+ ? cir::GlobalLinkageKind::LinkOnceODRLinkage
+ : cir::GlobalLinkageKind::InternalLinkage;
+ return cir::GlobalLinkageKind::ExternalLinkage;
+
+ case TSK_ImplicitInstantiation:
+ return cir::GlobalLinkageKind::LinkOnceODRLinkage;
+
+ case TSK_ExplicitInstantiationDefinition:
+ return cir::GlobalLinkageKind::WeakODRLinkage;
+
+ case TSK_ExplicitInstantiationDeclaration:
+ llvm_unreachable("Should not have been asked to emit this");
+ }
+ }
+
+ errorNYI(rd->getSourceRange(), "getVTableLinkage: no key function");
+ return cir::GlobalLinkageKind::ExternalLinkage;
+}
+
+void CIRGenVTables::emitThunks(GlobalDecl gd) {
+ const CXXMethodDecl *md =
+ cast<CXXMethodDecl>(gd.getDecl())->getCanonicalDecl();
+
+ // We don't need to generate thunks for the base destructor.
+ if (isa<CXXDestructorDecl>(md) && gd.getDtorType() == Dtor_Base)
+ return;
+
+ const VTableContextBase::ThunkInfoVectorTy *thunkInfoVector =
+ vtContext->getThunkInfo(gd);
+
+ if (!thunkInfoVector)
+ return;
+
+ cgm.errorNYI(md->getSourceRange(), "emitThunks");
+}
diff --git a/clang/lib/CIR/CodeGen/CIRGenVTables.h b/clang/lib/CIR/CodeGen/CIRGenVTables.h
index 66318c5f2393a..518d7d78f1737 100644
--- a/clang/lib/CIR/CodeGen/CIRGenVTables.h
+++ b/clang/lib/CIR/CodeGen/CIRGenVTables.h
@@ -16,6 +16,7 @@
#include "mlir/IR/Types.h"
#include "clang/AST/GlobalDecl.h"
#include "clang/AST/VTableBuilder.h"
+#include "clang/CIR/Dialect/IR/CIRDialect.h"
namespace clang {
class CXXRecordDecl;
@@ -29,11 +30,23 @@ class CIRGenVTables {
clang::VTableContextBase *vtContext;
+ mlir::Attribute
+ getVTableComponent(const VTableLayout &layout, unsigned componentIndex,
+ mlir::Attribute rtti, unsigned &nextVTableThunkIndex,
+ unsigned vtableAddressPoint, bool vtableHasLocalLinkage);
+
mlir::Type getVTableComponentType();
public:
CIRGenVTables(CIRGenModule &cgm);
+ /// Add vtable components for the giv...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/154808
More information about the cfe-commits
mailing list