[clang] [CIR] Implement pointer type RTTI (buildPointerTypeInfo) (PR #184011)
via cfe-commits
cfe-commits at lists.llvm.org
Mon Mar 2 04:02:37 PST 2026
https://github.com/Perdixky updated https://github.com/llvm/llvm-project/pull/184011
>From e7d6d88c49bca11d9c8855ffe4b894830dac6977 Mon Sep 17 00:00:00 2001
From: Nikita B <n2h9z4 at gmail.com>
Date: Thu, 16 Oct 2025 21:12:14 +0200
Subject: [PATCH 1/6] [CIR] vTableClassNameForType: return correct VTableClass
name for Type::ObjCObjectPointer, Type::Pointer
Signed-off-by: Nikita B <n2h9z4 at gmail.com>
---
clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp b/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp
index a18e2b91b1dd4..65b9ae9077e27 100644
--- a/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp
@@ -1009,8 +1009,7 @@ const char *vTableClassNameForType(const CIRGenModule &cgm, const Type *ty) {
case Type::ObjCObjectPointer:
case Type::Pointer:
- cgm.errorNYI("VTableClassNameForType: __pointer_type_info");
- break;
+ return "_ZTVN10__cxxabiv119__pointer_type_infoE";
case Type::MemberPointer:
cgm.errorNYI("VTableClassNameForType: __pointer_to_member_type_info");
>From 2168aa6f77e87ab8f1a72179d628d9cda94e14a7 Mon Sep 17 00:00:00 2001
From: Nikita B <n2h9z4 at gmail.com>
Date: Sat, 18 Oct 2025 13:15:23 +0200
Subject: [PATCH 2/6] [CIR] vTableClassNameForType: add throw test for
Type::Pointer
Signed-off-by: Nikita B <n2h9z4 at gmail.com>
---
clang/test/CIR/CodeGen/throws.cpp | 29 +++++++++++++++++++++++++++++
1 file changed, 29 insertions(+)
diff --git a/clang/test/CIR/CodeGen/throws.cpp b/clang/test/CIR/CodeGen/throws.cpp
index 53af1efc22cd4..bedb09a2d82ec 100644
--- a/clang/test/CIR/CodeGen/throws.cpp
+++ b/clang/test/CIR/CodeGen/throws.cpp
@@ -244,3 +244,32 @@ void throw_enum_class_expr() {
// OGCG: store i32 0, ptr %[[EXCEPTION_ADDR]], align 16
// OGCG: call void @__cxa_throw(ptr %[[EXCEPTION_ADDR]], ptr @_ZTIZ21throw_enum_class_exprvE4Test, ptr null)
// OGCG: unreachable
+
+void throw_pointer_type() {
+ static int var = 42;
+ int *ptr = &var;
+ throw ptr;
+}
+
+// CIR: %[[PTR_ADDR:.*]] = cir.alloca !cir.ptr<!s32i>, !cir.ptr<!cir.ptr<!s32i>>, ["ptr", init]
+// CIR: %[[VAR_ADDR:.*]] = cir.get_global @_ZZ18throw_pointer_typevE3var : !cir.ptr<!s32i>
+// CIR: cir.store{{.*}} %[[VAR_ADDR]], %[[PTR_ADDR]] : !cir.ptr<!s32i>, !cir.ptr<!cir.ptr<!s32i>>
+// CIR: %[[EXCEPTION_ADDR:.*]] = cir.alloc.exception 8 -> !cir.ptr<!cir.ptr<!s32i>>
+// CIR: %[[TMP_PTR:.*]] = cir.load{{.*}} %[[PTR_ADDR]] : !cir.ptr<!cir.ptr<!s32i>>, !cir.ptr<!s32i>
+// CIR: cir.store{{.*}} %[[TMP_PTR]], %[[EXCEPTION_ADDR]] : !cir.ptr<!s32i>, !cir.ptr<!cir.ptr<!s32i>>
+// CIR: cir.throw %[[EXCEPTION_ADDR]] : !cir.ptr<!cir.ptr<!s32i>>, @_ZTIPi
+// CIR: cir.unreachable
+
+// LLVM: %[[PTR_ADDR:.*]] = alloca ptr,{{.*}} align 8
+// LLVM: store ptr @_ZZ18throw_pointer_typevE3var, ptr %[[PTR_ADDR]], align 8
+// LLVM: %[[EXCEPTION_ADDR:.*]] = call ptr @__cxa_allocate_exception(i64 8)
+// LLVM: %[[TMP_PTR:.*]] = load ptr, ptr %[[PTR_ADDR]], align 8
+// LLVM: store ptr %[[TMP_PTR]], ptr %[[EXCEPTION_ADDR]], align 16
+// LLVM: call void @__cxa_throw(ptr %[[EXCEPTION_ADDR]], ptr @_ZTIPi, ptr null)
+
+// OGCG: %[[PTR_ADDR:.*]] = alloca ptr, align 8
+// OGCG: store ptr @_ZZ18throw_pointer_typevE3var, ptr %[[PTR_ADDR]], align 8
+// OGCG: %[[EXCEPTION_ADDR:.*]] = call ptr @__cxa_allocate_exception(i64 8)
+// OGCG: %[[TMP_PTR:.*]] = load ptr, ptr %[[PTR_ADDR]], align 8
+// OGCG: store ptr %[[TMP_PTR]], ptr %[[EXCEPTION_ADDR]], align 16
+// OGCG: call void @__cxa_throw(ptr %[[EXCEPTION_ADDR]], ptr @_ZTIPi, ptr null)
>From 1811f74074439a336c105eabcb6dfe7a965e426a Mon Sep 17 00:00:00 2001
From: Perdixky <3293789706 at qq.com>
Date: Sun, 1 Mar 2026 23:41:35 +0800
Subject: [PATCH 3/6] [CIR] Implement pointer type RTTI (buildPointerTypeInfo)
Add extractPBaseFlags() and buildPointerTypeInfo() to CIRGenItaniumCXXABI,
implementing __pointer_type_info emission per Itanium C++ ABI 2.9.4p7.
This handles PTI_Const/Volatile/Restrict/Incomplete/Noexcept flags and
recursively emits the pointee type info.
Also fix vTableClassNameForType for FunctionProto/FunctionNoProto to return
the correct __function_type_info vtable name instead of errorNYI, enabling
RTTI for pointer-to-function types.
Add clang/test/CIR/CodeGen/rtti-qualfn.cpp to test throwing a pointer to a
noexcept function, verifying the PTI_Noexcept flag (0x40 = 64) is set.
---
clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp | 68 ++++++++++++++++++-
clang/test/CIR/CodeGen/rtti-qualfn.cpp | 36 ++++++++++
2 files changed, 101 insertions(+), 3 deletions(-)
create mode 100644 clang/test/CIR/CodeGen/rtti-qualfn.cpp
diff --git a/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp b/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp
index 65b9ae9077e27..2f9400943c235 100644
--- a/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp
@@ -22,6 +22,7 @@
#include "clang/AST/ExprCXX.h"
#include "clang/AST/GlobalDecl.h"
+#include "clang/AST/TypeBase.h"
#include "clang/AST/VTableBuilder.h"
#include "clang/CIR/MissingFeatures.h"
#include "llvm/Support/ErrorHandling.h"
@@ -557,6 +558,10 @@ class CIRGenItaniumRTTIBuilder {
/// constraints, according ti the Itanium C++ ABI, 2.9.5p5c.
void buildVMIClassTypeInfo(mlir::Location loc, const CXXRecordDecl *rd);
+ /// Build an abi::__pointer_type_info, used for pointer types, according
+ /// to the Itanium API, 2.9.4p7.
+ void buildPointerTypeInfo(mlir::Location loc, QualType ty);
+
public:
CIRGenItaniumRTTIBuilder(const CIRGenItaniumCXXABI &abi, CIRGenModule &cgm)
: cgm(cgm), cxxABI(abi) {}
@@ -924,6 +929,31 @@ static bool containsIncompleteClassType(QualType ty) {
return false;
}
+static unsigned extractPBaseFlags(const ASTContext &ctx, QualType &ty) {
+ unsigned flags = 0;
+
+ if (ty.isConstQualified())
+ flags |= PTI_Const;
+ if (ty.isVolatileQualified())
+ flags |= PTI_Volatile;
+ if (ty.isRestrictQualified())
+ flags |= PTI_Restrict;
+
+ ty = ty.getUnqualifiedType();
+
+ if (containsIncompleteClassType(ty))
+ flags |= PTI_Incomplete;
+
+ if (const auto *proto = ty->getAs<FunctionProtoType>()) {
+ if (proto->isNothrow()) {
+ flags |= PTI_Noexcept;
+ ty = ctx.getFunctionTypeWithExceptionSpec(ty, EST_None);
+ }
+ }
+
+ return flags;
+}
+
const char *vTableClassNameForType(const CIRGenModule &cgm, const Type *ty) {
// abi::__class_type_info.
static const char *const classTypeInfo =
@@ -978,8 +1008,7 @@ const char *vTableClassNameForType(const CIRGenModule &cgm, const Type *ty) {
case Type::FunctionNoProto:
case Type::FunctionProto:
- cgm.errorNYI("VTableClassNameForType: __function_type_info");
- break;
+ return "_ZTVN10__cxxabiv120__function_type_infoE";
case Type::Enum:
return "_ZTVN10__cxxabiv116__enum_type_infoE";
@@ -1276,6 +1305,38 @@ void CIRGenItaniumRTTIBuilder::buildVMIClassTypeInfo(mlir::Location loc,
}
}
+void CIRGenItaniumRTTIBuilder::buildPointerTypeInfo(mlir::Location loc,
+ QualType ty) {
+ // Itanium C++ ABI 2.9.4p7:
+ // abi::__pbase_type_info is a base for both pointer types and
+ // pointer-to-member types. It adds two data members:
+ //
+ // class __pbase_type_info : public std::type_info {
+ // public:
+ // unsigned int __flags;
+ // const std::type_info *__pointee;
+ //
+ // enum __masks {
+ // __const_mask = 0x1,
+ // __volatile_mask = 0x2,
+ // __restrict_mask = 0x4,
+ // __incomplete_mask = 0x8,
+ // __incomplete_class_mask = 0x10,
+ // __transaction_safe_mask = 0x20
+ // __noexcept_mask = 0x40
+ // };
+ // };
+ const unsigned int flags = extractPBaseFlags(cgm.getASTContext(), ty);
+
+ auto unsignedIntTy = cgm.convertType(cgm.getASTContext().UnsignedIntTy);
+ mlir::Attribute flagsAttr = cir::IntAttr::get(unsignedIntTy, flags);
+ fields.push_back(flagsAttr);
+
+ mlir::Attribute pointeeTypeInfo =
+ CIRGenItaniumRTTIBuilder(cxxABI, cgm).buildTypeInfo(loc, ty);
+ fields.push_back(pointeeTypeInfo);
+}
+
mlir::Attribute CIRGenItaniumRTTIBuilder::buildTypeInfo(mlir::Location loc,
QualType ty) {
// We want to operate on the canonical type.
@@ -1437,7 +1498,8 @@ mlir::Attribute CIRGenItaniumRTTIBuilder::buildTypeInfo(
break;
case Type::Pointer:
- cgm.errorNYI("buildTypeInfo: Pointer");
+ // We need to get the type info for the pointee type.
+ buildPointerTypeInfo(loc, cast<PointerType>(ty)->getPointeeType());
break;
case Type::MemberPointer:
diff --git a/clang/test/CIR/CodeGen/rtti-qualfn.cpp b/clang/test/CIR/CodeGen/rtti-qualfn.cpp
new file mode 100644
index 0000000000000..acd732f65136b
--- /dev/null
+++ b/clang/test/CIR/CodeGen/rtti-qualfn.cpp
@@ -0,0 +1,36 @@
+// RUN: %clang_cc1 -std=c++17 -triple x86_64-unknown-linux-gnu -fcxx-exceptions -fexceptions -fclangir -emit-cir %s -o %t.cir
+// RUN: FileCheck --input-file=%t.cir %s -check-prefix=CIR
+// RUN: %clang_cc1 -std=c++17 -triple x86_64-unknown-linux-gnu -fcxx-exceptions -fexceptions -fclangir -emit-llvm %s -o %t-cir.ll
+// RUN: FileCheck --input-file=%t-cir.ll %s -check-prefix=LLVM
+// RUN: %clang_cc1 -std=c++17 -triple x86_64-unknown-linux-gnu -fcxx-exceptions -fexceptions -emit-llvm %s -o %t.ll
+// RUN: FileCheck --input-file=%t.ll %s -check-prefix=OGCG
+
+// Test that throwing a pointer to a noexcept function produces correct RTTI
+// with the PTI_Noexcept flag (0x40 = 64) set in the __pointer_type_info.
+
+void f() noexcept {
+ throw f;
+}
+
+// The pointee type _ZTIFvvE (function type info for void()) must be emitted
+// using the __function_type_info vtable.
+// CIR-DAG: cir.global {{.*}} @_ZTSFvvE = #cir.const_array<"FvvE" : !cir.array<!s8i x 4>> : !cir.array<!s8i x 4>
+// CIR-DAG: cir.global {{.*}} @_ZTIFvvE = #cir.typeinfo<{#cir.global_view<@_ZTVN10__cxxabiv120__function_type_infoE, [2 : i32]> : !cir.ptr<!u8i>, #cir.global_view<@_ZTSFvvE> : !cir.ptr<!u8i>}>
+
+// The pointer type info _ZTIPDoFvvE must include flag 64 (PTI_Noexcept).
+// CIR-DAG: cir.global {{.*}} @_ZTSPDoFvvE = #cir.const_array<"PDoFvvE" : !cir.array<!s8i x 7>> : !cir.array<!s8i x 7>
+// CIR-DAG: cir.global {{.*}} @_ZTIPDoFvvE = #cir.typeinfo<{#cir.global_view<@_ZTVN10__cxxabiv119__pointer_type_infoE, [2 : i32]> : !cir.ptr<!u8i>, #cir.global_view<@_ZTSPDoFvvE> : !cir.ptr<!u8i>, #cir.int<64> : !u32i, #cir.global_view<@_ZTIFvvE> : !cir.ptr<!u8i>}>
+
+// CIR: cir.throw %{{.*}} : !cir.ptr<!cir.ptr<!cir.func<()>>>, @_ZTIPDoFvvE
+
+// LLVM-DAG: @_ZTSFvvE = linkonce_odr global [4 x i8] c"FvvE"
+// LLVM-DAG: @_ZTIFvvE = constant { ptr, ptr } { ptr getelementptr (i8, ptr @_ZTVN10__cxxabiv120__function_type_infoE, i64 16), ptr @_ZTSFvvE }
+// LLVM-DAG: @_ZTSPDoFvvE = linkonce_odr global [7 x i8] c"PDoFvvE"
+// LLVM-DAG: @_ZTIPDoFvvE = constant { ptr, ptr, i32, ptr } { ptr getelementptr (i8, ptr @_ZTVN10__cxxabiv119__pointer_type_infoE, i64 16), ptr @_ZTSPDoFvvE, i32 64, ptr @_ZTIFvvE }
+// LLVM: call void @__cxa_throw(ptr %{{.*}}, ptr @_ZTIPDoFvvE, ptr null)
+
+// OGCG-DAG: @_ZTSFvvE = linkonce_odr constant [5 x i8] c"FvvE\00", comdat
+// OGCG-DAG: @_ZTIFvvE = linkonce_odr constant { ptr, ptr } { ptr getelementptr inbounds (ptr, ptr @_ZTVN10__cxxabiv120__function_type_infoE, i64 2), ptr @_ZTSFvvE }, comdat
+// OGCG-DAG: @_ZTSPDoFvvE = linkonce_odr constant [8 x i8] c"PDoFvvE\00", comdat
+// OGCG-DAG: @_ZTIPDoFvvE = linkonce_odr constant { ptr, ptr, i32, ptr } { ptr getelementptr inbounds (ptr, ptr @_ZTVN10__cxxabiv119__pointer_type_infoE, i64 2), ptr @_ZTSPDoFvvE, i32 64, ptr @_ZTIFvvE }, comdat
+// OGCG: invoke void @__cxa_throw(ptr %{{.*}}, ptr @_ZTIPDoFvvE, ptr null)
>From 497b5d4571df4649a55e592af1c63c7c0245a561 Mon Sep 17 00:00:00 2001
From: Perdixky <105138864+Perdixky at users.noreply.github.com>
Date: Mon, 2 Mar 2026 08:55:10 +0800
Subject: [PATCH 4/6] [CIR] Fix typo
---
clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp b/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp
index 2f9400943c235..302c64fc25db0 100644
--- a/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp
@@ -559,7 +559,7 @@ class CIRGenItaniumRTTIBuilder {
void buildVMIClassTypeInfo(mlir::Location loc, const CXXRecordDecl *rd);
/// Build an abi::__pointer_type_info, used for pointer types, according
- /// to the Itanium API, 2.9.4p7.
+ /// to the Itanium C++ ABI, 2.9.4p7.
void buildPointerTypeInfo(mlir::Location loc, QualType ty);
public:
>From cf8ecf78b06a738dfbed537203be9da1134c81dd Mon Sep 17 00:00:00 2001
From: Perdixky <3293789706 at qq.com>
Date: Mon, 2 Mar 2026 15:38:27 +0800
Subject: [PATCH 5/6] [CIR] Implement MemberPointer/ObjCObjectPointer RTTI
Add buildPointerToMemberTypeInfo() to CIRGenItaniumCXXABI to emit
__pointer_to_member_type_info which carries three fields: flags, pointee
and context (the containing class type) per Itanium C++ ABI 2.9.5p7.
Also fix vTableClassNameForType to return the correct vtable names for
Type::MemberPointer and Type::ObjCObjectPointer.
Add test for pointer-to-member RTTI. ObjCObjectPointer test is omitted
because CIR does not yet support ObjC AST codegen.
---
clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp | 39 ++++++++-
.../test/CIR/CodeGen/rtti-member-pointer.cpp | 79 +++++++++++++++++++
2 files changed, 116 insertions(+), 2 deletions(-)
create mode 100644 clang/test/CIR/CodeGen/rtti-member-pointer.cpp
diff --git a/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp b/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp
index 302c64fc25db0..2b6f6e738e8f2 100644
--- a/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp
@@ -562,6 +562,10 @@ class CIRGenItaniumRTTIBuilder {
/// to the Itanium C++ ABI, 2.9.4p7.
void buildPointerTypeInfo(mlir::Location loc, QualType ty);
+ /// Build an abi::__pointer_to_member_type_info, used for pointer to member
+ /// types, according to the Itanium C++ ABI, 2.9.4p9.
+ void buildPointerToMemberTypeInfo(mlir::Location loc, const MemberPointerType *ty);
+
public:
CIRGenItaniumRTTIBuilder(const CIRGenItaniumCXXABI &abi, CIRGenModule &cgm)
: cgm(cgm), cxxABI(abi) {}
@@ -1041,7 +1045,7 @@ const char *vTableClassNameForType(const CIRGenModule &cgm, const Type *ty) {
return "_ZTVN10__cxxabiv119__pointer_type_infoE";
case Type::MemberPointer:
- cgm.errorNYI("VTableClassNameForType: __pointer_to_member_type_info");
+ return "_ZTVN10__cxxabiv129__pointer_to_member_type_infoE";
break;
case Type::HLSLAttributedResource:
@@ -1337,6 +1341,37 @@ void CIRGenItaniumRTTIBuilder::buildPointerTypeInfo(mlir::Location loc,
fields.push_back(pointeeTypeInfo);
}
+void CIRGenItaniumRTTIBuilder::buildPointerToMemberTypeInfo(
+ mlir::Location loc, const MemberPointerType *ty) {
+
+ // The abi::__pointer_to_member_type_info type adds one field to abi::__pbase_type_info:
+ //
+ // class __pointer_to_member_type_info : public __pbase_type_info {
+ // public:
+ // const abi::__class_type_info *__context;
+ // };
+ QualType pointeeTy = ty->getPointeeType();
+
+ unsigned flags = extractPBaseFlags(cgm.getASTContext(), pointeeTy);
+
+ const auto *rd = ty->getMostRecentCXXRecordDecl();
+ if (!rd->hasDefinition())
+ flags |= PTI_ContainingClassIncomplete;
+
+ auto unsignedIntTy = cgm.convertType(cgm.getASTContext().UnsignedIntTy);
+ mlir::Attribute flagsAttr = cir::IntAttr::get(unsignedIntTy, flags);
+ fields.push_back(flagsAttr);
+
+ mlir::Attribute pointeeTypeInfo =
+ CIRGenItaniumRTTIBuilder(cxxABI, cgm).buildTypeInfo(loc, pointeeTy);
+ fields.push_back(pointeeTypeInfo);
+
+ CanQualType contextTy = cgm.getASTContext().getCanonicalTagType(rd);
+ mlir::Attribute classTypeInfo =
+ CIRGenItaniumRTTIBuilder(cxxABI, cgm).buildTypeInfo(loc, contextTy);
+ fields.push_back(classTypeInfo);
+}
+
mlir::Attribute CIRGenItaniumRTTIBuilder::buildTypeInfo(mlir::Location loc,
QualType ty) {
// We want to operate on the canonical type.
@@ -1503,7 +1538,7 @@ mlir::Attribute CIRGenItaniumRTTIBuilder::buildTypeInfo(
break;
case Type::MemberPointer:
- cgm.errorNYI("buildTypeInfo: MemberPointer");
+ buildPointerToMemberTypeInfo(loc, cast<MemberPointerType>(ty));
break;
case Type::Atomic:
diff --git a/clang/test/CIR/CodeGen/rtti-member-pointer.cpp b/clang/test/CIR/CodeGen/rtti-member-pointer.cpp
new file mode 100644
index 0000000000000..4b863d93e259f
--- /dev/null
+++ b/clang/test/CIR/CodeGen/rtti-member-pointer.cpp
@@ -0,0 +1,79 @@
+// RUN: %clang_cc1 -std=c++17 -triple x86_64-unknown-linux-gnu -fcxx-exceptions -fexceptions -fclangir -emit-cir %s -o %t.cir
+// RUN: FileCheck --input-file=%t.cir %s -check-prefix=CIR
+// RUN: %clang_cc1 -std=c++17 -triple x86_64-unknown-linux-gnu -fcxx-exceptions -fexceptions -fclangir -emit-llvm %s -o %t-cir.ll
+// RUN: FileCheck --input-file=%t-cir.ll %s -check-prefix=LLVM
+// RUN: %clang_cc1 -std=c++17 -triple x86_64-unknown-linux-gnu -fcxx-exceptions -fexceptions -emit-llvm %s -o %t.ll
+// RUN: FileCheck --input-file=%t.ll %s -check-prefix=OGCG
+
+// Test RTTI emission for pointer-to-member types (abi::__pointer_to_member_type_info).
+// Each descriptor must use the __pointer_to_member_type_info vtable and carry
+// three extra fields beyond the standard type_info header:
+// __flags (unsigned int)
+// __pointee (const type_info* for the pointed-to type)
+// __context (const __class_type_info* for the containing class)
+
+struct A {
+ int data;
+ void func();
+};
+
+// --- Test 1: data member pointer (int A::*) ---
+
+void throw_data_member_ptr() {
+ int A::*p = &A::data;
+ throw p;
+}
+
+// Class A has no bases, so it uses __class_type_info.
+// CIR-DAG: cir.global {{.*}} @_ZTS1A = #cir.const_array<"1A" : !cir.array<!s8i x 2>> : !cir.array<!s8i x 2>
+// CIR-DAG: cir.global {{.*}} @_ZTI1A = #cir.typeinfo<{#cir.global_view<@_ZTVN10__cxxabiv117__class_type_infoE, [2 : i32]> : !cir.ptr<!u8i>, #cir.global_view<@_ZTS1A> : !cir.ptr<!u8i>}>
+
+// The type name for "int A::*" is "M1Ai".
+// CIR-DAG: cir.global {{.*}} @_ZTSM1Ai = #cir.const_array<"M1Ai" : !cir.array<!s8i x 4>> : !cir.array<!s8i x 4>
+
+// The member-pointer type info must use the __pointer_to_member_type_info vtable,
+// flags=0 (int has no cv-qualifiers), pointee=int (_ZTIi), context=A (_ZTI1A).
+// CIR-DAG: cir.global {{.*}} @_ZTIM1Ai = #cir.typeinfo<{#cir.global_view<@_ZTVN10__cxxabiv129__pointer_to_member_type_infoE, [2 : i32]> : !cir.ptr<!u8i>, #cir.global_view<@_ZTSM1Ai> : !cir.ptr<!u8i>, #cir.int<0> : !u32i, #cir.global_view<@_ZTIi> : !cir.ptr<!u8i>, #cir.global_view<@_ZTI1A> : !cir.ptr<!u8i>}>
+
+// CIR-DAG: cir.throw %{{.*}} : !cir.ptr<!s64i>, @_ZTIM1Ai
+
+// LLVM-DAG: @_ZTSM1Ai = linkonce_odr global [4 x i8] c"M1Ai"
+// LLVM-DAG: @_ZTS1A = linkonce_odr global [2 x i8] c"1A"
+// LLVM-DAG: @_ZTI1A = constant { ptr, ptr } { ptr getelementptr (i8, ptr @_ZTVN10__cxxabiv117__class_type_infoE, i64 16), ptr @_ZTS1A }
+// LLVM-DAG: @_ZTIM1Ai = constant { ptr, ptr, i32, ptr, ptr } { ptr getelementptr (i8, ptr @_ZTVN10__cxxabiv129__pointer_to_member_type_infoE, i64 16), ptr @_ZTSM1Ai, i32 0, ptr @_ZTIi, ptr @_ZTI1A }
+// LLVM-DAG: call void @__cxa_throw(ptr %{{.*}}, ptr @_ZTIM1Ai, ptr null)
+
+// OGCG-DAG: @_ZTSM1Ai = linkonce_odr constant [5 x i8] c"M1Ai\00", comdat
+// OGCG-DAG: @_ZTS1A = linkonce_odr constant [3 x i8] c"1A\00", comdat
+// OGCG-DAG: @_ZTI1A = linkonce_odr constant { ptr, ptr } { ptr getelementptr inbounds (ptr, ptr @_ZTVN10__cxxabiv117__class_type_infoE, i64 2), ptr @_ZTS1A }, comdat
+// OGCG-DAG: @_ZTIM1Ai = linkonce_odr constant { ptr, ptr, i32, ptr, ptr } { ptr getelementptr inbounds (ptr, ptr @_ZTVN10__cxxabiv129__pointer_to_member_type_infoE, i64 2), ptr @_ZTSM1Ai, i32 0, ptr @_ZTIi, ptr @_ZTI1A }, comdat
+// OGCG-DAG: call void @__cxa_throw(ptr %{{.*}}, ptr @_ZTIM1Ai, ptr null)
+
+// --- Test 2: member function pointer (void (A::*)()) ---
+
+void throw_member_fn_ptr() {
+ void (A::*p)() = &A::func;
+ throw p;
+}
+
+// The type name for "void (A::*)()" is "M1AFvvE".
+// CIR-DAG: cir.global {{.*}} @_ZTSM1AFvvE = #cir.const_array<"M1AFvvE" : !cir.array<!s8i x 7>> : !cir.array<!s8i x 7>
+
+// The pointee "void()" is a function type, using __function_type_info.
+// CIR-DAG: cir.global {{.*}} @_ZTSFvvE = #cir.const_array<"FvvE" : !cir.array<!s8i x 4>> : !cir.array<!s8i x 4>
+// CIR-DAG: cir.global {{.*}} @_ZTIFvvE = #cir.typeinfo<{#cir.global_view<@_ZTVN10__cxxabiv120__function_type_infoE, [2 : i32]> : !cir.ptr<!u8i>, #cir.global_view<@_ZTSFvvE> : !cir.ptr<!u8i>}>
+
+// flags=0, pointee=void() (_ZTIFvvE), context=A (_ZTI1A).
+// CIR-DAG: cir.global {{.*}} @_ZTIM1AFvvE = #cir.typeinfo<{#cir.global_view<@_ZTVN10__cxxabiv129__pointer_to_member_type_infoE, [2 : i32]> : !cir.ptr<!u8i>, #cir.global_view<@_ZTSM1AFvvE> : !cir.ptr<!u8i>, #cir.int<0> : !u32i, #cir.global_view<@_ZTIFvvE> : !cir.ptr<!u8i>, #cir.global_view<@_ZTI1A> : !cir.ptr<!u8i>}>
+
+// LLVM-DAG: @_ZTSM1AFvvE = linkonce_odr global [7 x i8] c"M1AFvvE"
+// LLVM-DAG: @_ZTSFvvE = linkonce_odr global [4 x i8] c"FvvE"
+// LLVM-DAG: @_ZTIFvvE = constant { ptr, ptr } { ptr getelementptr (i8, ptr @_ZTVN10__cxxabiv120__function_type_infoE, i64 16), ptr @_ZTSFvvE }
+// LLVM-DAG: @_ZTIM1AFvvE = constant { ptr, ptr, i32, ptr, ptr } { ptr getelementptr (i8, ptr @_ZTVN10__cxxabiv129__pointer_to_member_type_infoE, i64 16), ptr @_ZTSM1AFvvE, i32 0, ptr @_ZTIFvvE, ptr @_ZTI1A }
+// LLVM-DAG: call void @__cxa_throw(ptr %{{.*}}, ptr @_ZTIM1AFvvE, ptr null)
+
+// OGCG-DAG: @_ZTSM1AFvvE = linkonce_odr constant [8 x i8] c"M1AFvvE\00", comdat
+// OGCG-DAG: @_ZTSFvvE = linkonce_odr constant [5 x i8] c"FvvE\00", comdat
+// OGCG-DAG: @_ZTIFvvE = linkonce_odr constant { ptr, ptr } { ptr getelementptr inbounds (ptr, ptr @_ZTVN10__cxxabiv120__function_type_infoE, i64 2), ptr @_ZTSFvvE }, comdat
+// OGCG-DAG: @_ZTIM1AFvvE = linkonce_odr constant { ptr, ptr, i32, ptr, ptr } { ptr getelementptr inbounds (ptr, ptr @_ZTVN10__cxxabiv129__pointer_to_member_type_infoE, i64 2), ptr @_ZTSM1AFvvE, i32 0, ptr @_ZTIFvvE, ptr @_ZTI1A }, comdat
+// OGCG-DAG: call void @__cxa_throw(ptr %{{.*}}, ptr @_ZTIM1AFvvE, ptr null)
>From 17017871c28f0624807ecd32c2d29eebd06f7755 Mon Sep 17 00:00:00 2001
From: Perdixky <105138864+Perdixky at users.noreply.github.com>
Date: Mon, 2 Mar 2026 20:01:07 +0800
Subject: [PATCH 6/6] Update clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp
Co-authored-by: Copilot <175728472+Copilot at users.noreply.github.com>
---
clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp | 1 -
1 file changed, 1 deletion(-)
diff --git a/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp b/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp
index 2b6f6e738e8f2..f7b16675f34e7 100644
--- a/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp
@@ -1046,7 +1046,6 @@ const char *vTableClassNameForType(const CIRGenModule &cgm, const Type *ty) {
case Type::MemberPointer:
return "_ZTVN10__cxxabiv129__pointer_to_member_type_infoE";
- break;
case Type::HLSLAttributedResource:
case Type::HLSLInlineSpirv:
More information about the cfe-commits
mailing list