[clang] [CIR] Implement reference type of record ptr in initCatchParam (PR #185214)
via cfe-commits
cfe-commits at lists.llvm.org
Sat Mar 7 10:18:06 PST 2026
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clangir
@llvm/pr-subscribers-clang
Author: Amr Hesham (AmrDeveloper)
<details>
<summary>Changes</summary>
Implement the reference type of record ptr in initCatchParam
---
Full diff: https://github.com/llvm/llvm-project/pull/185214.diff
2 Files Affected:
- (modified) clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp (+74-4)
- (modified) clang/test/CIR/CodeGen/try-catch.cpp (+127)
``````````diff
diff --git a/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp b/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp
index b347c15e888a0..ef2c57c7ce327 100644
--- a/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp
@@ -586,6 +586,10 @@ class CIRGenItaniumRTTIBuilder {
/// constraints, according ti the Itanium C++ ABI, 2.9.5p5c.
void buildVMIClassTypeInfo(mlir::Location loc, const CXXRecordDecl *rd);
+ /// BuildPointerTypeInfo - Build an abi::__pointer_type_info struct, used
+ /// for pointer types.
+ void buildPointerTypeInfo(mlir::Location loc, QualType pointeeTy);
+
public:
CIRGenItaniumRTTIBuilder(const CIRGenItaniumCXXABI &abi, CIRGenModule &cgm)
: cgm(cgm), cxxABI(abi) {}
@@ -1467,7 +1471,7 @@ mlir::Attribute CIRGenItaniumRTTIBuilder::buildTypeInfo(
break;
case Type::Pointer:
- cgm.errorNYI("buildTypeInfo: Pointer");
+ buildPointerTypeInfo(loc, cast<PointerType>(ty)->getPointeeType());
break;
case Type::MemberPointer:
@@ -1597,6 +1601,55 @@ mlir::Value CIRGenItaniumCXXABI::emitTypeid(CIRGenFunction &cgf, QualType srcTy,
cgf.getPointerAlign());
}
+/// Compute the flags for a __pbase_type_info, and remove the corresponding
+/// pieces from \p Type.
+static unsigned extractPBaseFlags(ASTContext &ctx, QualType &type) {
+ unsigned flags = 0;
+
+ if (type.isConstQualified())
+ flags |= PTI_Const;
+ if (type.isVolatileQualified())
+ flags |= PTI_Volatile;
+ if (type.isRestrictQualified())
+ flags |= PTI_Restrict;
+ type = type.getUnqualifiedType();
+
+ // Itanium C++ ABI 2.9.5p7:
+ // When the abi::__pbase_type_info is for a direct or indirect pointer to an
+ // incomplete class type, the incomplete target type flag is set.
+ if (containsIncompleteClassType(type))
+ flags |= PTI_Incomplete;
+
+ if (auto *proto = type->getAs<FunctionProtoType>()) {
+ if (proto->isNothrow()) {
+ flags |= PTI_Noexcept;
+ type = ctx.getFunctionTypeWithExceptionSpec(type, EST_None);
+ }
+ }
+
+ return flags;
+}
+
+/// BuildPointerTypeInfo - Build an abi::__pointer_type_info struct,
+/// used for pointer types.
+void CIRGenItaniumRTTIBuilder::buildPointerTypeInfo(mlir::Location loc,
+ QualType pointeeTy) {
+ // Itanium C++ ABI 2.9.5p7:
+ // __flags is a flag word describing the cv-qualification and other
+ // attributes of the type pointed to
+ unsigned flags = extractPBaseFlags(cgm.getASTContext(), pointeeTy);
+ mlir::Type unsignedIntLTy =
+ cgm.getTypes().convertType(cgm.getASTContext().UnsignedIntTy);
+ fields.push_back(cir::IntAttr::get(unsignedIntLTy, flags));
+
+ // Itanium C++ ABI 2.9.5p7:
+ // __pointee is a pointer to the std::type_info derivation for the
+ // unqualified type being pointed to.
+ mlir::Attribute pointeeTypeInfo =
+ CIRGenItaniumRTTIBuilder(cxxABI, cgm).buildTypeInfo(loc, pointeeTy);
+ fields.push_back(pointeeTypeInfo);
+}
+
mlir::Attribute CIRGenItaniumCXXABI::getAddrOfRTTIDescriptor(mlir::Location loc,
QualType ty) {
return CIRGenItaniumRTTIBuilder(*this, cgm).buildTypeInfo(loc, ty);
@@ -2441,9 +2494,26 @@ static void initCatchParam(CIRGenFunction &cgf, mlir::Value ehToken,
// We have no way to tell the personality function that we're
// catching by reference, so if we're catching a pointer,
// __cxa_begin_catch will actually return that pointer by value.
- if (isa<PointerType>(caughtType)) {
- cgf.cgm.errorNYI(loc, "initCatchParam: catching a pointer");
- return;
+ if (const PointerType *pt = dyn_cast<PointerType>(caughtType)) {
+ QualType pointeeType = pt->getPointeeType();
+ // When catching by reference, generally we should just ignore
+ // this by-value pointer and use the exception object instead.
+ if (!pointeeType->isRecordType()) {
+ cgf.cgm.errorNYI(loc,
+ "initCatchParam: catching a pointer of non-record");
+ } else {
+ // Pull the pointer for the reference type off.
+ mlir::Type ptrTy = cgf.convertTypeForMem(caughtType);
+
+ // Create the temporary and write the adjusted pointer into it.
+ Address exnPtrTmp = cgf.createTempAlloca(
+ ptrTy, cgf.getPointerAlign(), cgf.getLoc(loc), "exn.byref.tmp");
+ mlir::Value casted = cgf.getBuilder().createBitcast(adjustedExn, ptrTy);
+ cgf.getBuilder().createStore(cgf.getLoc(loc), casted, exnPtrTmp);
+
+ // Bind the reference to the temporary.
+ adjustedExn = exnPtrTmp.emitRawPointer();
+ }
}
mlir::Value exnCast =
diff --git a/clang/test/CIR/CodeGen/try-catch.cpp b/clang/test/CIR/CodeGen/try-catch.cpp
index a9ad38a56715d..0d82fd70d0da8 100644
--- a/clang/test/CIR/CodeGen/try-catch.cpp
+++ b/clang/test/CIR/CodeGen/try-catch.cpp
@@ -996,3 +996,130 @@ void cleanup_inside_try_body() {
// OGCG: %[[BEGIN_CATCH:.*]] = call ptr @__cxa_begin_catch(ptr %[[EXCEPTION]])
// OGCG: call void @__cxa_end_catch()
// OGCG: br label %[[TRY_CONT]]
+
+struct Record {
+ int x;
+ int y;
+};
+
+void call_function_inside_try_catch_with_ref_ptr_of_record_exception_type() {
+ try {
+ division();
+ } catch (Record *&ref_ptr) {
+ }
+}
+
+// CIR: cir.func {{.*}} @_Z68call_function_inside_try_catch_with_ref_ptr_of_record_exception_typev(){{.*}} personality(@__gxx_personality_v0) {
+// CIR: %[[E_ADDR:.*]] = cir.alloca !cir.ptr<!cir.ptr<!rec_Record>>, !cir.ptr<!cir.ptr<!cir.ptr<!rec_Record>>>, ["ref_ptr", const]
+// CIR: %[[EXN_BYREF_TMP:.*]] = cir.alloca !cir.ptr<!rec_Record>, !cir.ptr<!cir.ptr<!rec_Record>>, ["exn.byref.tmp"]
+// CIR: cir.try {
+// CIR: %[[CALL:.*]] = cir.call @_Z8divisionv() : () -> (!s32i {llvm.noundef})
+// CIR: cir.yield
+// CIR: } catch [type #cir.global_view<@_ZTIP6Record> : !cir.ptr<!u8i>] (%[[EH_TOKEN:.*]]: !cir.eh_token {{.*}}) {
+// CIR: %[[CATCH_TOKEN:.*]], %[[EXN_PTR:.*]] = cir.begin_catch %[[EH_TOKEN]] : !cir.eh_token -> (!cir.catch_token, !cir.ptr<!cir.ptr<!rec_Record>>)
+// CIR: cir.cleanup.scope {
+// CIR: %[[EXN_PTR_REC_PTR:.*]] = cir.cast bitcast %[[EXN_PTR]] : !cir.ptr<!cir.ptr<!rec_Record>> -> !cir.ptr<!rec_Record>
+// CIR: cir.store {{.*}} %[[EXN_PTR_REC_PTR]], %[[EXN_BYREF_TMP]] : !cir.ptr<!rec_Record>, !cir.ptr<!cir.ptr<!rec_Record>>
+// CIR: cir.store {{.*}} %[[EXN_BYREF_TMP]], %[[E_ADDR]] : !cir.ptr<!cir.ptr<!rec_Record>>, !cir.ptr<!cir.ptr<!cir.ptr<!rec_Record>>>
+// CIR: cir.yield
+// CIR: } cleanup all {
+// CIR: cir.end_catch %[[CATCH_TOKEN]] : !cir.catch_token
+// CIR: cir.yield
+// CIR: }
+// CIR: cir.yield
+// CIR: } unwind (%{{.*}}: !cir.eh_token {{.*}}) {
+// CIR: cir.resume %{{.*}} : !cir.eh_token
+// CIR: }
+// CIR: }
+
+// LLVM: define {{.*}} void @_Z68call_function_inside_try_catch_with_ref_ptr_of_record_exception_typev() {{.*}} personality ptr @__gxx_personality_v0
+// LLVM: %[[E_ADDR:.*]] = alloca ptr
+// LLVM: %[[EXN_BYREF_TMP:.*]] = alloca ptr
+// LLVM: br label %[[TRY_SCOPE:.*]]
+// LLVM: [[TRY_SCOPE]]:
+// LLVM: br label %[[TRY_BEGIN:.*]]
+// LLVM: [[TRY_BEGIN]]:
+// LLVM: invoke i32 @_Z8divisionv()
+// LLVM: to label %[[INVOKE_CONT:.*]] unwind label %[[LANDING_PAD:.*]]
+// LLVM: [[INVOKE_CONT:.*]]:
+// LLVM: br label %[[TRY_CONT:.*]]
+// LLVM: [[LANDING_PAD]]:
+// LLVM: %[[LP:.*]] = landingpad { ptr, i32 }
+// LLVM: catch ptr @_ZTIP6Record
+// LLVM: %[[EXN_OBJ:.*]] = extractvalue { ptr, i32 } %[[LP]], 0
+// LLVM: %[[EH_SELECTOR_VAL:.*]] = extractvalue { ptr, i32 } %[[LP]], 1
+// LLVM: br label %[[CATCH:.*]]
+// LLVM: [[CATCH]]:
+// LLVM: %[[EXN_OBJ_PHI:.*]] = phi ptr [ %[[EXN_OBJ:.*]], %[[LANDING_PAD:.*]] ]
+// LLVM: %[[EH_SELECTOR_PHI:.*]] = phi i32 [ %[[EH_SELECTOR_VAL:.*]], %[[LANDING_PAD:.*]] ]
+// LLVM: br label %[[DISPATCH:.*]]
+// LLVM: [[DISPATCH]]:
+// LLVM: %[[EXN_OBJ_PHI1:.*]] = phi ptr [ %[[EXN_OBJ_PHI:.*]], %[[CATCH:.*]] ]
+// LLVM: %[[EH_SELECTOR_PHI1:.*]] = phi i32 [ %[[EH_SELECTOR_PHI:.*]], %[[CATCH:.*]] ]
+// LLVM: %[[EH_TYPE_ID:.*]] = call i32 @llvm.eh.typeid.for.p0(ptr @_ZTIP6Record)
+// LLVM: %[[TYPE_ID_EQ:.*]] = icmp eq i32 %[[EH_SELECTOR_PHI1]], %[[EH_TYPE_ID]]
+// LLVM: br i1 %[[TYPE_ID_EQ]], label %[[BEGIN_CATCH:.*]], label %[[RESUME:.*]]
+// LLVM: [[BEGIN_CATCH]]:
+// LLVM: %[[EXN_OBJ_PHI2:.*]] = phi ptr [ %[[EXN_OBJ_PHI1:.*]], %[[DISPATCH:.*]] ]
+// LLVM: %[[EH_SELECTOR_PHI2:.*]] = phi i32 [ %[[EH_SELECTOR_PHI1:.*]], %[[DISPATCH:.*]] ]
+// LLVM: %[[TOKEN:.*]] = call ptr @__cxa_begin_catch(ptr %[[EXN_OBJ_PHI2]])
+// LLVM: br label %[[CATCH_BODY:.*]]
+// LLVM: [[CATCH_BODY]]:
+// LLVM: store ptr %[[TOKEN]], ptr %[[EXN_BYREF_TMP]], align 8
+// LLVM: store ptr %[[EXN_BYREF_TMP]], ptr %[[E_ADDR]], align 8
+// LLVM: br label %[[END_CATCH:.*]]
+// LLVM: [[END_CATCH]]:
+// LLVM: call void @__cxa_end_catch()
+// LLVM: br label %[[END_DISPATCH:.*]]
+// LLVM: [[END_DISPATCH]]:
+// LLVM: br label %[[END_TRY:.*]]
+// LLVM: [[END_TRY]]:
+// LLVM: br label %[[TRY_CONT:.*]]
+// LLVM: [[RESUME]]:
+// LLVM: %[[EXN_OBJ_PHI3:.*]] = phi ptr [ %[[EXN_OBJ_PHI1:.*]], %[[DISPATCH:.*]] ]
+// LLVM: %[[EH_SELECTOR_PHI3:.*]] = phi i32 [ %[[EH_SELECTOR_PHI1:.*]], %[[DISPATCH:.*]] ]
+// LLVM: %[[TMP_EXCEPTION_INFO:.*]] = insertvalue { ptr, i32 } poison, ptr %[[EXN_OBJ_PHI3]], 0
+// LLVM: %[[EXCEPTION_INFO:.*]] = insertvalue { ptr, i32 } %[[TMP_EXCEPTION_INFO]], i32 %[[EH_SELECTOR_PHI3]], 1
+// LLVM: resume { ptr, i32 } %[[EXCEPTION_INFO]]
+// LLVM: [[TRY_CONT]]:
+// LLVM: br label %[[DONE:.*]]
+// LLVM: [[DONE]]:
+// LLVM: ret void
+
+// OGCG: define {{.*}} void @_Z68call_function_inside_try_catch_with_ref_ptr_of_record_exception_typev() {{.*}} personality ptr @__gxx_personality_v0
+// OGCG: %[[EXCEPTION_ADDR:.*]] = alloca ptr, align 8
+// OGCG: %[[EH_TYPE_ID_ADDR:.*]] = alloca i32, align 4
+// OGCG: %[[E_ADDR:.*]] = alloca ptr, align 8
+// OGCG: %[[EXN_BYREF_TMP:.*]] = alloca ptr, align 8
+// OGCG: %[[CALL:.*]] = invoke noundef i32 @_Z8divisionv()
+// OGCG: to label %[[INVOKE_NORMAL:.*]] unwind label %[[INVOKE_UNWIND:.*]]
+// OGCG: [[INVOKE_NORMAL]]:
+// OGCG: br label %[[TRY_CONT:.*]]
+// OGCG: [[INVOKE_UNWIND]]:
+// OGCG: %[[LANDING_PAD:.*]] = landingpad { ptr, i32 }
+// OGCG: catch ptr @_ZTIP6Record
+// OGCG: %[[EXCEPTION:.*]] = extractvalue { ptr, i32 } %[[LANDING_PAD]], 0
+// OGCG: store ptr %[[EXCEPTION]], ptr %[[EXCEPTION_ADDR]], align 8
+// OGCG: %[[EH_TYPE_ID:.*]] = extractvalue { ptr, i32 } %[[LANDING_PAD]], 1
+// OGCG: store i32 %[[EH_TYPE_ID]], ptr %[[EH_TYPE_ID_ADDR]], align 4
+// OGCG: br label %[[CATCH_DISPATCH:.*]]
+// OGCG: [[CATCH_DISPATCH]]:
+// OGCG: %[[TMP_EH_TYPE_ID:.*]] = load i32, ptr %ehselector.slot, align 4
+// OGCG: %[[EH_TYPE_ID:.*]] = call i32 @llvm.eh.typeid.for.p0(ptr @_ZTIP6Record)
+// OGCG: %[[TYPE_ID_EQ:.*]] = icmp eq i32 %[[TMP_EH_TYPE_ID]], %[[EH_TYPE_ID]]
+// OGCG: br i1 %[[TYPE_ID_EQ]], label %[[CATCH_EXCEPTION:.*]], label %[[EH_RESUME:.*]]
+// OGCG: [[CATCH_EXCEPTION]]:
+// OGCG: %[[TMP_EXCEPTION:.*]] = load ptr, ptr %[[EXCEPTION_ADDR]], align 8
+// OGCG: %[[BEGIN_CATCH:.*]] = call ptr @__cxa_begin_catch(ptr %[[TMP_EXCEPTION]])
+// OGCG: store ptr %[[BEGIN_CATCH]], ptr %[[EXN_BYREF_TMP]], align 8
+// OGCG: store ptr %[[EXN_BYREF_TMP]], ptr %[[E_ADDR]], align 8
+// OGCG: call void @__cxa_end_catch()
+// OGCG: br label %[[TRY_CONT]]
+// OGCG: [[TRY_CONT]]:
+// OGCG: ret void
+// OGCG: [[EH_RESUME]]:
+// OGCG: %[[TMP_EXCEPTION:.*]] = load ptr, ptr %[[EXCEPTION_ADDR]], align 8
+// OGCG: %[[TMP_EH_TYPE_ID:.*]] = load i32, ptr %[[EH_TYPE_ID_ADDR]], align 4
+// OGCG: %[[TMP_EXCEPTION_INFO:.*]] = insertvalue { ptr, i32 } poison, ptr %[[TMP_EXCEPTION]], 0
+// OGCG: %[[EXCEPTION_INFO:.*]] = insertvalue { ptr, i32 } %[[TMP_EXCEPTION_INFO]], i32 %[[TMP_EH_TYPE_ID]], 1
+// OGCG: resume { ptr, i32 } %[[EXCEPTION_INFO]]
``````````
</details>
https://github.com/llvm/llvm-project/pull/185214
More information about the cfe-commits
mailing list