aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm-project/clang/lib/CodeGen/CGVTables.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm-project/clang/lib/CodeGen/CGVTables.cpp')
-rw-r--r--contrib/llvm-project/clang/lib/CodeGen/CGVTables.cpp267
1 files changed, 151 insertions, 116 deletions
diff --git a/contrib/llvm-project/clang/lib/CodeGen/CGVTables.cpp b/contrib/llvm-project/clang/lib/CodeGen/CGVTables.cpp
index bef9a293b7ed..8dee3f74b44b 100644
--- a/contrib/llvm-project/clang/lib/CodeGen/CGVTables.cpp
+++ b/contrib/llvm-project/clang/lib/CodeGen/CGVTables.cpp
@@ -24,6 +24,7 @@
#include "llvm/Transforms/Utils/Cloning.h"
#include <algorithm>
#include <cstdio>
+#include <utility>
using namespace clang;
using namespace CodeGen;
@@ -90,9 +91,11 @@ static RValue PerformReturnAdjustment(CodeGenFunction &CGF,
auto ClassDecl = ResultType->getPointeeType()->getAsCXXRecordDecl();
auto ClassAlign = CGF.CGM.getClassPointerAlignment(ClassDecl);
- ReturnValue = CGF.CGM.getCXXABI().performReturnAdjustment(CGF,
- Address(ReturnValue, ClassAlign),
- Thunk.Return);
+ ReturnValue = CGF.CGM.getCXXABI().performReturnAdjustment(
+ CGF,
+ Address(ReturnValue, CGF.ConvertTypeForMem(ResultType->getPointeeType()),
+ ClassAlign),
+ Thunk.Return);
if (NullCheckValue) {
CGF.Builder.CreateBr(AdjustEnd);
@@ -126,7 +129,7 @@ static void resolveTopLevelMetadata(llvm::Function *Fn,
// Find all llvm.dbg.declare intrinsics and resolve the DILocalVariable nodes
// they are referencing.
- for (auto &BB : Fn->getBasicBlockList()) {
+ for (auto &BB : *Fn) {
for (auto &I : BB) {
if (auto *DII = dyn_cast<llvm::DbgVariableIntrinsic>(&I)) {
auto *DILocal = DII->getVariable();
@@ -198,10 +201,12 @@ CodeGenFunction::GenerateVarArgsThunk(llvm::Function *Fn,
// Find the first store of "this", which will be to the alloca associated
// with "this".
- Address ThisPtr(&*AI, CGM.getClassPointerAlignment(MD->getParent()));
+ Address ThisPtr =
+ Address(&*AI, ConvertTypeForMem(MD->getFunctionObjectParameterType()),
+ CGM.getClassPointerAlignment(MD->getParent()));
llvm::BasicBlock *EntryBB = &Fn->front();
llvm::BasicBlock::iterator ThisStore =
- std::find_if(EntryBB->begin(), EntryBB->end(), [&](llvm::Instruction &I) {
+ llvm::find_if(*EntryBB, [&](llvm::Instruction &I) {
return isa<llvm::StoreInst>(I) &&
I.getOperand(0) == ThisPtr.getPointer();
});
@@ -396,9 +401,7 @@ void CodeGenFunction::EmitMustTailThunk(GlobalDecl GD,
// to translate AST arguments into LLVM IR arguments. For thunks, we know
// that the caller prototype more or less matches the callee prototype with
// the exception of 'this'.
- SmallVector<llvm::Value *, 8> Args;
- for (llvm::Argument &A : CurFn->args())
- Args.push_back(&A);
+ SmallVector<llvm::Value *, 8> Args(llvm::make_pointer_range(CurFn->args()));
// Set the adjusted 'this' pointer.
const ABIArgInfo &ThisAI = CurFnInfo->arg_begin()->info;
@@ -427,7 +430,8 @@ void CodeGenFunction::EmitMustTailThunk(GlobalDecl GD,
unsigned CallingConv;
llvm::AttributeList Attrs;
CGM.ConstructAttributeList(Callee.getCallee()->getName(), *CurFnInfo, GD,
- Attrs, CallingConv, /*AttrOnCallSite=*/true);
+ Attrs, CallingConv, /*AttrOnCallSite=*/true,
+ /*IsThunk=*/false);
Call->setAttributes(Attrs);
Call->setCallingConv(static_cast<llvm::CallingConv::ID>(CallingConv));
@@ -461,10 +465,6 @@ void CodeGenFunction::generateThunk(llvm::Function *Fn,
llvm::Constant *Callee = CGM.GetAddrOfFunction(GD, Ty, /*ForVTable=*/true);
- // Fix up the function type for an unprototyped musttail call.
- if (IsUnprototyped)
- Callee = llvm::ConstantExpr::getBitCast(Callee, Fn->getType());
-
// Make the call and return the result.
EmitCallAndReturnForThunk(llvm::FunctionCallee(Fn->getFunctionType(), Callee),
&Thunk, IsUnprototyped);
@@ -531,13 +531,10 @@ llvm::Constant *CodeGenVTables::maybeEmitThunk(GlobalDecl GD,
OldThunkFn->setName(StringRef());
ThunkFn = llvm::Function::Create(ThunkFnTy, llvm::Function::ExternalLinkage,
Name.str(), &CGM.getModule());
- CGM.SetLLVMFunctionAttributes(MD, FnInfo, ThunkFn);
+ CGM.SetLLVMFunctionAttributes(MD, FnInfo, ThunkFn, /*IsThunk=*/false);
- // If needed, replace the old thunk with a bitcast.
if (!OldThunkFn->use_empty()) {
- llvm::Constant *NewPtrForOldDecl =
- llvm::ConstantExpr::getBitCast(ThunkFn, OldThunkFn->getType());
- OldThunkFn->replaceAllUsesWith(NewPtrForOldDecl);
+ OldThunkFn->replaceAllUsesWith(ThunkFn);
}
// Remove the old thunk.
@@ -636,8 +633,16 @@ void CodeGenVTables::addRelativeComponent(ConstantArrayBuilder &builder,
// want the stub/proxy to be emitted for properly calculating the offset.
// Examples where there would be no symbol emitted are available_externally
// and private linkages.
- auto stubLinkage = vtableHasLocalLinkage ? llvm::GlobalValue::InternalLinkage
- : llvm::GlobalValue::ExternalLinkage;
+ //
+ // `internal` linkage results in STB_LOCAL Elf binding while still manifesting a
+ // local symbol.
+ //
+ // `linkonce_odr` linkage results in a STB_DEFAULT Elf binding but also allows for
+ // the rtti_proxy to be transparently replaced with a GOTPCREL reloc by a
+ // target that supports this replacement.
+ auto stubLinkage = vtableHasLocalLinkage
+ ? llvm::GlobalValue::InternalLinkage
+ : llvm::GlobalValue::LinkOnceODRLinkage;
llvm::Constant *target;
if (auto *func = dyn_cast<llvm::Function>(globalVal)) {
@@ -661,6 +666,12 @@ void CodeGenVTables::addRelativeComponent(ConstantArrayBuilder &builder,
proxy->setVisibility(llvm::GlobalValue::HiddenVisibility);
proxy->setComdat(module.getOrInsertComdat(rttiProxyName));
}
+ // Do not instrument the rtti proxies with hwasan to avoid a duplicate
+ // symbol error. Aliases generated by hwasan will retain the same namebut
+ // the addresses they are set to may have different tags from different
+ // compilation units. We don't run into this without hwasan because the
+ // proxies are in comdat groups, but those aren't propagated to the alias.
+ RemoveHwasanMetadata(proxy);
}
target = proxy;
}
@@ -669,15 +680,23 @@ void CodeGenVTables::addRelativeComponent(ConstantArrayBuilder &builder,
/*position=*/vtableAddressPoint);
}
-bool CodeGenVTables::useRelativeLayout() const {
+static bool UseRelativeLayout(const CodeGenModule &CGM) {
return CGM.getTarget().getCXXABI().isItaniumFamily() &&
CGM.getItaniumVTableContext().isRelativeLayout();
}
+bool CodeGenVTables::useRelativeLayout() const {
+ return UseRelativeLayout(CGM);
+}
+
+llvm::Type *CodeGenModule::getVTableComponentType() const {
+ if (UseRelativeLayout(*this))
+ return Int32Ty;
+ return GlobalsInt8PtrTy;
+}
+
llvm::Type *CodeGenVTables::getVTableComponentType() const {
- if (useRelativeLayout())
- return CGM.Int32Ty;
- return CGM.Int8PtrTy;
+ return CGM.getVTableComponentType();
}
static void AddPointerLayoutOffset(const CodeGenModule &CGM,
@@ -685,7 +704,7 @@ static void AddPointerLayoutOffset(const CodeGenModule &CGM,
CharUnits offset) {
builder.add(llvm::ConstantExpr::getIntToPtr(
llvm::ConstantInt::get(CGM.PtrDiffTy, offset.getQuantity()),
- CGM.Int8PtrTy));
+ CGM.GlobalsInt8PtrTy));
}
static void AddRelativeLayoutOffset(const CodeGenModule &CGM,
@@ -722,27 +741,12 @@ void CodeGenVTables::addVTableComponent(ConstantArrayBuilder &builder,
vtableHasLocalLinkage,
/*isCompleteDtor=*/false);
else
- return builder.add(llvm::ConstantExpr::getBitCast(rtti, CGM.Int8PtrTy));
+ return builder.add(rtti);
case VTableComponent::CK_FunctionPointer:
case VTableComponent::CK_CompleteDtorPointer:
case VTableComponent::CK_DeletingDtorPointer: {
- GlobalDecl GD;
-
- // Get the right global decl.
- switch (component.getKind()) {
- default:
- llvm_unreachable("Unexpected vtable component kind");
- case VTableComponent::CK_FunctionPointer:
- GD = component.getFunctionDecl();
- break;
- case VTableComponent::CK_CompleteDtorPointer:
- GD = GlobalDecl(component.getDestructorDecl(), Dtor_Complete);
- break;
- case VTableComponent::CK_DeletingDtorPointer:
- GD = GlobalDecl(component.getDestructorDecl(), Dtor_Deleting);
- break;
- }
+ GlobalDecl GD = component.getGlobalDecl();
if (CGM.getLangOpts().CUDA) {
// Emit NULL for methods we can't codegen on this
@@ -756,7 +760,8 @@ void CodeGenVTables::addVTableComponent(ConstantArrayBuilder &builder,
? MD->hasAttr<CUDADeviceAttr>()
: (MD->hasAttr<CUDAHostAttr>() || !MD->hasAttr<CUDADeviceAttr>());
if (!CanEmitMethod)
- return builder.add(llvm::ConstantExpr::getNullValue(CGM.Int8PtrTy));
+ return builder.add(
+ llvm::ConstantExpr::getNullValue(CGM.GlobalsInt8PtrTy));
// Method is acceptable, continue processing as usual.
}
@@ -769,26 +774,26 @@ void CodeGenVTables::addVTableComponent(ConstantArrayBuilder &builder,
// with the local symbol. As a temporary solution, fill these components
// with zero. We shouldn't be calling these in the first place anyway.
if (useRelativeLayout())
- return llvm::ConstantPointerNull::get(CGM.Int8PtrTy);
+ return llvm::ConstantPointerNull::get(CGM.GlobalsInt8PtrTy);
// For NVPTX devices in OpenMP emit special functon as null pointers,
// otherwise linking ends up with unresolved references.
- if (CGM.getLangOpts().OpenMP && CGM.getLangOpts().OpenMPIsDevice &&
+ if (CGM.getLangOpts().OpenMP && CGM.getLangOpts().OpenMPIsTargetDevice &&
CGM.getTriple().isNVPTX())
- return llvm::ConstantPointerNull::get(CGM.Int8PtrTy);
+ return llvm::ConstantPointerNull::get(CGM.GlobalsInt8PtrTy);
llvm::FunctionType *fnTy =
llvm::FunctionType::get(CGM.VoidTy, /*isVarArg=*/false);
llvm::Constant *fn = cast<llvm::Constant>(
CGM.CreateRuntimeFunction(fnTy, name).getCallee());
if (auto f = dyn_cast<llvm::Function>(fn))
f->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global);
- return llvm::ConstantExpr::getBitCast(fn, CGM.Int8PtrTy);
+ return fn;
};
llvm::Constant *fnPtr;
// Pure virtual member functions.
- if (cast<CXXMethodDecl>(GD.getDecl())->isPure()) {
+ if (cast<CXXMethodDecl>(GD.getDecl())->isPureVirtual()) {
if (!PureVirtualFn)
PureVirtualFn =
getSpecialVirtualFn(CGM.getCXXABI().GetPureVirtualCallName());
@@ -820,15 +825,26 @@ void CodeGenVTables::addVTableComponent(ConstantArrayBuilder &builder,
return addRelativeComponent(
builder, fnPtr, vtableAddressPoint, vtableHasLocalLinkage,
component.getKind() == VTableComponent::CK_CompleteDtorPointer);
- } else
- return builder.add(llvm::ConstantExpr::getBitCast(fnPtr, CGM.Int8PtrTy));
+ } else {
+ // TODO: this icky and only exists due to functions being in the generic
+ // address space, rather than the global one, even though they are
+ // globals; fixing said issue might be intrusive, and will be done
+ // later.
+ unsigned FnAS = fnPtr->getType()->getPointerAddressSpace();
+ unsigned GVAS = CGM.GlobalsInt8PtrTy->getPointerAddressSpace();
+
+ if (FnAS != GVAS)
+ fnPtr =
+ llvm::ConstantExpr::getAddrSpaceCast(fnPtr, CGM.GlobalsInt8PtrTy);
+ return builder.add(fnPtr);
+ }
}
case VTableComponent::CK_UnusedFunctionPointer:
if (useRelativeLayout())
return builder.add(llvm::ConstantExpr::getNullValue(CGM.Int32Ty));
else
- return builder.addNullPointer(CGM.Int8PtrTy);
+ return builder.addNullPointer(CGM.GlobalsInt8PtrTy);
}
llvm_unreachable("Unexpected vtable component kind");
@@ -907,7 +923,7 @@ llvm::GlobalVariable *CodeGenVTables::GenerateConstructionVTable(
if (Linkage == llvm::GlobalVariable::AvailableExternallyLinkage)
Linkage = llvm::GlobalVariable::InternalLinkage;
- unsigned Align = CGM.getDataLayout().getABITypeAlignment(VTType);
+ llvm::Align Align = CGM.getDataLayout().getABITypeAlign(VTType);
// Create the variable that will hold the construction vtable.
llvm::GlobalVariable *VTable =
@@ -933,12 +949,33 @@ llvm::GlobalVariable *CodeGenVTables::GenerateConstructionVTable(
CGM.EmitVTableTypeMetadata(RD, VTable, *VTLayout.get());
- if (UsingRelativeLayout && !VTable->isDSOLocal())
- GenerateRelativeVTableAlias(VTable, OutName);
+ if (UsingRelativeLayout) {
+ RemoveHwasanMetadata(VTable);
+ if (!VTable->isDSOLocal())
+ GenerateRelativeVTableAlias(VTable, OutName);
+ }
return VTable;
}
+// Ensure this vtable is not instrumented by hwasan. That is, a global alias is
+// not generated for it. This is mainly used by the relative-vtables ABI where
+// vtables instead contain 32-bit offsets between the vtable and function
+// pointers. Hwasan is disabled for these vtables for now because the tag in a
+// vtable pointer may fail the overflow check when resolving 32-bit PLT
+// relocations. A future alternative for this would be finding which usages of
+// the vtable can continue to use the untagged hwasan value without any loss of
+// value in hwasan.
+void CodeGenVTables::RemoveHwasanMetadata(llvm::GlobalValue *GV) const {
+ if (CGM.getLangOpts().Sanitize.has(SanitizerKind::HWAddress)) {
+ llvm::GlobalValue::SanitizerMetadata Meta;
+ if (GV->hasSanitizerMetadata())
+ Meta = GV->getSanitizerMetadata();
+ Meta.NoHWAddress = true;
+ GV->setSanitizerMetadata(Meta);
+ }
+}
+
// If the VTable is not dso_local, then we will not be able to indicate that
// the VTable does not need a relocation and move into rodata. A frequent
// time this can occur is for classes that should be made public from a DSO
@@ -1022,19 +1059,20 @@ CodeGenModule::getVTableLinkage(const CXXRecordDecl *RD) {
switch (keyFunction->getTemplateSpecializationKind()) {
case TSK_Undeclared:
case TSK_ExplicitSpecialization:
- assert((def || CodeGenOpts.OptimizationLevel > 0 ||
- CodeGenOpts.getDebugInfo() != codegenoptions::NoDebugInfo) &&
- "Shouldn't query vtable linkage without key function, "
- "optimizations, or debug info");
- if (!def && CodeGenOpts.OptimizationLevel > 0)
- return llvm::GlobalVariable::AvailableExternallyLinkage;
+ 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 llvm::GlobalVariable::AvailableExternallyLinkage;
- if (keyFunction->isInlined())
- return !Context.getLangOpts().AppleKext ?
- llvm::GlobalVariable::LinkOnceODRLinkage :
- llvm::Function::InternalLinkage;
+ if (keyFunction->isInlined())
+ return !Context.getLangOpts().AppleKext
+ ? llvm::GlobalVariable::LinkOnceODRLinkage
+ : llvm::Function::InternalLinkage;
- return llvm::GlobalVariable::ExternalLinkage;
+ return llvm::GlobalVariable::ExternalLinkage;
case TSK_ImplicitInstantiation:
return !Context.getLangOpts().AppleKext ?
@@ -1148,9 +1186,16 @@ bool CodeGenVTables::isVTableExternal(const CXXRecordDecl *RD) {
if (!keyFunction)
return false;
+ const FunctionDecl *Def;
// Otherwise, if we don't have a definition of the key function, the
// vtable must be defined somewhere else.
- return !keyFunction->hasBody();
+ if (!keyFunction->hasBody(Def))
+ return true;
+
+ assert(Def && "The body of the key function is not assigned to Def?");
+ // If the non-inline key function comes from another module unit, the vtable
+ // must be defined there.
+ return Def->isInAnotherModuleUnit() && !Def->isInlineSpecified();
}
/// Given that we're currently at the end of the translation unit, and
@@ -1187,12 +1232,16 @@ void CodeGenModule::EmitDeferredVTables() {
DeferredVTables.clear();
}
-bool CodeGenModule::HasLTOVisibilityPublicStd(const CXXRecordDecl *RD) {
+bool CodeGenModule::AlwaysHasLTOVisibilityPublic(const CXXRecordDecl *RD) {
+ if (RD->hasAttr<LTOVisibilityPublicAttr>() || RD->hasAttr<UuidAttr>() ||
+ RD->hasAttr<DLLExportAttr>() || RD->hasAttr<DLLImportAttr>())
+ return true;
+
if (!getCodeGenOpts().LTOVisibilityPublicStd)
return false;
const DeclContext *DC = RD;
- while (1) {
+ while (true) {
auto *D = cast<Decl>(DC);
DC = DC->getParent();
if (isa<TranslationUnitDecl>(DC->getRedeclContext())) {
@@ -1212,18 +1261,11 @@ bool CodeGenModule::HasHiddenLTOVisibility(const CXXRecordDecl *RD) {
if (!isExternallyVisible(LV.getLinkage()))
return true;
- if (RD->hasAttr<LTOVisibilityPublicAttr>() || RD->hasAttr<UuidAttr>())
+ if (!getTriple().isOSBinFormatCOFF() &&
+ LV.getVisibility() != HiddenVisibility)
return false;
- if (getTriple().isOSBinFormatCOFF()) {
- if (RD->hasAttr<DLLExportAttr>() || RD->hasAttr<DLLImportAttr>())
- return false;
- } else {
- if (LV.getVisibility() != HiddenVisibility)
- return false;
- }
-
- return !HasLTOVisibilityPublicStd(RD);
+ return !AlwaysHasLTOVisibilityPublic(RD);
}
llvm::GlobalObject::VCallVisibility CodeGenModule::GetVCallVisibilityLevel(
@@ -1245,13 +1287,13 @@ llvm::GlobalObject::VCallVisibility CodeGenModule::GetVCallVisibilityLevel(
else
TypeVis = llvm::GlobalObject::VCallVisibilityPublic;
- for (auto B : RD->bases())
+ for (const auto &B : RD->bases())
if (B.getType()->getAsCXXRecordDecl()->isDynamicClass())
TypeVis = std::min(
TypeVis,
GetVCallVisibilityLevel(B.getType()->getAsCXXRecordDecl(), Visited));
- for (auto B : RD->vbases())
+ for (const auto &B : RD->vbases())
if (B.getType()->getAsCXXRecordDecl()->isDynamicClass())
TypeVis = std::min(
TypeVis,
@@ -1263,49 +1305,42 @@ llvm::GlobalObject::VCallVisibility CodeGenModule::GetVCallVisibilityLevel(
void CodeGenModule::EmitVTableTypeMetadata(const CXXRecordDecl *RD,
llvm::GlobalVariable *VTable,
const VTableLayout &VTLayout) {
- if (!getCodeGenOpts().LTOUnit)
+ // Emit type metadata on vtables with LTO or IR instrumentation.
+ // In IR instrumentation, the type metadata is used to find out vtable
+ // definitions (for type profiling) among all global variables.
+ if (!getCodeGenOpts().LTOUnit && !getCodeGenOpts().hasProfileIRInstr())
return;
- CharUnits PointerWidth =
- Context.toCharUnitsFromBits(Context.getTargetInfo().getPointerWidth(0));
+ CharUnits ComponentWidth = GetTargetTypeStoreSize(getVTableComponentType());
- typedef std::pair<const CXXRecordDecl *, unsigned> AddressPoint;
+ struct AddressPoint {
+ const CXXRecordDecl *Base;
+ size_t Offset;
+ std::string TypeName;
+ bool operator<(const AddressPoint &RHS) const {
+ int D = TypeName.compare(RHS.TypeName);
+ return D < 0 || (D == 0 && Offset < RHS.Offset);
+ }
+ };
std::vector<AddressPoint> AddressPoints;
- for (auto &&AP : VTLayout.getAddressPoints())
- AddressPoints.push_back(std::make_pair(
- AP.first.getBase(), VTLayout.getVTableOffset(AP.second.VTableIndex) +
- AP.second.AddressPointIndex));
+ for (auto &&AP : VTLayout.getAddressPoints()) {
+ AddressPoint N{AP.first.getBase(),
+ VTLayout.getVTableOffset(AP.second.VTableIndex) +
+ AP.second.AddressPointIndex,
+ {}};
+ llvm::raw_string_ostream Stream(N.TypeName);
+ getCXXABI().getMangleContext().mangleCanonicalTypeName(
+ QualType(N.Base->getTypeForDecl(), 0), Stream);
+ AddressPoints.push_back(std::move(N));
+ }
// Sort the address points for determinism.
- llvm::sort(AddressPoints, [this](const AddressPoint &AP1,
- const AddressPoint &AP2) {
- if (&AP1 == &AP2)
- return false;
-
- std::string S1;
- llvm::raw_string_ostream O1(S1);
- getCXXABI().getMangleContext().mangleTypeName(
- QualType(AP1.first->getTypeForDecl(), 0), O1);
- O1.flush();
-
- std::string S2;
- llvm::raw_string_ostream O2(S2);
- getCXXABI().getMangleContext().mangleTypeName(
- QualType(AP2.first->getTypeForDecl(), 0), O2);
- O2.flush();
-
- if (S1 < S2)
- return true;
- if (S1 != S2)
- return false;
-
- return AP1.second < AP2.second;
- });
+ llvm::sort(AddressPoints);
ArrayRef<VTableComponent> Comps = VTLayout.vtable_components();
for (auto AP : AddressPoints) {
// Create type metadata for the address point.
- AddVTableTypeMetadata(VTable, PointerWidth * AP.second, AP.first);
+ AddVTableTypeMetadata(VTable, ComponentWidth * AP.Offset, AP.Base);
// The class associated with each address point could also potentially be
// used for indirect calls via a member function pointer, so we need to
@@ -1317,8 +1352,8 @@ void CodeGenModule::EmitVTableTypeMetadata(const CXXRecordDecl *RD,
llvm::Metadata *MD = CreateMetadataIdentifierForVirtualMemPtrType(
Context.getMemberPointerType(
Comps[I].getFunctionDecl()->getType(),
- Context.getRecordType(AP.first).getTypePtr()));
- VTable->addTypeMetadata((PointerWidth * I).getQuantity(), MD);
+ Context.getRecordType(AP.Base).getTypePtr()));
+ VTable->addTypeMetadata((ComponentWidth * I).getQuantity(), MD);
}
}