leonardchan updated this revision to Diff 197196.
leonardchan marked an inline comment as done.
leonardchan retitled this revision from "[WIP] Support for relative vtables" to
"Support for relative vtables".
leonardchan added a comment.
Ok. Formally requesting for code reviews now.
- Made the flag an `experimental` flag.
- Added changes to relevant AST Serialization code.
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D58321/new/
https://reviews.llvm.org/D58321
Files:
clang/include/clang/AST/DeclCXX.h
clang/include/clang/AST/VTableBuilder.h
clang/include/clang/Basic/LangOptions.def
clang/include/clang/Driver/Options.td
clang/include/clang/Sema/Sema.h
clang/lib/AST/DeclCXX.cpp
clang/lib/CodeGen/CGClass.cpp
clang/lib/CodeGen/CGDebugInfo.cpp
clang/lib/CodeGen/CGVTables.cpp
clang/lib/CodeGen/CGVTables.h
clang/lib/CodeGen/CodeGenFunction.h
clang/lib/CodeGen/ItaniumCXXABI.cpp
clang/lib/CodeGen/MicrosoftCXXABI.cpp
clang/lib/Driver/ToolChains/Clang.cpp
clang/lib/Frontend/CompilerInvocation.cpp
clang/lib/Sema/SemaDeclCXX.cpp
clang/lib/Serialization/ASTReaderDecl.cpp
clang/lib/Serialization/ASTWriter.cpp
clang/test/CodeGenCXX/debug-info-virtual-fn-relative.cpp
clang/test/CodeGenCXX/vtable-relative-abi.cpp
llvm/lib/IR/Constants.cpp
Index: llvm/lib/IR/Constants.cpp
===================================================================
--- llvm/lib/IR/Constants.cpp
+++ llvm/lib/IR/Constants.cpp
@@ -495,6 +495,35 @@
return false;
}
+/// Returns true if this constant mathes the relative referencing for virtual
+/// functions introduced in the relative ABI. This is the difference between a
+/// function and its corresponding vtable entry.
+///
+/// i64 sub (
+/// i64 ptrtoint (i8* obj to i64),
+// i64 ptrtoint (
+// i32* getelementptr inbounds (%object_vtable, %object_vtable*
+// @_ZTV12derived_virt, i32 0, i32 0, i32 2) to i64)
+static bool MatchesRelativeOffset(const Constant *C) {
+ const auto *CE = dyn_cast<ConstantExpr>(C);
+ if (!CE || CE->getOpcode() != Instruction::Sub)
+ return false;
+
+ const auto *LHS = dyn_cast<ConstantExpr>(CE->getOperand(0));
+ const auto *RHS = dyn_cast<ConstantExpr>(CE->getOperand(1));
+ if (!LHS || !RHS || LHS->getOpcode() != Instruction::PtrToInt ||
+ RHS->getOpcode() != Instruction::PtrToInt)
+ return false;
+
+ RHS = dyn_cast<ConstantExpr>(RHS->getOperand(0));
+ if (!RHS)
+ return false;
+
+ return (isa<GlobalValue>(LHS->getOperand(0)) &&
+ RHS->getOpcode() == Instruction::GetElementPtr &&
+ isa<GlobalValue>(RHS->getOperand(0)));
+}
+
bool Constant::needsRelocation() const {
if (isa<GlobalValue>(this))
return true; // Global reference.
@@ -519,6 +548,10 @@
return false;
}
+ // This results in an R_PLT_PC reloc which can be computed at link time.
+ if (MatchesRelativeOffset(this))
+ return false;
+
bool Result = false;
for (unsigned i = 0, e = getNumOperands(); i != e; ++i)
Result |= cast<Constant>(getOperand(i))->needsRelocation();
Index: clang/test/CodeGenCXX/vtable-relative-abi.cpp
===================================================================
--- /dev/null
+++ clang/test/CodeGenCXX/vtable-relative-abi.cpp
@@ -0,0 +1,117 @@
+// RUN: %clang_cc1 %s -triple x86_64-unknown-linux-gnu -fexperimental-relative-c++-abi-vtables -emit-llvm -o - | FileCheck --check-prefix=CHECK --check-prefix=CHECK-ITANIUM %s
+// RUN: %clang_cc1 %s -triple x86_64-unknown-windows-msvc -fexperimental-relative-c++-abi-vtables -emit-llvm -o - | FileCheck --check-prefix=CHECK --check-prefix=CHECK-MS %s
+
+// CHECK-ITANIUM: @_ZTV1S = unnamed_addr constant { { i8*, i8*, i32, i32 } } { { i8*, i8*, i32, i32 } { i8* null, i8* bitcast ({ i8*, i8* }* @_ZTI1S to i8*), i32 trunc (i64 sub (i64 ptrtoint (void (%struct.S*)* @_ZN1S2f1Ev to i64), i64 ptrtoint (i32* getelementptr inbounds ({ { i8*, i8*, i32, i32 } }, { { i8*, i8*, i32, i32 } }* @_ZTV1S, i32 0, i32 0, i32 2) to i64)) to i32), i32 trunc (i64 sub (i64 ptrtoint (void (%struct.S*)* @_ZN1S2f2Ev to i64), i64 ptrtoint (i32* getelementptr inbounds ({ { i8*, i8*, i32, i32 } }, { { i8*, i8*, i32, i32 } }* @_ZTV1S, i32 0, i32 0, i32 2) to i64)) to i32) } }, align 8
+// CHECK-MS: @0 = private unnamed_addr constant { { i8*, i32, i32 } } { { i8*, i32, i32 } { i8* bitcast (%rtti.CompleteObjectLocator* @"??_R4S@@6B@" to i8*), i32 trunc (i64 sub (i64 ptrtoint (void (%struct.S*)* @"?f1@S@@UEAAXXZ" to i64), i64 ptrtoint (i32* getelementptr inbounds ({ { i8*, i32, i32 } }, { { i8*, i32, i32 } }* @0, i32 0, i32 0, i32 1) to i64)) to i32), i32 trunc (i64 sub (i64 ptrtoint (void (%struct.S*)* @"?f2@S@@UEAAXXZ" to i64), i64 ptrtoint (i32* getelementptr inbounds ({ { i8*, i32, i32 } }, { { i8*, i32, i32 } }* @0, i32 0, i32 0, i32 1) to i64)) to i32) } }, comdat($"??_7S@@6B@")
+
+struct S {
+ S();
+ virtual void f1();
+ virtual void f2();
+};
+
+// CHECK-ITANIUM: @_ZTV1T = unnamed_addr constant { { i8*, i8*, i32 } } { { i8*, i8*, i32 } { i8* null, i8* bitcast ({ i8*, i8* }* @_ZTI1T to i8*), i32 trunc (i64 sub (i64 ptrtoint (void (%struct.T*)* @_ZN1T1gEv to i64), i64 ptrtoint (i32* getelementptr inbounds ({ { i8*, i8*, i32 } }, { { i8*, i8*, i32 } }* @_ZTV1T, i32 0, i32 0, i32 2) to i64)) to i32) } }, align 8
+// CHECK-MS: @1 = private unnamed_addr constant { { i8*, i32 } } { { i8*, i32 } { i8* bitcast (%rtti.CompleteObjectLocator* @"??_R4T@@6B@" to i8*), i32 trunc (i64 sub (i64 ptrtoint (void (%struct.T*)* @"?g@T@@UEAAXXZ" to i64), i64 ptrtoint (i32* getelementptr inbounds ({ { i8*, i32 } }, { { i8*, i32 } }* @1, i32 0, i32 0, i32 1) to i64)) to i32) } }, comdat($"??_7T@@6B@")
+struct T {
+ T();
+ virtual void g();
+};
+
+// CHECK-ITANIUM: @_ZTV1U = unnamed_addr constant { { i8*, i8*, i32, i32 }, { i8*, i8*, i32 } } { { i8*, i8*, i32, i32 } { i8* null, i8* bitcast ({ i8*, i8*, i32, i32, i8*, i64, i8*, i64 }* @_ZTI1U to i8*), i32 trunc (i64 sub (i64 ptrtoint (void (%struct.U*)* @_ZN1U2f1Ev to i64), i64 ptrtoint (i32* getelementptr inbounds ({ { i8*, i8*, i32, i32 }, { i8*, i8*, i32 } }, { { i8*, i8*, i32, i32 }, { i8*, i8*, i32 } }* @_ZTV1U, i32 0, i32 0, i32 2) to i64)) to i32), i32 trunc (i64 sub (i64 ptrtoint (void (%struct.S*)* @_ZN1S2f2Ev to i64), i64 ptrtoint (i32* getelementptr inbounds ({ { i8*, i8*, i32, i32 }, { i8*, i8*, i32 } }, { { i8*, i8*, i32, i32 }, { i8*, i8*, i32 } }* @_ZTV1U, i32 0, i32 0, i32 2) to i64)) to i32) }, { i8*, i8*, i32 } { i8* inttoptr (i64 -8 to i8*), i8* bitcast ({ i8*, i8*, i32, i32, i8*, i64, i8*, i64 }* @_ZTI1U to i8*), i32 trunc (i64 sub (i64 ptrtoint (void (%struct.T*)* @_ZN1T1gEv to i64), i64 ptrtoint (i32* getelementptr inbounds ({ { i8*, i8*, i32, i32 }, { i8*, i8*, i32 } }, { { i8*, i8*, i32, i32 }, { i8*, i8*, i32 } }* @_ZTV1U, i32 0, i32 1, i32 2) to i64)) to i32) } }, align 8
+// CHECK-MS: @2 = private unnamed_addr constant { { i8*, i32, i32 } } { { i8*, i32, i32 } { i8* bitcast (%rtti.CompleteObjectLocator* @"??_R4U@@6BS@@@" to i8*), i32 trunc (i64 sub (i64 ptrtoint (void (%struct.U*)* @"?f1@U@@UEAAXXZ" to i64), i64 ptrtoint (i32* getelementptr inbounds ({ { i8*, i32, i32 } }, { { i8*, i32, i32 } }* @2, i32 0, i32 0, i32 1) to i64)) to i32), i32 trunc (i64 sub (i64 ptrtoint (void (%struct.S*)* @"?f2@S@@UEAAXXZ" to i64), i64 ptrtoint (i32* getelementptr inbounds ({ { i8*, i32, i32 } }, { { i8*, i32, i32 } }* @2, i32 0, i32 0, i32 1) to i64)) to i32) } }, comdat($"??_7U@@6BS@@@")
+// CHECK-MS: @3 = private unnamed_addr constant { { i8*, i32 } } { { i8*, i32 } { i8* bitcast (%rtti.CompleteObjectLocator* @"??_R4U@@6BT@@@" to i8*), i32 trunc (i64 sub (i64 ptrtoint (void (%struct.T*)* @"?g@T@@UEAAXXZ" to i64), i64 ptrtoint (i32* getelementptr inbounds ({ { i8*, i32 } }, { { i8*, i32 } }* @3, i32 0, i32 0, i32 1) to i64)) to i32) } }, comdat($"??_7U@@6BT@@@")
+struct U : S, T {
+ U();
+ virtual void f1();
+};
+
+S::S() {}
+void S::f1() {}
+
+T::T() {}
+void T::g() {}
+
+U::U() {}
+void U::f1() {}
+
+struct V {
+ virtual void f();
+};
+
+struct V1 : virtual V {
+};
+
+struct V2 : virtual V {
+};
+
+// CHECK-ITANIUM: @_ZTC2V30_2V1 = linkonce_odr unnamed_addr constant { { i8*, i8*, i8*, i8*, i32 } } { { i8*, i8*, i8*, i8*, i32 } { i8* null, i8* null, i8* null, i8* bitcast ({ i8*, i8*, i32, i32, i8*, i64 }* @_ZTI2V1 to i8*), i32 trunc (i64 sub (i64 ptrtoint (void (%struct.V*)* @_ZN1V1fEv to i64), i64 ptrtoint (i32* getelementptr inbounds ({ { i8*, i8*, i8*, i8*, i32 } }, { { i8*, i8*, i8*, i8*, i32 } }* @_ZTC2V30_2V1, i32 0, i32 0, i32 4) to i64)) to i32) } }, comdat, align 8
+// CHECK-ITANIUM: @_ZTC2V38_2V2 = linkonce_odr unnamed_addr constant { { i8*, i8*, i8*, i8*, i32 }, { i8*, i8*, i8*, i32 } } { { i8*, i8*, i8*, i8*, i32 } { i8* inttoptr (i64 -8 to i8*), i8* inttoptr (i64 -8 to i8*), i8* null, i8* bitcast ({ i8*, i8*, i32, i32, i8*, i64 }* @_ZTI2V2 to i8*), i32 0 }, { i8*, i8*, i8*, i32 } { i8* null, i8* inttoptr (i64 8 to i8*), i8* bitcast ({ i8*, i8*, i32, i32, i8*, i64 }* @_ZTI2V2 to i8*), i32 trunc (i64 sub (i64 ptrtoint (void (%struct.V*)* @_ZN1V1fEv to i64), i64 ptrtoint (i32* getelementptr inbounds ({ { i8*, i8*, i8*, i8*, i32 }, { i8*, i8*, i8*, i32 } }, { { i8*, i8*, i8*, i8*, i32 }, { i8*, i8*, i8*, i32 } }* @_ZTC2V38_2V2, i32 0, i32 1, i32 3) to i64)) to i32) } }, comdat, align 8
+struct V3 : V1, V2 {
+ V3();
+};
+
+V3::V3() {}
+
+// CHECK-ITANIUM: define void @_Z5call1P1S
+// CHECK-MS: define {{.*}} void @"?call1@@YAXPEAUS@@@Z"
+void call1(S *s) {
+ // CHECK: [[VTABLE:%.*]] = load void
+ // CHECK: [[VTABLEI8:%.*]] = bitcast {{.*}} [[VTABLE]] to i8*
+ // CHECK: [[VFN:%.*]] = call i8* @llvm.load.relative.i32(i8* [[VTABLEI8]], i32 0)
+ // CHECK: [[VFNCASTED:%.*]] = bitcast i8* [[VFN]] to void (
+ // CHECK: call void [[VFNCASTED]](
+ s->f1();
+}
+
+// CHECK-ITANIUM: define void @_Z5call2P1S
+// CHECK-MS: define {{.*}} void @"?call2@@YAXPEAUS@@@Z"
+void call2(S *s) {
+ // CHECK: [[VTABLE:%.*]] = load void
+ // CHECK: [[VTABLEI8:%.*]] = bitcast {{.*}} [[VTABLE]] to i8*
+ // CHECK: [[VFN:%.*]] = call i8* @llvm.load.relative.i32(i8* [[VTABLEI8]], i32 4)
+ // CHECK: [[VFNCASTED:%.*]] = bitcast i8* [[VFN]] to void (
+ // CHECK: call void [[VFNCASTED]](
+ s->f2();
+}
+
+typedef void (S::*mfp)();
+
+// CHECK-ITANIUM: define { i64, i64 } @_Z7getmfp1v()
+// CHECK-ITANIUM: ret { i64, i64 } { i64 1, i64 0 }
+// CHECK-MS: define {{.*}} i8* @"?getmfp1@@YAP8S@@EAAXXZXZ"()
+// CHECK-MS: ret i8* bitcast {{.*}} @"??_9S@@$BA@AA"
+// CHECK-MS: define linkonce_odr void @"??_9S@@$BA@AA"
+// CHECK-MS: [[VTABLE:%.*]] = load void
+// CHECK-MS: [[VTABLEI8:%.*]] = bitcast {{.*}} [[VTABLE]] to i8*
+// CHECK-MS: [[VFN:%.*]] = call i8* @llvm.load.relative.i32(i8* [[VTABLEI8]], i32 0)
+// CHECK-MS: [[VFNCASTED:%.*]] = bitcast i8* [[VFN]] to void (
+// CHECK-MS: musttail call {{.*}} [[VFNCASTED]](
+mfp getmfp1() {
+ return &S::f1;
+}
+
+// CHECK-ITANIUM: define { i64, i64 } @_Z7getmfp2v()
+// CHECK-ITANIUM: ret { i64, i64 } { i64 5, i64 0 }
+// CHECK-MS: define {{.*}} i8* @"?getmfp2@@YAP8S@@EAAXXZXZ"()
+// CHECK-MS: ret i8* bitcast {{.*}} @"??_9S@@$B7AA"
+// CHECK-MS: define linkonce_odr void @"??_9S@@$B7AA"
+// CHECK-MS: [[VTABLE:%.*]] = load void
+// CHECK-MS: [[VTABLEI8:%.*]] = bitcast {{.*}} [[VTABLE]] to i8*
+// CHECK-MS: [[VFN:%.*]] = call i8* @llvm.load.relative.i32(i8* [[VTABLEI8]], i32 4)
+// CHECK-MS: [[VFNCASTED:%.*]] = bitcast i8* [[VFN]] to void (
+// CHECK-MS: musttail call {{.*}} [[VFNCASTED]](
+mfp getmfp2() {
+ return &S::f2;
+}
+
+// In the MS ABI virtual member function calls use thunks (which we already
+// tested above), so there's nothing to test that's specific to the relative
+// ABI.
+
+// CHECK-ITANIUM: define void @_Z7callmfpP1SMS_FvvE
+void callmfp(S *s, mfp p) {
+ // CHECK-ITANIUM: [[VTOFFSET:%.*]] = sub i64 {{.*}}, 1
+ // CHECK-ITANIUM: [[VFN:%.*]] = call i8* @llvm.load.relative.i64(i8* {{.*}}, i64 [[VTOFFSET]])
+ // CHECK-ITANIUM: bitcast i8* [[VFN]] to void (
+ (s->*p)();
+}
Index: clang/test/CodeGenCXX/debug-info-virtual-fn-relative.cpp
===================================================================
--- /dev/null
+++ clang/test/CodeGenCXX/debug-info-virtual-fn-relative.cpp
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 -emit-llvm -debug-info-kind=limited %s -o - | FileCheck --check-prefix=CHECK-STABLE %s
+// RUN: %clang_cc1 -fexperimental-relative-c++-abi-vtables -emit-llvm -debug-info-kind=limited %s -o - | FileCheck --check-prefix=CHECK-UNSTABLE %s
+
+struct S {
+ S();
+ virtual void f();
+};
+
+// CHECK-STABLE: virtualIndex: 0,
+// CHECK-UNSTABLE: virtualIndex: 4294967295,
+S::S() {}
+void S::f() {}
Index: clang/lib/Serialization/ASTWriter.cpp
===================================================================
--- clang/lib/Serialization/ASTWriter.cpp
+++ clang/lib/Serialization/ASTWriter.cpp
@@ -6105,6 +6105,7 @@
Record->push_back(Data.ImplicitCopyAssignmentHasConstParam);
Record->push_back(Data.HasDeclaredCopyConstructorWithConstParam);
Record->push_back(Data.HasDeclaredCopyAssignmentWithConstParam);
+ Record->push_back(Data.IsRelativeCXXABI);
// getODRHash will compute the ODRHash if it has not been previously computed.
Record->push_back(D->getODRHash());
Index: clang/lib/Serialization/ASTReaderDecl.cpp
===================================================================
--- clang/lib/Serialization/ASTReaderDecl.cpp
+++ clang/lib/Serialization/ASTReaderDecl.cpp
@@ -1689,6 +1689,7 @@
Data.ImplicitCopyAssignmentHasConstParam = Record.readInt();
Data.HasDeclaredCopyConstructorWithConstParam = Record.readInt();
Data.HasDeclaredCopyAssignmentWithConstParam = Record.readInt();
+ Data.IsRelativeCXXABI = Record.readInt();
Data.ODRHash = Record.readInt();
Data.HasODRHash = true;
@@ -1830,6 +1831,7 @@
MATCH_FIELD(ImplicitCopyAssignmentHasConstParam)
OR_FIELD(HasDeclaredCopyConstructorWithConstParam)
OR_FIELD(HasDeclaredCopyAssignmentWithConstParam)
+ MATCH_FIELD(IsRelativeCXXABI)
MATCH_FIELD(IsLambda)
#undef OR_FIELD
#undef MATCH_FIELD
Index: clang/lib/Sema/SemaDeclCXX.cpp
===================================================================
--- clang/lib/Sema/SemaDeclCXX.cpp
+++ clang/lib/Sema/SemaDeclCXX.cpp
@@ -5893,6 +5893,13 @@
}
}
+void Sema::checkClassABI(CXXRecordDecl *Record) {
+ if (!getLangOpts().RelativeCXXABIVTables)
+ return;
+
+ Record->setIsRelativeCXXABI();
+}
+
/// Determine whether a type is permitted to be passed or returned in
/// registers, per C++ [class.temporary]p3.
static bool canPassInRegisters(Sema &S, CXXRecordDecl *D,
@@ -6172,6 +6179,7 @@
checkClassLevelDLLAttribute(Record);
checkClassLevelCodeSegAttribute(Record);
+ checkClassABI(Record);
bool ClangABICompat4 =
Context.getLangOpts().getClangABICompat() <= LangOptions::ClangABI::Ver4;
Index: clang/lib/Frontend/CompilerInvocation.cpp
===================================================================
--- clang/lib/Frontend/CompilerInvocation.cpp
+++ clang/lib/Frontend/CompilerInvocation.cpp
@@ -3045,6 +3045,9 @@
Opts.CompleteMemberPointers = Args.hasArg(OPT_fcomplete_member_pointers);
Opts.BuildingPCHWithObjectFile = Args.hasArg(OPT_building_pch_with_obj);
+
+ Opts.RelativeCXXABIVTables =
+ Args.hasArg(OPT_fexperimental_relative_cxx_abi_vtables);
}
static bool isStrictlyPreprocessorAction(frontend::ActionKind Action) {
Index: clang/lib/Driver/ToolChains/Clang.cpp
===================================================================
--- clang/lib/Driver/ToolChains/Clang.cpp
+++ clang/lib/Driver/ToolChains/Clang.cpp
@@ -5309,6 +5309,10 @@
CmdArgs.push_back("-fwhole-program-vtables");
}
+ // Add unstable C++ ABI flags.
+ if (Args.hasArg(options::OPT_fexperimental_relative_cxx_abi_vtables))
+ CmdArgs.push_back("-fexperimental-relative-c++-abi-vtables");
+
bool RequiresSplitLTOUnit = WholeProgramVTables || Sanitize.needsLTO();
bool SplitLTOUnit =
Args.hasFlag(options::OPT_fsplit_lto_unit,
Index: clang/lib/CodeGen/MicrosoftCXXABI.cpp
===================================================================
--- clang/lib/CodeGen/MicrosoftCXXABI.cpp
+++ clang/lib/CodeGen/MicrosoftCXXABI.cpp
@@ -1645,10 +1645,7 @@
[](const VTableComponent &VTC) { return VTC.isRTTIKind(); }))
RTTI = getMSCompleteObjectLocator(RD, *Info);
- ConstantInitBuilder Builder(CGM);
- auto Components = Builder.beginStruct();
- CGVT.createVTableInitializer(Components, VTLayout, RTTI);
- Components.finishAndSetAsInitializer(VTable);
+ CGVT.SetVTableInitializer(VTable, VTLayout, RTTI, RD->isRelativeCXXABI());
emitVTableTypeMetadata(*Info, RD, VTable);
}
@@ -1774,7 +1771,7 @@
StringRef VTableName = VTableAliasIsRequred ? StringRef() : VFTableName.str();
- llvm::Type *VTableType = CGM.getVTables().getVTableType(VTLayout);
+ llvm::Type *VTableType = CGM.getVTables().getVTableType(RD, VTLayout);
// Create a backing variable for the contents of VTable. The VTable may
// or may not include space for a pointer to RTTI data.
@@ -1807,6 +1804,7 @@
if (C)
C->setSelectionKind(llvm::Comdat::Largest);
}
+ VTableGEP = llvm::ConstantExpr::getBitCast(VTableGEP, CGM.Int8PtrPtrTy);
VFTable = llvm::GlobalAlias::create(CGM.Int8PtrTy,
/*AddressSpace=*/0, VFTableLinkage,
VFTableName.str(), VTableGEP,
@@ -1834,14 +1832,12 @@
Address This,
llvm::Type *Ty,
SourceLocation Loc) {
- CGBuilderTy &Builder = CGF.Builder;
-
- Ty = Ty->getPointerTo()->getPointerTo();
Address VPtr =
adjustThisArgumentForVirtualFunctionCall(CGF, GD, This, true);
auto *MethodDecl = cast<CXXMethodDecl>(GD.getDecl());
- llvm::Value *VTable = CGF.GetVTablePtr(VPtr, Ty, MethodDecl->getParent());
+ llvm::Value *VTable = CGF.GetVTablePtr(
+ VPtr, Ty->getPointerTo()->getPointerTo(), MethodDecl->getParent());
MicrosoftVTableContext &VFTContext = CGM.getMicrosoftVTableContext();
MethodVFTableLocation ML = VFTContext.getMethodVFTableLocation(GD);
@@ -1867,9 +1863,8 @@
if (CGM.getCodeGenOpts().PrepareForLTO)
CGF.EmitTypeMetadataCodeForVCall(getObjectWithVPtr(), VTable, Loc);
- llvm::Value *VFuncPtr =
- Builder.CreateConstInBoundsGEP1_64(VTable, ML.Index, "vfn");
- VFunc = Builder.CreateAlignedLoad(VFuncPtr, CGF.getPointerAlign());
+ VFunc = CGF.GetVirtualFunctionFromVTable(MethodDecl->getParent(), VTable,
+ ML.Index, Ty);
}
CGCallee Callee(GD, VFunc);
@@ -1990,10 +1985,8 @@
llvm::Value *VTable = CGF.GetVTablePtr(
getThisAddress(CGF), ThunkTy->getPointerTo()->getPointerTo(), MD->getParent());
- llvm::Value *VFuncPtr =
- CGF.Builder.CreateConstInBoundsGEP1_64(VTable, ML.Index, "vfn");
- llvm::Value *Callee =
- CGF.Builder.CreateAlignedLoad(VFuncPtr, CGF.getPointerAlign());
+ llvm::Value *Callee = CGF.GetVirtualFunctionFromVTable(
+ MD->getParent(), VTable, ML.Index, ThunkTy);
CGF.EmitMustTailThunk(MD, getThisValue(CGF), {ThunkTy, Callee});
Index: clang/lib/CodeGen/ItaniumCXXABI.cpp
===================================================================
--- clang/lib/CodeGen/ItaniumCXXABI.cpp
+++ clang/lib/CodeGen/ItaniumCXXABI.cpp
@@ -666,9 +666,20 @@
}
// Load the virtual function to call.
- VFPAddr = Builder.CreateBitCast(VFPAddr, FTy->getPointerTo()->getPointerTo());
- llvm::Value *VirtualFn = Builder.CreateAlignedLoad(
- VFPAddr, CGF.getPointerAlign(), "memptr.virtualfn");
+ llvm::Value *VirtualFn;
+ if (RD->hasDefinition() && RD->isRelativeCXXABI()) {
+ VirtualFn =
+ Builder.CreateCall(CGM.getIntrinsic(llvm::Intrinsic::load_relative,
+ {VTableOffset->getType()}),
+ {VTable, VTableOffset});
+ VirtualFn = Builder.CreateBitCast(VirtualFn, FTy->getPointerTo());
+ } else {
+ // Apply the offset.
+ llvm::Value *VTableSlotPtr =
+ Builder.CreateBitCast(VFPAddr, FTy->getPointerTo()->getPointerTo());
+ VirtualFn = Builder.CreateAlignedLoad(VTableSlotPtr, CGF.getPointerAlign(),
+ "memptr.virtualfn");
+ }
CGF.EmitBranch(FnEnd);
// In the non-virtual path, the function pointer is actually a
@@ -914,7 +925,11 @@
const ASTContext &Context = getContext();
CharUnits PointerWidth =
Context.toCharUnitsFromBits(Context.getTargetInfo().getPointerWidth(0));
- uint64_t VTableOffset = (Index * PointerWidth.getQuantity());
+ uint64_t VTableOffset = Index;
+ if (MD->getParent()->isRelativeCXXABI())
+ VTableOffset *= 4;
+ else
+ VTableOffset *= PointerWidth.getQuantity();
if (UseARMMethodPtrABI) {
// ARM C++ ABI 3.2.1:
@@ -1584,10 +1599,7 @@
CGM.GetAddrOfRTTIDescriptor(CGM.getContext().getTagDeclType(RD));
// Create and set the initializer.
- ConstantInitBuilder Builder(CGM);
- auto Components = Builder.beginStruct();
- CGVT.createVTableInitializer(Components, VTLayout, RTTI);
- Components.finishAndSetAsInitializer(VTable);
+ CGVT.SetVTableInitializer(VTable, VTLayout, RTTI, RD->isRelativeCXXABI());
// Set the correct linkage.
VTable->setLinkage(Linkage);
@@ -1695,7 +1707,7 @@
const VTableLayout &VTLayout =
CGM.getItaniumVTableContext().getVTableLayout(RD);
- llvm::Type *VTableType = CGM.getVTables().getVTableType(VTLayout);
+ llvm::Type *VTableType = CGM.getVTables().getVTableType(RD, VTLayout);
// Use pointer alignment for the vtable. Otherwise we would align them based
// on the size of the initializer which doesn't make sense as only single
@@ -1717,9 +1729,9 @@
Address This,
llvm::Type *Ty,
SourceLocation Loc) {
- Ty = Ty->getPointerTo()->getPointerTo();
auto *MethodDecl = cast<CXXMethodDecl>(GD.getDecl());
- llvm::Value *VTable = CGF.GetVTablePtr(This, Ty, MethodDecl->getParent());
+ llvm::Value *VTable = CGF.GetVTablePtr(
+ This, Ty->getPointerTo()->getPointerTo(), MethodDecl->getParent());
uint64_t VTableIndex = CGM.getItaniumVTableContext().getMethodVTableIndex(GD);
llvm::Value *VFunc;
@@ -1730,10 +1742,8 @@
} else {
CGF.EmitTypeMetadataCodeForVCall(MethodDecl->getParent(), VTable, Loc);
- llvm::Value *VFuncPtr =
- CGF.Builder.CreateConstInBoundsGEP1_64(VTable, VTableIndex, "vfn");
- auto *VFuncLoad =
- CGF.Builder.CreateAlignedLoad(VFuncPtr, CGF.getPointerAlign());
+ auto *VFuncLoad = CGF.GetVirtualFunctionFromVTable(MethodDecl->getParent(),
+ VTable, VTableIndex, Ty);
// Add !invariant.load md to virtual function load to indicate that
// function didn't change inside vtable.
@@ -1742,11 +1752,14 @@
// the same virtual function loads from the same vtable load, which won't
// happen without enabled devirtualization with -fstrict-vtable-pointers.
if (CGM.getCodeGenOpts().OptimizationLevel > 0 &&
- CGM.getCodeGenOpts().StrictVTablePointers)
- VFuncLoad->setMetadata(
- llvm::LLVMContext::MD_invariant_load,
- llvm::MDNode::get(CGM.getLLVMContext(),
- llvm::ArrayRef<llvm::Metadata *>()));
+ CGM.getCodeGenOpts().StrictVTablePointers) {
+ if (auto *VFuncLoadInstr = dyn_cast<llvm::Instruction>(VFuncLoad)) {
+ VFuncLoadInstr->setMetadata(
+ llvm::LLVMContext::MD_invariant_load,
+ llvm::MDNode::get(CGM.getLLVMContext(),
+ llvm::ArrayRef<llvm::Metadata *>()));
+ }
+ }
VFunc = VFuncLoad;
}
Index: clang/lib/CodeGen/CodeGenFunction.h
===================================================================
--- clang/lib/CodeGen/CodeGenFunction.h
+++ clang/lib/CodeGen/CodeGenFunction.h
@@ -1904,6 +1904,11 @@
llvm::Value *GetVTablePtr(Address This, llvm::Type *VTableTy,
const CXXRecordDecl *VTableClass);
+ llvm::Value *GetVirtualFunctionFromVTable(const CXXRecordDecl *RD,
+ llvm::Value *VTable,
+ uint64_t VTableIndex,
+ llvm::Type *Ty);
+
enum CFITypeCheckKind {
CFITCK_VCall,
CFITCK_NVCall,
Index: clang/lib/CodeGen/CGVTables.h
===================================================================
--- clang/lib/CodeGen/CGVTables.h
+++ clang/lib/CodeGen/CGVTables.h
@@ -61,17 +61,33 @@
const ThunkInfo &ThunkAdjustments,
bool ForVTable);
- void addVTableComponent(ConstantArrayBuilder &builder,
- const VTableLayout &layout, unsigned idx,
- llvm::Constant *rtti,
- unsigned &nextVTableThunkIndex);
+ /// Get the constant to be added to a VTable.
+ llvm::Constant *getVTableComponent(const VTableLayout &layout,
+ unsigned componentIdx, unsigned vtableIdx,
+ llvm::Constant *rtti,
+ unsigned &nextVTableThunkIndex,
+ bool RelativeABI);
public:
/// Add vtable components for the given vtable layout to the given
/// global initializer.
- void createVTableInitializer(ConstantStructBuilder &builder,
- const VTableLayout &layout,
- llvm::Constant *rtti);
+ void SetVTableInitializer(llvm::GlobalVariable *VTable,
+ const VTableLayout &VTLayout, llvm::Constant *RTTI,
+ bool RelativeABI);
+
+ /// Make a function pointer into a relative integer when using the relative
+ /// vtables ABI.
+ llvm::Constant *makeRelative(llvm::Constant *C, llvm::GlobalVariable *VTable,
+ unsigned vtableIdx,
+ unsigned lastAddrPoint) const;
+
+ /// Populate the fields of a single vtable element. This accepts either a
+ /// StructBuilder or ArrayBuilder.
+ template <class BuilderTy>
+ void buildVTableElement(BuilderTy &builder, llvm::GlobalVariable *VTable,
+ const VTableLayout &VTLayout, llvm::Constant *RTTI,
+ unsigned &nextVTableThunkIndex, unsigned vtableIdx,
+ bool RelativeABI);
CodeGenVTables(CodeGenModule &CGM);
@@ -123,7 +139,8 @@
/// Returns the type of a vtable with the given layout. Normally a struct of
/// arrays of pointers, with one struct element for each vtable in the vtable
/// group.
- llvm::Type *getVTableType(const VTableLayout &layout);
+ llvm::Type *getVTableType(const CXXRecordDecl *RD,
+ const VTableLayout &layout);
};
} // end namespace CodeGen
Index: clang/lib/CodeGen/CGVTables.cpp
===================================================================
--- clang/lib/CodeGen/CGVTables.cpp
+++ clang/lib/CodeGen/CGVTables.cpp
@@ -586,15 +586,43 @@
maybeEmitThunk(GD, Thunk, /*ForVTable=*/false);
}
-void CodeGenVTables::addVTableComponent(
- ConstantArrayBuilder &builder, const VTableLayout &layout,
- unsigned idx, llvm::Constant *rtti, unsigned &nextVTableThunkIndex) {
- auto &component = layout.vtable_components()[idx];
+llvm::Constant *CodeGenVTables::makeRelative(llvm::Constant *C,
+ llvm::GlobalVariable *VTable,
+ unsigned vtableIdx,
+ unsigned lastAddrPoint) const {
+ llvm::Type *Int32Ty = CGM.Int32Ty;
+ llvm::Type *PtrDiffTy =
+ CGM.getTypes().ConvertType(CGM.getContext().getPointerDiffType());
+ llvm::Type *VTableTy = VTable->getValueType();
+ llvm::Constant *gep = llvm::ConstantExpr::getGetElementPtr(
+ VTableTy, VTable,
+ llvm::ArrayRef<llvm::Constant *>{
+ llvm::ConstantInt::get(Int32Ty, 0),
+ llvm::ConstantInt::get(Int32Ty, vtableIdx),
+ llvm::ConstantInt::get(Int32Ty, lastAddrPoint)});
+
+ llvm::Constant *AddrPointInt =
+ llvm::ConstantExpr::getPtrToInt(gep, PtrDiffTy);
+ llvm::Constant *ptrToInt = llvm::ConstantExpr::getPtrToInt(C, PtrDiffTy);
+
+ return llvm::ConstantExpr::getIntegerCast(
+ llvm::ConstantExpr::getSub(ptrToInt, AddrPointInt), Int32Ty,
+ /*isSigned=*/true);
+}
+
+llvm::Constant *CodeGenVTables::getVTableComponent(
+ const VTableLayout &layout, unsigned componentIdx, unsigned vtableIdx,
+ llvm::Constant *rtti, unsigned &nextVTableThunkIndex, bool RelativeABI) {
+ auto &component = layout.getVTableComponent(componentIdx);
+
+ llvm::Type *Int8PtrTy = CGM.Int8PtrTy;
+ llvm::Type *Int32Ty = CGM.Int32Ty;
+ llvm::Type *FunctionPtrTy = RelativeABI ? Int32Ty : Int8PtrTy;
auto addOffsetConstant = [&](CharUnits offset) {
- builder.add(llvm::ConstantExpr::getIntToPtr(
+ return llvm::ConstantExpr::getIntToPtr(
llvm::ConstantInt::get(CGM.PtrDiffTy, offset.getQuantity()),
- CGM.Int8PtrTy));
+ CGM.Int8PtrTy);
};
switch (component.getKind()) {
@@ -608,7 +636,7 @@
return addOffsetConstant(component.getOffsetToTop());
case VTableComponent::CK_RTTI:
- return builder.add(llvm::ConstantExpr::getBitCast(rtti, CGM.Int8PtrTy));
+ return llvm::ConstantExpr::getBitCast(rtti, CGM.Int8PtrTy);
case VTableComponent::CK_FunctionPointer:
case VTableComponent::CK_CompleteDtorPointer:
@@ -642,7 +670,7 @@
? MD->hasAttr<CUDADeviceAttr>()
: (MD->hasAttr<CUDAHostAttr>() || !MD->hasAttr<CUDADeviceAttr>());
if (!CanEmitMethod)
- return builder.addNullPointer(CGM.Int8PtrTy);
+ return llvm::ConstantExpr::getNullValue(FunctionPtrTy);
// Method is acceptable, continue processing as usual.
}
@@ -674,7 +702,8 @@
// Thunks.
} else if (nextVTableThunkIndex < layout.vtable_thunks().size() &&
- layout.vtable_thunks()[nextVTableThunkIndex].first == idx) {
+ layout.vtable_thunks()[nextVTableThunkIndex].first ==
+ componentIdx) {
auto &thunkInfo = layout.vtable_thunks()[nextVTableThunkIndex].second;
nextVTableThunkIndex++;
@@ -686,40 +715,104 @@
fnPtr = CGM.GetAddrOfFunction(GD, fnTy, /*ForVTable=*/true);
}
- fnPtr = llvm::ConstantExpr::getBitCast(fnPtr, CGM.Int8PtrTy);
- builder.add(fnPtr);
- return;
+ return llvm::ConstantExpr::getBitCast(fnPtr, CGM.Int8PtrTy);
}
case VTableComponent::CK_UnusedFunctionPointer:
- return builder.addNullPointer(CGM.Int8PtrTy);
+ return llvm::ConstantExpr::getNullValue(FunctionPtrTy);
}
llvm_unreachable("Unexpected vtable component kind");
}
-llvm::Type *CodeGenVTables::getVTableType(const VTableLayout &layout) {
- SmallVector<llvm::Type *, 4> tys;
+llvm::Type *CodeGenVTables::getVTableType(const CXXRecordDecl *RD,
+ const VTableLayout &layout) {
+ SmallVector<llvm::Type *, 4> types;
for (unsigned i = 0, e = layout.getNumVTables(); i != e; ++i) {
- tys.push_back(llvm::ArrayType::get(CGM.Int8PtrTy, layout.getVTableSize(i)));
+ if (!RD->isRelativeCXXABI()) {
+ types.push_back(
+ llvm::ArrayType::get(CGM.Int8PtrTy, layout.getVTableSize(i)));
+ } else {
+ SmallVector<llvm::Type *, 4> innerTypes;
+ size_t thisIndex = layout.getVTableOffset(i);
+ size_t nextIndex = thisIndex + layout.getVTableSize(i);
+ for (unsigned componentIdx = thisIndex; componentIdx != nextIndex;
+ ++componentIdx) {
+ auto &component = layout.getVTableComponent(componentIdx);
+ if (component.isFunctionPointerKind())
+ innerTypes.push_back(CGM.Int32Ty);
+ else
+ innerTypes.push_back(CGM.Int8PtrTy);
+ }
+ types.push_back(llvm::StructType::get(CGM.getLLVMContext(), innerTypes));
+ }
}
- return llvm::StructType::get(CGM.getLLVMContext(), tys);
+ return llvm::StructType::get(CGM.getLLVMContext(), types);
}
-void CodeGenVTables::createVTableInitializer(ConstantStructBuilder &builder,
- const VTableLayout &layout,
- llvm::Constant *rtti) {
+template <class BuilderTy>
+void CodeGenVTables::buildVTableElement(BuilderTy &builder,
+ llvm::GlobalVariable *VTable,
+ const VTableLayout &VTLayout,
+ llvm::Constant *RTTI,
+ unsigned &nextVTableThunkIndex,
+ unsigned vtableIdx, bool RelativeABI) {
+ // We want to point to the first function in the vtable. This would
+ // normally be the 3rd component under Itanium ABI (2nd for Microsoft),
+ // but not in the case of virtual inheritance. For both of these ABIs, the
+ // first virtual function comes after the RTTI component, so we can just
+ // check if the previous component was RTTI.
+ //
+ // FIXME: Need a better way of identifying address points that works with
+ // the Itanium and MS ABIs.
+ unsigned lastAddrPoint = 0;
+
+ size_t thisIndex = VTLayout.getVTableOffset(vtableIdx);
+ size_t nextIndex = thisIndex + VTLayout.getVTableSize(vtableIdx);
+ for (unsigned componentIdx = thisIndex; componentIdx != nextIndex;
+ ++componentIdx) {
+ if (componentIdx > 0 &&
+ VTLayout.getVTableComponent(componentIdx - 1).isRTTIKind())
+ lastAddrPoint = componentIdx;
+
+ llvm::Constant *component =
+ getVTableComponent(VTLayout, componentIdx, vtableIdx, RTTI,
+ nextVTableThunkIndex, RelativeABI);
+
+ auto &layoutComponent = VTLayout.getVTableComponent(componentIdx);
+ if (RelativeABI && layoutComponent.isUsedFunctionPointerKind())
+ component =
+ makeRelative(component, VTable, vtableIdx, lastAddrPoint - thisIndex);
+
+ builder.add(component);
+ }
+}
+
+void CodeGenVTables::SetVTableInitializer(llvm::GlobalVariable *VTable,
+ const VTableLayout &VTLayout,
+ llvm::Constant *RTTI,
+ bool RelativeABI) {
+ ConstantInitBuilder builder(CGM);
+ auto components = builder.beginStruct();
+
unsigned nextVTableThunkIndex = 0;
- for (unsigned i = 0, e = layout.getNumVTables(); i != e; ++i) {
- auto vtableElem = builder.beginArray(CGM.Int8PtrTy);
- size_t thisIndex = layout.getVTableOffset(i);
- size_t nextIndex = thisIndex + layout.getVTableSize(i);
- for (unsigned i = thisIndex; i != nextIndex; ++i) {
- addVTableComponent(vtableElem, layout, i, rtti, nextVTableThunkIndex);
+ for (unsigned vtableIdx = 0; vtableIdx != VTLayout.getNumVTables();
+ ++vtableIdx) {
+ if (!RelativeABI) {
+ auto vtableElem = components.beginArray(CGM.Int8PtrTy);
+ buildVTableElement(vtableElem, VTable, VTLayout, RTTI,
+ nextVTableThunkIndex, vtableIdx, RelativeABI);
+ vtableElem.finishAndAddTo(components);
+ } else {
+ auto vtableElem = components.beginStruct();
+ buildVTableElement(vtableElem, VTable, VTLayout, RTTI,
+ nextVTableThunkIndex, vtableIdx, RelativeABI);
+ vtableElem.finishAndAddTo(components);
}
- vtableElem.finishAndAddTo(builder);
}
+
+ components.finishAndSetAsInitializer(VTable);
}
llvm::GlobalVariable *
@@ -746,7 +839,7 @@
Base.getBase(), Out);
StringRef Name = OutName.str();
- llvm::Type *VTType = getVTableType(*VTLayout);
+ llvm::Type *VTType = getVTableType(RD, *VTLayout);
// Construction vtable symbols are not part of the Itanium ABI, so we cannot
// guarantee that they actually will be available externally. Instead, when
@@ -769,10 +862,7 @@
CGM.getContext().getTagDeclType(Base.getBase()));
// Create and set the initializer.
- ConstantInitBuilder builder(CGM);
- auto components = builder.beginStruct();
- createVTableInitializer(components, *VTLayout, RTTI);
- components.finishAndSetAsInitializer(VTable);
+ SetVTableInitializer(VTable, *VTLayout, RTTI, RD->isRelativeCXXABI());
// Set properties only after the initializer has been set to ensure that the
// GV is treated as definition and not declaration.
@@ -1053,8 +1143,10 @@
ArrayRef<VTableComponent> Comps = VTLayout.vtable_components();
for (auto AP : AddressPoints) {
+ CharUnits ByteOffset = PointerWidth * AP.second;
+
// Create type metadata for the address point.
- AddVTableTypeMetadata(VTable, PointerWidth * AP.second, AP.first);
+ AddVTableTypeMetadata(VTable, ByteOffset, AP.first);
// The class associated with each address point could also potentially be
// used for indirect calls via a member function pointer, so we need to
Index: clang/lib/CodeGen/CGDebugInfo.cpp
===================================================================
--- clang/lib/CodeGen/CGDebugInfo.cpp
+++ clang/lib/CodeGen/CGDebugInfo.cpp
@@ -1542,8 +1542,11 @@
if (CGM.getTarget().getCXXABI().isItaniumFamily()) {
// It doesn't make sense to give a virtual destructor a vtable index,
// since a single destructor has two entries in the vtable.
- if (!isa<CXXDestructorDecl>(Method))
+ if (!isa<CXXDestructorDecl>(Method) &&
+ !Method->getParent()->isRelativeCXXABI())
VIndex = CGM.getItaniumVTableContext().getMethodVTableIndex(Method);
+ else
+ VIndex = -1u;
} else {
// Emit MS ABI vftable information. There is only one entry for the
// deleting dtor.
Index: clang/lib/CodeGen/CGClass.cpp
===================================================================
--- clang/lib/CodeGen/CGClass.cpp
+++ clang/lib/CodeGen/CGClass.cpp
@@ -2587,6 +2587,23 @@
return VTable;
}
+llvm::Value *CodeGenFunction::GetVirtualFunctionFromVTable(
+ const CXXRecordDecl *RD, llvm::Value *VTable, uint64_t VTableIndex,
+ llvm::Type *Ty) {
+ if (!RD->isRelativeCXXABI()) {
+ VTable = Builder.CreateBitCast(VTable, Ty->getPointerTo()->getPointerTo());
+ llvm::Value *VTableSlotPtr =
+ Builder.CreateConstInBoundsGEP1_64(VTable, VTableIndex, "vfn");
+ return Builder.CreateAlignedLoad(VTableSlotPtr, getPointerAlign());
+ }
+
+ VTable = Builder.CreateBitCast(VTable, Int8PtrTy);
+ llvm::Value *Load = Builder.CreateCall(
+ CGM.getIntrinsic(llvm::Intrinsic::load_relative, {Int32Ty}),
+ {VTable, llvm::ConstantInt::get(Int32Ty, 4 * VTableIndex)});
+ return Builder.CreateBitCast(Load, Ty->getPointerTo());
+}
+
// If a class has a single non-virtual base and does not introduce or override
// virtual member functions or fields, it will have the same layout as its base.
// This function returns the least derived such class.
Index: clang/lib/AST/DeclCXX.cpp
===================================================================
--- clang/lib/AST/DeclCXX.cpp
+++ clang/lib/AST/DeclCXX.cpp
@@ -35,6 +35,7 @@
#include "clang/Basic/PartialDiagnostic.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/Basic/Specifiers.h"
+#include "clang/Basic/TargetInfo.h"
#include "llvm/ADT/None.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallVector.h"
@@ -102,7 +103,8 @@
ImplicitCopyAssignmentHasConstParam(true),
HasDeclaredCopyConstructorWithConstParam(false),
HasDeclaredCopyAssignmentWithConstParam(false), IsLambda(false),
- IsParsingBaseSpecifiers(false), HasODRHash(false), Definition(D) {}
+ IsParsingBaseSpecifiers(false), IsRelativeCXXABI(false),
+ HasODRHash(false), Definition(D) {}
CXXBaseSpecifier *CXXRecordDecl::DefinitionData::getBasesSlowCase() const {
return Bases.get(Definition->getASTContext().getExternalSource());
Index: clang/include/clang/Sema/Sema.h
===================================================================
--- clang/include/clang/Sema/Sema.h
+++ clang/include/clang/Sema/Sema.h
@@ -10972,6 +10972,9 @@
// (including field initializers) is fully parsed.
SmallVector<CXXRecordDecl*, 4> DelayedDllExportClasses;
+ /// Determine if this class can use the relative vtable ABI.
+ void checkClassABI(CXXRecordDecl *RD);
+
private:
class SavePendingParsedClassStateRAII {
public:
Index: clang/include/clang/Driver/Options.td
===================================================================
--- clang/include/clang/Driver/Options.td
+++ clang/include/clang/Driver/Options.td
@@ -1245,6 +1245,10 @@
"fno-fine-grained-bitfield-accesses">, Group<f_clang_Group>, Flags<[CC1Option]>,
HelpText<"Use large-integer access for consecutive bitfield runs.">;
+def fexperimental_relative_cxx_abi_vtables : Flag<["-"], "fexperimental-relative-c++-abi-vtables">,
+ Group<f_Group>, Flags<[CC1Option]>,
+ HelpText<"Use the experimental C++ class ABI for classes with virtual tables">;
+
def flat__namespace : Flag<["-"], "flat_namespace">;
def flax_vector_conversions : Flag<["-"], "flax-vector-conversions">, Group<f_Group>;
def flimited_precision_EQ : Joined<["-"], "flimited-precision=">, Group<f_Group>;
Index: clang/include/clang/Basic/LangOptions.def
===================================================================
--- clang/include/clang/Basic/LangOptions.def
+++ clang/include/clang/Basic/LangOptions.def
@@ -324,6 +324,10 @@
LANGOPT(RegisterStaticDestructors, 1, 1, "Register C++ static destructors")
+LANGOPT(RelativeCXXABIVTables, 1, 0,
+ "Whether to use clang's relative C++ ABI "
+ "for classes with vtables")
+
#undef LANGOPT
#undef COMPATIBLE_LANGOPT
#undef BENIGN_LANGOPT
Index: clang/include/clang/AST/VTableBuilder.h
===================================================================
--- clang/include/clang/AST/VTableBuilder.h
+++ clang/include/clang/AST/VTableBuilder.h
@@ -264,6 +264,10 @@
return VTableComponents;
}
+ VTableComponent &getVTableComponent(size_t i) const {
+ return VTableComponents[i];
+ }
+
ArrayRef<VTableThunkTy> vtable_thunks() const {
return VTableThunks;
}
Index: clang/include/clang/AST/DeclCXX.h
===================================================================
--- clang/include/clang/AST/DeclCXX.h
+++ clang/include/clang/AST/DeclCXX.h
@@ -527,6 +527,9 @@
/// Whether we are currently parsing base specifiers.
unsigned IsParsingBaseSpecifiers : 1;
+ /// \brief Whether the class uses the relative C++ vtable ABI.
+ unsigned IsRelativeCXXABI : 1;
+
unsigned HasODRHash : 1;
/// A hash of parts of the class to help in ODR checking.
@@ -807,6 +810,10 @@
return data().IsParsingBaseSpecifiers;
}
+ void setIsRelativeCXXABI() { data().IsRelativeCXXABI = true; }
+
+ bool isRelativeCXXABI() const { return data().IsRelativeCXXABI; }
+
unsigned getODRHash() const;
/// Sets the base classes of this struct or class.
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits