[clang] 5160a05 - [CIR] Emit CatchParamOp in the catch region (#171169)
via cfe-commits
cfe-commits at lists.llvm.org
Wed Dec 10 04:53:20 PST 2025
Author: Amr Hesham
Date: 2025-12-10T13:53:17+01:00
New Revision: 5160a05b0e9f4c0d1df0ac8da41c6090955777cb
URL: https://github.com/llvm/llvm-project/commit/5160a05b0e9f4c0d1df0ac8da41c6090955777cb
DIFF: https://github.com/llvm/llvm-project/commit/5160a05b0e9f4c0d1df0ac8da41c6090955777cb.diff
LOG: [CIR] Emit CatchParamOp in the catch region (#171169)
Emit structured CatchParamOp in the catch region
Issue https://github.com/llvm/llvm-project/issues/154992
Added:
Modified:
clang/include/clang/CIR/MissingFeatures.h
clang/lib/CIR/CodeGen/CIRGenCXXABI.h
clang/lib/CIR/CodeGen/CIRGenException.cpp
clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp
clang/test/CIR/CodeGen/try-catch-tmp.cpp
Removed:
################################################################################
diff --git a/clang/include/clang/CIR/MissingFeatures.h b/clang/include/clang/CIR/MissingFeatures.h
index 80f3ceaffeda0..9975ee0142d77 100644
--- a/clang/include/clang/CIR/MissingFeatures.h
+++ b/clang/include/clang/CIR/MissingFeatures.h
@@ -380,6 +380,9 @@ struct MissingFeatures {
// Future CIR attributes
static bool optInfoAttr() { return false; }
+
+ // Maybe only needed for Windows exception handling
+ static bool currentFuncletPad() { return false; }
};
} // namespace cir
diff --git a/clang/lib/CIR/CodeGen/CIRGenCXXABI.h b/clang/lib/CIR/CodeGen/CIRGenCXXABI.h
index 57b1a1f20aa17..b96d656b91e62 100644
--- a/clang/lib/CIR/CodeGen/CIRGenCXXABI.h
+++ b/clang/lib/CIR/CodeGen/CIRGenCXXABI.h
@@ -126,6 +126,9 @@ class CIRGenCXXABI {
virtual void emitBadCastCall(CIRGenFunction &cgf, mlir::Location loc) = 0;
+ virtual void emitBeginCatch(CIRGenFunction &cgf,
+ const CXXCatchStmt *catchStmt) = 0;
+
virtual mlir::Attribute getAddrOfRTTIDescriptor(mlir::Location loc,
QualType ty) = 0;
diff --git a/clang/lib/CIR/CodeGen/CIRGenException.cpp b/clang/lib/CIR/CodeGen/CIRGenException.cpp
index 375828421eb1b..06b3aec38daa4 100644
--- a/clang/lib/CIR/CodeGen/CIRGenException.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenException.cpp
@@ -419,7 +419,8 @@ void CIRGenFunction::exitCXXTryStmt(const CXXTryStmt &s, bool isFnTryBlock) {
RunCleanupsScope catchScope(*this);
// Initialize the catch variable and set up the cleanups.
- assert(!cir::MissingFeatures::catchParamOp());
+ assert(!cir::MissingFeatures::currentFuncletPad());
+ cgm.getCXXABI().emitBeginCatch(*this, catchStmt);
// Emit the PGO counter increment.
assert(!cir::MissingFeatures::incrementProfileCounter());
diff --git a/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp b/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp
index 7e145f2c57ce6..56a735e0410d7 100644
--- a/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp
@@ -81,6 +81,9 @@ class CIRGenItaniumCXXABI : public CIRGenCXXABI {
void emitRethrow(CIRGenFunction &cgf, bool isNoReturn) override;
void emitThrow(CIRGenFunction &cgf, const CXXThrowExpr *e) override;
+ void emitBeginCatch(CIRGenFunction &cgf,
+ const CXXCatchStmt *catchStmt) override;
+
bool useThunkForDtorVariant(const CXXDestructorDecl *dtor,
CXXDtorType dt) const override {
// Itanium does not emit any destructor variant as an inline thunk.
@@ -2266,3 +2269,91 @@ Address CIRGenItaniumCXXABI::initializeArrayCookie(CIRGenFunction &cgf,
CharUnits finalAlignment = baseAlignment.alignmentAtOffset(cookieSize);
return Address(finalPtr, newPtr.getElementType(), finalAlignment);
}
+
+namespace {
+/// From traditional LLVM, useful info for LLVM lowering support:
+/// A cleanup to call __cxa_end_catch. In many cases, the caught
+/// exception type lets us state definitively that the thrown exception
+/// type does not have a destructor. In particular:
+/// - Catch-alls tell us nothing, so we have to conservatively
+/// assume that the thrown exception might have a destructor.
+/// - Catches by reference behave according to their base types.
+/// - Catches of non-record types will only trigger for exceptions
+/// of non-record types, which never have destructors.
+/// - Catches of record types can trigger for arbitrary subclasses
+/// of the caught type, so we have to assume the actual thrown
+/// exception type might have a throwing destructor, even if the
+/// caught type's destructor is trivial or nothrow.
+struct CallEndCatch final : EHScopeStack::Cleanup {
+ CallEndCatch(bool mightThrow) : mightThrow(mightThrow) {}
+ bool mightThrow;
+
+ void emit(CIRGenFunction &cgf, Flags flags) override {
+ if (!mightThrow) {
+ // Traditional LLVM codegen would emit a call to __cxa_end_catch
+ // here. For CIR, just let it pass since the cleanup is going
+ // to be emitted on a later pass when lowering the catch region.
+ // CGF.EmitNounwindRuntimeCall(getEndCatchFn(CGF.CGM));
+ cir::YieldOp::create(cgf.getBuilder(), *cgf.currSrcLoc);
+ return;
+ }
+
+ // Traditional LLVM codegen would emit a call to __cxa_end_catch
+ // here. For CIR, just let it pass since the cleanup is going
+ // to be emitted on a later pass when lowering the catch region.
+ // CGF.EmitRuntimeCallOrTryCall(getEndCatchFn(CGF.CGM));
+ if (!cgf.getBuilder().getBlock()->mightHaveTerminator())
+ cir::YieldOp::create(cgf.getBuilder(), *cgf.currSrcLoc);
+ }
+};
+} // namespace
+
+static mlir::Value callBeginCatch(CIRGenFunction &cgf, mlir::Type paramTy,
+ bool endMightThrow) {
+
+ auto catchParam = cir::CatchParamOp::create(
+ cgf.getBuilder(), cgf.getBuilder().getUnknownLoc(), paramTy);
+
+ cgf.ehStack.pushCleanup<CallEndCatch>(
+ NormalAndEHCleanup,
+ endMightThrow && !cgf.cgm.getLangOpts().AssumeNothrowExceptionDtor);
+
+ return catchParam.getParam();
+}
+
+/// Begins a catch statement by initializing the catch variable and
+/// calling __cxa_begin_catch.
+void CIRGenItaniumCXXABI::emitBeginCatch(CIRGenFunction &cgf,
+ const CXXCatchStmt *catchStmt) {
+ // We have to be very careful with the ordering of cleanups here:
+ // C++ [except.throw]p4:
+ // The destruction [of the exception temporary] occurs
+ // immediately after the destruction of the object declared in
+ // the exception-declaration in the handler.
+ //
+ // So the precise ordering is:
+ // 1. Construct catch variable.
+ // 2. __cxa_begin_catch
+ // 3. Enter __cxa_end_catch cleanup
+ // 4. Enter dtor cleanup
+ //
+ // We do this by using a slightly abnormal initialization process.
+ // Delegation sequence:
+ // - ExitCXXTryStmt opens a RunCleanupsScope
+ // - EmitAutoVarAlloca creates the variable and debug info
+ // - InitCatchParam initializes the variable from the exception
+ // - CallBeginCatch calls __cxa_begin_catch
+ // - CallBeginCatch enters the __cxa_end_catch cleanup
+ // - EmitAutoVarCleanups enters the variable destructor cleanup
+ // - EmitCXXTryStmt emits the code for the catch body
+ // - EmitCXXTryStmt close the RunCleanupsScope
+
+ VarDecl *catchParam = catchStmt->getExceptionDecl();
+ if (!catchParam) {
+ callBeginCatch(cgf, cgf.getBuilder().getVoidPtrTy(),
+ /*endMightThrow=*/true);
+ return;
+ }
+
+ cgf.cgm.errorNYI("emitBeginCatch: catch with exception decl");
+}
diff --git a/clang/test/CIR/CodeGen/try-catch-tmp.cpp b/clang/test/CIR/CodeGen/try-catch-tmp.cpp
index 078447f844d9a..baf5d102a8b74 100644
--- a/clang/test/CIR/CodeGen/try-catch-tmp.cpp
+++ b/clang/test/CIR/CodeGen/try-catch-tmp.cpp
@@ -17,6 +17,7 @@ void calling_division_inside_try_block() {
// CIR: %[[CALL:.*]] = cir.call @_Z8divisionv() : () -> !s32i
// CIR: cir.yield
// CIR: } catch all {
+// CIR: %[[CATCH_PARAM:.*]] = cir.catch_param : !cir.ptr<!void>
// CIR: cir.yield
// CIR: }
// CIR: }
More information about the cfe-commits
mailing list