[clang] 1e02641 - [clang][CodeGen] Emit offsets to __cxa_pure/deleted_virtual under relative vtables (#224148)
via cfe-commits
cfe-commits at lists.llvm.org
Fri Sep 18 11:04:34 PDT 2026
Author: PiJoules
Date: 2026-09-18T11:04:29-07:00
New Revision: 1e02641babceb803e3b568e8dfbe5036f0f15f0f
URL: https://github.com/llvm/llvm-project/commit/1e02641babceb803e3b568e8dfbe5036f0f15f0f
DIFF: https://github.com/llvm/llvm-project/commit/1e02641babceb803e3b568e8dfbe5036f0f15f0f.diff
LOG: [clang][CodeGen] Emit offsets to __cxa_pure/deleted_virtual under relative vtables (#224148)
Previously, pure and deleted virtual functions were emitted as null (0)
in relative vtables as a temporary workaround for PR43094 (#42439).
Before dso_local_equivalent, taking relative offsets to external runtime
functions required generating local symbols, which caused LLD COMDAT
group merging conflicts for classes defined across multiple TUs.
With dso_local_equivalent, we can now emit direct relative offsets to
__cxa_pure_virtual and __cxa_deleted_virtual without generating local
aliases or encountering COMDAT signature clashes.
Added:
clang/test/CodeGenCXX/RelativeVTablesABI/deleted-virtual-method.cpp
Modified:
clang/lib/CodeGen/CGVTables.cpp
clang/test/CodeGenCXX/RelativeVTablesABI/override-pure-virtual-method.cpp
Removed:
################################################################################
diff --git a/clang/lib/CodeGen/CGVTables.cpp b/clang/lib/CodeGen/CGVTables.cpp
index ba4e90c0f95ba..f0c48eba1f5c3 100644
--- a/clang/lib/CodeGen/CGVTables.cpp
+++ b/clang/lib/CodeGen/CGVTables.cpp
@@ -819,16 +819,6 @@ void CodeGenVTables::addVTableComponent(ConstantArrayBuilder &builder,
}
auto getSpecialVirtualFn = [&](StringRef name) -> llvm::Constant * {
- // FIXME(PR43094): When merging comdat groups, lld can select a local
- // symbol as the signature symbol even though it cannot be accessed
- // outside that symbol's TU. The relative vtables ABI would make
- // __cxa_pure_virtual and __cxa_deleted_virtual local symbols, and
- // depending on link order, the comdat groups could resolve to the one
- // 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 (RelativeCXXABIVTables)
- return llvm::ConstantPointerNull::get(CGM.GlobalsInt8PtrTy);
-
llvm::FunctionType *fnTy =
llvm::FunctionType::get(CGM.VoidTy, /*isVarArg=*/false);
auto *F = cast<llvm::Function>(
diff --git a/clang/test/CodeGenCXX/RelativeVTablesABI/deleted-virtual-method.cpp b/clang/test/CodeGenCXX/RelativeVTablesABI/deleted-virtual-method.cpp
new file mode 100644
index 0000000000000..e683cce8a743b
--- /dev/null
+++ b/clang/test/CodeGenCXX/RelativeVTablesABI/deleted-virtual-method.cpp
@@ -0,0 +1,17 @@
+// Check the layout of the vtable for a class with a deleted virtual function.
+
+// RUN: %clang_cc1 %s -triple=aarch64-unknown-fuchsia -O1 -o - -emit-llvm -fhalf-no-semantic-interposition | FileCheck %s
+
+// CHECK: @_ZTV1A.local = internal constant { [4 x i32] } { [4 x i32] [i32 0, i32 trunc (i64 sub (i64 ptrtoint (ptr @_ZTI1A.rtti_proxy to i64), i64 ptrtoint (ptr getelementptr inbounds ({ [4 x i32] }, ptr @_ZTV1A.local, i32 0, i32 0, i32 2) to i64)) to i32), i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @__cxa_deleted_virtual to i64), i64 ptrtoint (ptr getelementptr inbounds ({ [4 x i32] }, ptr @_ZTV1A.local, i32 0, i32 0, i32 2) to i64)) to i32), i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @_ZN1A3barEv to i64), i64 ptrtoint (ptr getelementptr inbounds ({ [4 x i32] }, ptr @_ZTV1A.local, i32 0, i32 0, i32 2) to i64)) to i32)] }, align 4
+
+// CHECK: @_ZTV1A ={{.*}}alias { [4 x i32] }, ptr @_ZTV1A.local
+
+// CHECK: declare void @__cxa_deleted_virtual() unnamed_addr
+
+class A {
+public:
+ virtual void foo() = delete;
+ virtual void bar();
+};
+
+void A::bar() {}
diff --git a/clang/test/CodeGenCXX/RelativeVTablesABI/override-pure-virtual-method.cpp b/clang/test/CodeGenCXX/RelativeVTablesABI/override-pure-virtual-method.cpp
index 58d11f2b49ebd..67fb8196d193c 100644
--- a/clang/test/CodeGenCXX/RelativeVTablesABI/override-pure-virtual-method.cpp
+++ b/clang/test/CodeGenCXX/RelativeVTablesABI/override-pure-virtual-method.cpp
@@ -1,17 +1,16 @@
// Override pure virtual function.
-// We instead emit zero for the pure virtual function component. See PR43094 for
-// details.
+// Check that pure virtual functions emit a reference to __cxa_pure_virtual.
// RUN: %clang_cc1 %s -triple=aarch64-unknown-fuchsia -O1 -o - -emit-llvm -fhalf-no-semantic-interposition | FileCheck %s
-// CHECK: @_ZTV1A.local = internal constant { [4 x i32] } { [4 x i32] [i32 0, i32 trunc (i64 sub (i64 ptrtoint (ptr @_ZTI1A.rtti_proxy to i64), i64 ptrtoint (ptr getelementptr inbounds ({ [4 x i32] }, ptr @_ZTV1A.local, i32 0, i32 0, i32 2) to i64)) to i32), i32 0, i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @_ZN1A3barEv to i64), i64 ptrtoint (ptr getelementptr inbounds ({ [4 x i32] }, ptr @_ZTV1A.local, i32 0, i32 0, i32 2) to i64)) to i32)] }, align 4
+// CHECK: @_ZTV1A.local = internal constant { [4 x i32] } { [4 x i32] [i32 0, i32 trunc (i64 sub (i64 ptrtoint (ptr @_ZTI1A.rtti_proxy to i64), i64 ptrtoint (ptr getelementptr inbounds ({ [4 x i32] }, ptr @_ZTV1A.local, i32 0, i32 0, i32 2) to i64)) to i32), i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @__cxa_pure_virtual to i64), i64 ptrtoint (ptr getelementptr inbounds ({ [4 x i32] }, ptr @_ZTV1A.local, i32 0, i32 0, i32 2) to i64)) to i32), i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @_ZN1A3barEv to i64), i64 ptrtoint (ptr getelementptr inbounds ({ [4 x i32] }, ptr @_ZTV1A.local, i32 0, i32 0, i32 2) to i64)) to i32)] }, align 4
// CHECK: @_ZTV1B.local = internal constant { [4 x i32] } { [4 x i32] [i32 0, i32 trunc (i64 sub (i64 ptrtoint (ptr @_ZTI1B.rtti_proxy to i64), i64 ptrtoint (ptr getelementptr inbounds ({ [4 x i32] }, ptr @_ZTV1B.local, i32 0, i32 0, i32 2) to i64)) to i32), i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @_ZN1B3fooEv to i64), i64 ptrtoint (ptr getelementptr inbounds ({ [4 x i32] }, ptr @_ZTV1B.local, i32 0, i32 0, i32 2) to i64)) to i32), i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @_ZN1B3barEv to i64), i64 ptrtoint (ptr getelementptr inbounds ({ [4 x i32] }, ptr @_ZTV1B.local, i32 0, i32 0, i32 2) to i64)) to i32)] }, align 4
// CHECK: @_ZTV1A ={{.*}}alias { [4 x i32] }, ptr @_ZTV1A.local
// CHECK: @_ZTV1B ={{.*}}alias { [4 x i32] }, ptr @_ZTV1B.local
-// CHECK-NOT: declare void @__cxa_pure_virtual() unnamed_addr
+// CHECK: declare void @__cxa_pure_virtual() unnamed_addr
class A {
public:
More information about the cfe-commits
mailing list