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
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to