https://github.com/AmrDeveloper updated 
https://github.com/llvm/llvm-project/pull/171042

>From 41c0ab179fe77c973d711f89c26ce65eb5c23cb2 Mon Sep 17 00:00:00 2001
From: Amr Hesham <[email protected]>
Date: Sun, 30 Nov 2025 17:12:04 +0100
Subject: [PATCH 1/8] [CIR] Support Try catch with handler for specific type

---
 clang/include/clang/CIR/Dialect/IR/CIROps.td  |   5 +-
 clang/lib/CIR/CodeGen/CIRGenCXXABI.h          |   3 +
 clang/lib/CIR/CodeGen/CIRGenCall.cpp          |   2 +
 clang/lib/CIR/CodeGen/CIRGenException.cpp     | 149 ++++++++++++++++--
 clang/lib/CIR/CodeGen/CIRGenFunction.h        |   2 +
 clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp |   7 +
 clang/test/CIR/CodeGen/try-catch-tmp.cpp      |  56 ++++++-
 7 files changed, 206 insertions(+), 18 deletions(-)

diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td 
b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index 240459428b22c..dc7cc56cdeb14 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -837,7 +837,7 @@ def CIR_ConditionOp : CIR_Op<"condition", [
 
//===----------------------------------------------------------------------===//
 
 defvar CIR_YieldableScopes = [
-  "ArrayCtor", "ArrayDtor", "AwaitOp", "CaseOp", "DoWhileOp", "ForOp",
+  "ArrayCtor", "ArrayDtor", "AwaitOp", "CallOp", "CaseOp", "DoWhileOp", 
"ForOp",
   "GlobalOp", "IfOp", "ScopeOp", "SwitchOp", "TernaryOp", "WhileOp", "TryOp"
 ];
 
@@ -3031,6 +3031,7 @@ def CIR_CallOp : CIR_CallOpBase<"call", 
[NoRegionArguments]> {
 
   let results = (outs Optional<CIR_AnyType>:$result);
   let arguments = commonArgs;
+  let regions = (region AnyRegion:$cleanup);
 
   let builders = [
     OpBuilder<(ins "mlir::SymbolRefAttr":$callee, "mlir::Type":$resType,
@@ -3040,6 +3041,8 @@ def CIR_CallOp : CIR_CallOpBase<"call", 
[NoRegionArguments]> {
         $_state.addAttribute("callee", callee);
       if (resType && !isa<VoidType>(resType))
         $_state.addTypes(resType);
+      // Create region placeholder for potential cleanups.
+      $_state.addRegion();
     }]>
   ];
 }
diff --git a/clang/lib/CIR/CodeGen/CIRGenCXXABI.h 
b/clang/lib/CIR/CodeGen/CIRGenCXXABI.h
index b96d656b91e62..1d5fce3036bf4 100644
--- a/clang/lib/CIR/CodeGen/CIRGenCXXABI.h
+++ b/clang/lib/CIR/CodeGen/CIRGenCXXABI.h
@@ -161,6 +161,9 @@ class CIRGenCXXABI {
   /// Loads the incoming C++ this pointer as it was passed by the caller.
   mlir::Value loadIncomingCXXThis(CIRGenFunction &cgf);
 
+  virtual CatchTypeInfo
+  getAddrOfCXXCatchHandlerType(mlir::Location loc, QualType ty,
+                               QualType catchHandlerType) = 0;
   virtual CatchTypeInfo getCatchAllTypeInfo();
 
   /// Get the implicit (second) parameter that comes after the "this" pointer,
diff --git a/clang/lib/CIR/CodeGen/CIRGenCall.cpp 
b/clang/lib/CIR/CodeGen/CIRGenCall.cpp
index 17f0c6dbab35c..3ef443962aaa7 100644
--- a/clang/lib/CIR/CodeGen/CIRGenCall.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenCall.cpp
@@ -503,7 +503,9 @@ emitCallLikeOp(CIRGenFunction &cgf, mlir::Location callLoc,
     callOpWithExceptions =
         builder.createCallOp(callLoc, directFuncOp, cirCallArgs);
 
+    cgf.callWithExceptionCtx = callOpWithExceptions;
     cgf.populateCatchHandlersIfRequired(tryOp);
+    cgf.callWithExceptionCtx = nullptr;
     return callOpWithExceptions;
   }
 
diff --git a/clang/lib/CIR/CodeGen/CIRGenException.cpp 
b/clang/lib/CIR/CodeGen/CIRGenException.cpp
index 70812452ed999..a4fde69e8f59e 100644
--- a/clang/lib/CIR/CodeGen/CIRGenException.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenException.cpp
@@ -244,6 +244,30 @@ void CIRGenFunction::emitAnyExprToExn(const Expr *e, 
Address addr) {
   assert(!cir::MissingFeatures::ehCleanupScope());
 }
 
+void CIRGenFunction::populateUnwindResumeBlock(bool isCleanup,
+                                               cir::TryOp tryOp) {
+  const EHPersonality &personality = EHPersonality::get(*this);
+  // This can always be a call because we necessarily didn't find
+  // anything on the EH stack which needs our help.
+  const char *rethrowName = personality.catchallRethrowFn;
+  if (rethrowName != nullptr && !isCleanup) {
+    cgm.errorNYI("populateUnwindResumeBlock CatchallRethrowFn");
+    return;
+  }
+
+  unsigned regionsNum = tryOp->getNumRegions();
+  mlir::Region *unwindRegion = &tryOp->getRegion(regionsNum - 1);
+  mlir::Block *unwindResumeBlock = &unwindRegion->front();
+  if (!unwindResumeBlock->empty())
+    return;
+
+  // Emit cir.resume into the unwind region last block
+  cir::CIRBaseBuilderTy::InsertPoint ip = builder.saveInsertionPoint();
+  builder.setInsertionPointToStart(unwindResumeBlock);
+  cir::ResumeOp::create(builder, tryOp.getLoc());
+  builder.restoreInsertionPoint(ip);
+}
+
 mlir::LogicalResult CIRGenFunction::emitCXXTryStmt(const CXXTryStmt &s) {
   if (s.getTryBlock()->body_empty())
     return mlir::LogicalResult::success();
@@ -344,21 +368,88 @@ CIRGenFunction::emitCXXTryStmtUnderScope(const CXXTryStmt 
&s) {
   return mlir::success();
 }
 
+/// Emit the structure of the dispatch block for the given catch scope.
+/// It is an invariant that the dispatch block already exists.
+static void emitCatchDispatchBlock(CIRGenFunction &cgf,
+                                   EHCatchScope &catchScope, cir::TryOp tryOp) 
{
+  if (EHPersonality::get(cgf).isWasmPersonality()) {
+    cgf.cgm.errorNYI("emitCatchDispatchBlock: WasmPersonality");
+    return;
+  }
+
+  if (EHPersonality::get(cgf).usesFuncletPads()) {
+    cgf.cgm.errorNYI("emitCatchDispatchBlock: usesFuncletPads");
+    return;
+  }
+
+  unsigned int numHandlers = catchScope.getNumHandlers();
+  if (numHandlers == 1 && catchScope.getHandler(0).isCatchAll()) {
+    return;
+  }
+
+  // In traditional LLVM codegen, the right handler is selected (with
+  // calls to eh_typeid_for) and the selector value is loaded. After that,
+  // blocks get connected for later codegen. In CIR, these are all
+  // implicit behaviors of cir.catch - not a lot of work to do.
+  //
+  // Test against each of the exception types we claim to catch.
+  for (unsigned i = 0;; ++i) {
+    assert(i < numHandlers && "ran off end of handlers!");
+    const EHCatchScope::Handler &handler = catchScope.getHandler(i);
+
+    [[maybe_unused]] mlir::TypedAttr typeValue = handler.type.rtti;
+    assert(handler.Type.Flags == 0 && "catch handler flags not supported");
+    assert(typeValue && "fell into catch-all case!");
+
+    // Check for address space mismatch
+    assert(!cir::MissingFeatures::addressSpace());
+
+    // If this is the last handler, we're at the end, and the next
+    // block is the block for the enclosing EH scope. Make sure to call
+    // populateEHCatchRegions for caching it.
+    if (i + 1 == numHandlers) {
+      cgf.populateEHCatchRegions(catchScope.getEnclosingEHScope(), tryOp);
+      return;
+    }
+
+    // If the next handler is a catch-all, we're at the end, and the
+    // next block is that handler.
+    if (catchScope.getHandler(i + 1).isCatchAll())
+      return;
+  }
+}
+
 void CIRGenFunction::enterCXXTryStmt(const CXXTryStmt &s, cir::TryOp tryOp,
                                      bool isFnTryBlock) {
   unsigned numHandlers = s.getNumHandlers();
   EHCatchScope *catchScope = ehStack.pushCatch(numHandlers);
   for (unsigned i = 0; i != numHandlers; ++i) {
     const CXXCatchStmt *catchStmt = s.getHandler(i);
+    mlir::Region *handler = &tryOp.getHandlerRegions()[i];
     if (catchStmt->getExceptionDecl()) {
-      cgm.errorNYI("enterCXXTryStmt: CatchStmt with ExceptionDecl");
-      return;
-    }
+      // FIXME: Dropping the reference type on the type into makes it
+      // impossible to correctly implement catch-by-reference
+      // semantics for pointers.  Unfortunately, this is what all
+      // existing compilers do, and it's not clear that the standard
+      // personality routine is capable of doing this right.  See C++ DR 388:
+      //   http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#388
+      Qualifiers caughtTypeQuals;
+      QualType caughtType = cgm.getASTContext().getUnqualifiedArrayType(
+          catchStmt->getCaughtType().getNonReferenceType(), caughtTypeQuals);
+      if (caughtType->isObjCObjectPointerType()) {
+        cgm.errorNYI("enterCXXTryStmt: caughtType ObjCObjectPointerType");
+        return;
+      }
 
-    // No exception decl indicates '...', a catch-all.
-    mlir::Region *handler = &tryOp.getHandlerRegions()[i];
-    catchScope->setHandler(i, cgm.getCXXABI().getCatchAllTypeInfo(), handler,
-                           s.getHandler(i));
+      CatchTypeInfo typeInfo = cgm.getCXXABI().getAddrOfCXXCatchHandlerType(
+          getLoc(catchStmt->getSourceRange()), caughtType,
+          catchStmt->getCaughtType());
+      catchScope->setHandler(i, typeInfo, handler, catchStmt);
+    } else {
+      // No exception decl indicates '...', a catch-all.
+      catchScope->setHandler(i, cgm.getCXXABI().getCatchAllTypeInfo(), handler,
+                             s.getHandler(i));
+    }
 
     // Under async exceptions, catch(...) needs to catch HW exception too
     // Mark scope with SehTryBegin as a SEH __try scope
@@ -397,6 +488,9 @@ void CIRGenFunction::exitCXXTryStmt(const CXXTryStmt &s, 
bool isFnTryBlock) {
     return;
   }
 
+  // Emit the structure of the EH dispatch for this catch.
+  emitCatchDispatchBlock(*this, catchScope, tryOp);
+
   // Copy the handler blocks off before we pop the EH stack.  Emitting
   // the handlers might scribble on this memory.
   SmallVector<EHCatchScope::Handler> handlers(catchScope.begin(),
@@ -499,9 +593,11 @@ void CIRGenFunction::populateCatchHandlers(cir::TryOp 
tryOp) {
   // with function local static initializers).
   mlir::ArrayAttr handlerTypesAttr = tryOp.getHandlerTypesAttr();
   if (!handlerTypesAttr || handlerTypesAttr.empty()) {
+    // Accumulate all the handlers in scope.
     // Accumulate all the handlers in scope.
     bool hasCatchAll = false;
-    llvm::SmallVector<mlir::Attribute, 4> handlerAttrs;
+    llvm::SmallPtrSet<mlir::Attribute, 4> catchTypes;
+    llvm::SmallVector<mlir::Attribute> handlerAttrs;
     for (EHScopeStack::iterator i = ehStack.begin(), e = ehStack.end(); i != e;
          ++i) {
       switch (i->getKind()) {
@@ -534,8 +630,10 @@ void CIRGenFunction::populateCatchHandlers(cir::TryOp 
tryOp) {
           break;
         }
 
-        cgm.errorNYI("emitLandingPad: non catch-all");
-        return;
+        // Check whether we already have a handler for this type.
+        // If not, keep track to later add to catch op.
+        if (catchTypes.insert(handler.type.rtti).second)
+          handlerAttrs.push_back(handler.type.rtti);
       }
 
       if (hasCatchAll)
@@ -544,9 +642,12 @@ void CIRGenFunction::populateCatchHandlers(cir::TryOp 
tryOp) {
 
     if (hasCatchAll) {
       handlerAttrs.push_back(cir::CatchAllAttr::get(&getMLIRContext()));
-    } else {
-      cgm.errorNYI("emitLandingPad: non catch-all");
-      return;
+    }
+
+    // If there's no catch_all, attach the unwind region. This needs to be the
+    // last region in the TryOp catch list.
+    if (!hasCatchAll) {
+      handlerAttrs.push_back(cir::UnwindAttr::get(&getMLIRContext()));
     }
 
     // Add final array of clauses into TryOp.
@@ -571,6 +672,13 @@ void 
CIRGenFunction::populateEHCatchRegions(EHScopeStack::stable_iterator scope,
     return;
   }
 
+  // The dispatch block for the end of the scope chain is a block that
+  // just resumes unwinding.
+  if (scope == ehStack.stable_end()) {
+    populateUnwindResumeBlock(/*isCleanup=*/true, tryOp);
+    return;
+  }
+
   // Otherwise, we should look at the actual scope.
   EHScope &ehScope = *ehStack.find(scope);
   bool mayThrow = ehScope.mayThrow();
@@ -588,16 +696,25 @@ void 
CIRGenFunction::populateEHCatchRegions(EHScopeStack::stable_iterator scope,
   if (!mayThrow) {
     switch (ehScope.getKind()) {
     case EHScope::Catch: {
+      mayThrow = true;
+
       // LLVM does some optimization with branches here, CIR just keep track of
       // the corresponding calls.
       EHCatchScope &catchScope = cast<EHCatchScope>(ehScope);
       if (catchScope.getNumHandlers() == 1 &&
           catchScope.getHandler(0).isCatchAll()) {
-        mayThrow = true;
         break;
       }
-      cgm.errorNYI("getEHDispatchBlock: mayThrow non-catch all");
-      return;
+
+      assert(callWithExceptionCtx && "expected call information");
+      {
+        mlir::OpBuilder::InsertionGuard guard(builder);
+        assert(callWithExceptionCtx.getCleanup().empty() &&
+               "one per call: expected empty region at this point");
+        builder.createBlock(&callWithExceptionCtx.getCleanup());
+        builder.createYield(callWithExceptionCtx.getLoc());
+      }
+      break;
     }
     case EHScope::Cleanup: {
       cgm.errorNYI("getEHDispatchBlock: mayThrow & cleanup");
diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h 
b/clang/lib/CIR/CodeGen/CIRGenFunction.h
index cfe9b37c2c725..a1c0ceed9db1b 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.h
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h
@@ -974,6 +974,8 @@ class CIRGenFunction : public CIRGenTypeCache {
     return false;
   }
 
+  cir::CallOp callWithExceptionCtx = nullptr;
+  void populateUnwindResumeBlock(bool isCleanup, cir::TryOp tryOp);
   void populateEHCatchRegions(EHScopeStack::stable_iterator scope,
                               cir::TryOp tryOp);
 
diff --git a/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp 
b/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp
index 56a735e0410d7..cb1f5728b5d14 100644
--- a/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp
@@ -121,6 +121,13 @@ class CIRGenItaniumCXXABI : public CIRGenCXXABI {
 
   mlir::Attribute getAddrOfRTTIDescriptor(mlir::Location loc,
                                           QualType ty) override;
+  CatchTypeInfo
+  getAddrOfCXXCatchHandlerType(mlir::Location loc, QualType ty,
+                               QualType catchHandlerType) override {
+    auto rtti = dyn_cast<cir::GlobalViewAttr>(getAddrOfRTTIDescriptor(loc, 
ty));
+    assert(rtti && "expected GlobalViewAttr");
+    return CatchTypeInfo{rtti, 0};
+  }
 
   bool doStructorsInitializeVPtrs(const CXXRecordDecl *vtableClass) override {
     return true;
diff --git a/clang/test/CIR/CodeGen/try-catch-tmp.cpp 
b/clang/test/CIR/CodeGen/try-catch-tmp.cpp
index baf5d102a8b74..e6188e52603ff 100644
--- a/clang/test/CIR/CodeGen/try-catch-tmp.cpp
+++ b/clang/test/CIR/CodeGen/try-catch-tmp.cpp
@@ -5,7 +5,7 @@
 
 int division();
 
-void calling_division_inside_try_block() {
+void call_function_inside_try_catch_all() {
   try {
     division();
   } catch (...) {
@@ -43,3 +43,57 @@ void calling_division_inside_try_block() {
 // OGCG:   br label %[[TRY_CONT]]
 // OGCG: [[TRY_CONT]]:
 // OGCG:   ret void
+
+void call_function_inside_try_catch_with_exception_type() {
+  try {
+    division();
+  } catch (int e) {
+  }
+}
+
+// CIR: cir.scope {
+// CIR:   cir.try {
+// CIR:     %[[CALL:.*]] = cir.call @_Z8divisionv() : () -> !s32i
+// CIR:     cir.yield
+// CIR:   } catch [type #cir.global_view<@_ZTIi> : !cir.ptr<!u8i>] {
+// CIR:     cir.yield
+// CIR:   } unwind {
+// CIR:     cir.resume
+// CIR:   }
+// CIR: }
+
+// OGCG:   %[[EXCEPTION_ADDR:.*]] = alloca ptr, align 8
+// OGCG:   %[[EH_TYPE_ID_ADDR:.*]] = alloca i32, align 4
+// OGCG:   %[[E_ADDR:.*]] = alloca i32, align 4
+// 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 @_ZTIi
+// 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 %[[EH_TYPE_ID_ADDR]], align 4
+// OGCG:   %[[EH_TYPE_ID:.*]] = call i32 @llvm.eh.typeid.for.p0(ptr @_ZTIi)
+// 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:   %[[TMP_BEGIN_CATCH:.*]] = load i32, ptr %[[BEGIN_CATCH]], align 4
+// OGCG:   store i32 %[[TMP_BEGIN_CATCH]], ptr %[[E_ADDR]], align 4
+// OGCG:   call void @__cxa_end_catch()
+// OGCG:   br label %[[TRY_NORMA:.*]]
+// OGCG: [[TRY_NORMA]]:
+// 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]]

>From c3a39275302bb918ba3007c9808453d3ef5d135a Mon Sep 17 00:00:00 2001
From: Amr Hesham <[email protected]>
Date: Sun, 7 Dec 2025 18:26:42 +0100
Subject: [PATCH 2/8] Fix compiling assert

---
 clang/lib/CIR/CodeGen/CIRGenException.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang/lib/CIR/CodeGen/CIRGenException.cpp 
b/clang/lib/CIR/CodeGen/CIRGenException.cpp
index a4fde69e8f59e..24c417a879432 100644
--- a/clang/lib/CIR/CodeGen/CIRGenException.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenException.cpp
@@ -398,7 +398,7 @@ static void emitCatchDispatchBlock(CIRGenFunction &cgf,
     const EHCatchScope::Handler &handler = catchScope.getHandler(i);
 
     [[maybe_unused]] mlir::TypedAttr typeValue = handler.type.rtti;
-    assert(handler.Type.Flags == 0 && "catch handler flags not supported");
+    assert(handler.type.flags == 0 && "catch handler flags not supported");
     assert(typeValue && "fell into catch-all case!");
 
     // Check for address space mismatch

>From ddd724eea1ee571d2f49c7591e3f04f808aba611 Mon Sep 17 00:00:00 2001
From: Amr Hesham <[email protected]>
Date: Sun, 7 Dec 2025 19:35:47 +0100
Subject: [PATCH 3/8] Support cleanup region in the parser/printer

---
 clang/include/clang/CIR/Dialect/IR/CIROps.td |  2 ++
 clang/lib/CIR/Dialect/IR/CIRDialect.cpp      | 18 +++++++++++
 clang/test/CIR/IR/try-catch.cir              | 34 ++++++++++++++++++++
 3 files changed, 54 insertions(+)

diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td 
b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index dc7cc56cdeb14..d5a57db841d6c 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -3033,6 +3033,8 @@ def CIR_CallOp : CIR_CallOpBase<"call", 
[NoRegionArguments]> {
   let arguments = commonArgs;
   let regions = (region AnyRegion:$cleanup);
 
+  let skipDefaultBuilders = 1;
+
   let builders = [
     OpBuilder<(ins "mlir::SymbolRefAttr":$callee, "mlir::Type":$resType,
                    "mlir::ValueRange":$operands), [{
diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp 
b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
index 95fc3afffb156..d4464d77c972a 100644
--- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
@@ -847,6 +847,16 @@ static mlir::ParseResult parseCallCommon(mlir::OpAsmParser 
&parser,
   if (parser.resolveOperands(ops, opsFnTy.getInputs(), opsLoc, 
result.operands))
     return mlir::failure();
 
+  // If exception is present and there are cleanups, this should be latest 
thing
+  // present (after all attributes, etc).
+  if (!hasDestinationBlocks) {
+    mlir::Region *cleanupRegion = result.addRegion();
+    if (parser.parseOptionalKeyword("cleanup").succeeded()) {
+      if (parser.parseRegion(*cleanupRegion))
+        return failure();
+    }
+  }
+
   return mlir::success();
 }
 
@@ -899,6 +909,14 @@ static void printCallCommon(mlir::Operation *op,
   printer << " : ";
   printer.printFunctionalType(op->getOperands().getTypes(),
                               op->getResultTypes());
+
+  // If exception is present and there are cleanups, this should be latest 
thing
+  // present (after all attributes, etc).
+  auto call = dyn_cast<cir::CallOp>(op);
+  if (call && !call.getCleanup().empty()) {
+    printer << " cleanup ";
+    printer.printRegion(call.getCleanup());
+  }
 }
 
 mlir::ParseResult cir::CallOp::parse(mlir::OpAsmParser &parser,
diff --git a/clang/test/CIR/IR/try-catch.cir b/clang/test/CIR/IR/try-catch.cir
index 8ffce067ba043..94368c46c6ba5 100644
--- a/clang/test/CIR/IR/try-catch.cir
+++ b/clang/test/CIR/IR/try-catch.cir
@@ -1,6 +1,7 @@
 // RUN: cir-opt %s --verify-roundtrip | FileCheck %s
 
 !u8i = !cir.int<u, 8>
+!s32i = !cir.int<s, 32>
 
 module {
 
@@ -103,4 +104,37 @@ cir.func 
@empty_try_block_with_catch_unwind_contains_resume() {
 // CHECK:   cir.return
 // CHECK: }
 
+
+cir.func private @function_with_cleanup() -> !s32i
+
+// CHECK: cir.func private @function_with_cleanup() -> !s32i
+
+cir.func @try_catch_with_call_that_has_cleanup() {
+  cir.scope {
+    cir.try {
+      cir.call @function_with_cleanup() : () -> !s32i cleanup {
+        cir.yield
+      }
+      cir.yield
+    } unwind {
+      cir.resume
+    }
+  }
+  cir.return
+}
+
+// CHECK: cir.func @try_catch_with_call_that_has_cleanup() {
+// CHECK:   cir.scope {
+// CHECK:     cir.try {
+// CHECK:       cir.call @function_with_cleanup() : () -> !s32i cleanup {
+// CHECK:         cir.yield
+// CHECK:       }
+// CHECK:       cir.yield
+// CHECK:     } unwind {
+// CHECK:       cir.resume
+// CHECK:     }
+// CHECK:   }
+// CHECK:   cir.return
+// CHECK: }
+
 }

>From 9d384383e6b42da6fdd13b26d1d8f61ad1d19739 Mon Sep 17 00:00:00 2001
From: Amr Hesham <[email protected]>
Date: Wed, 10 Dec 2025 18:06:14 +0100
Subject: [PATCH 4/8] Add support for CatchParamOp

---
 clang/include/clang/CIR/MissingFeatures.h     |  1 -
 clang/lib/CIR/CodeGen/CIRGenException.cpp     |  3 -
 clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp | 76 ++++++++++++++++++-
 clang/test/CIR/CodeGen/try-catch-tmp.cpp      |  1 +
 4 files changed, 75 insertions(+), 6 deletions(-)

diff --git a/clang/include/clang/CIR/MissingFeatures.h 
b/clang/include/clang/CIR/MissingFeatures.h
index ad8c7ca7336e6..75f3599875372 100644
--- a/clang/include/clang/CIR/MissingFeatures.h
+++ b/clang/include/clang/CIR/MissingFeatures.h
@@ -376,7 +376,6 @@ struct MissingFeatures {
   static bool tryOp() { return false; }
   static bool vecTernaryOp() { return false; }
   static bool zextOp() { return false; }
-  static bool catchParamOp() { return false; }
 
   // Future CIR attributes
   static bool optInfoAttr() { return false; }
diff --git a/clang/lib/CIR/CodeGen/CIRGenException.cpp 
b/clang/lib/CIR/CodeGen/CIRGenException.cpp
index 24c417a879432..05f2be6d077eb 100644
--- a/clang/lib/CIR/CodeGen/CIRGenException.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenException.cpp
@@ -536,9 +536,6 @@ void CIRGenFunction::exitCXXTryStmt(const CXXTryStmt &s, 
bool isFnTryBlock) {
         emitStmt(catchStmt->getHandlerBlock(), /*useCurrentScope=*/true);
     assert(emitResult.succeeded() && "failed to emit catch handler block");
 
-    assert(!cir::MissingFeatures::catchParamOp());
-    cir::YieldOp::create(builder, tryOp->getLoc());
-
     // [except.handle]p11:
     //   The currently handled exception is rethrown if control
     //   reaches the end of a handler of the function-try-block of a
diff --git a/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp 
b/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp
index cb1f5728b5d14..7de2f32a28b0c 100644
--- a/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp
@@ -2317,7 +2317,6 @@ struct CallEndCatch final : EHScopeStack::Cleanup {
 
 static mlir::Value callBeginCatch(CIRGenFunction &cgf, mlir::Type paramTy,
                                   bool endMightThrow) {
-
   auto catchParam = cir::CatchParamOp::create(
       cgf.getBuilder(), cgf.getBuilder().getUnknownLoc(), paramTy);
 
@@ -2328,6 +2327,56 @@ static mlir::Value callBeginCatch(CIRGenFunction &cgf, 
mlir::Type paramTy,
   return catchParam.getParam();
 }
 
+/// A "special initializer" callback for initializing a catch
+/// parameter during catch initialization.
+static void initCatchParam(CIRGenFunction &cgf, const VarDecl &catchParam,
+                           Address paramAddr, SourceLocation loc) {
+  CanQualType catchType =
+      cgf.cgm.getASTContext().getCanonicalType(catchParam.getType());
+  // If we're catching by reference, we can just cast the object
+  // pointer to the appropriate pointer.
+  if (isa<ReferenceType>(catchType)) {
+    cgf.cgm.errorNYI(loc, "initCatchParam: ReferenceType");
+    return;
+  }
+
+  // Scalars and complexes.
+  cir::TypeEvaluationKind tek = cgf.getEvaluationKind(catchType);
+  if (tek != cir::TEK_Aggregate) {
+    // Notes for LLVM lowering:
+    // If the catch type is a pointer type, __cxa_begin_catch returns
+    // the pointer by value.
+    if (catchType->hasPointerRepresentation()) {
+      cgf.cgm.errorNYI(loc, "initCatchParam: hasPointerRepresentation");
+      return;
+    }
+
+    mlir::Type cirCatchTy = cgf.convertTypeForMem(catchType);
+    mlir::Value catchParam =
+        callBeginCatch(cgf, cgf.getBuilder().getPointerTo(cirCatchTy), false);
+    LValue srcLV = cgf.makeNaturalAlignAddrLValue(catchParam, catchType);
+    LValue destLV = cgf.makeAddrLValue(paramAddr, catchType);
+    switch (tek) {
+    case cir::TEK_Complex: {
+      cgf.cgm.errorNYI(loc, "initCatchParam: cir::TEK_Complex");
+      return;
+    }
+    case cir::TEK_Scalar: {
+      auto exnLoad = cgf.emitLoadOfScalar(srcLV, loc);
+      cgf.emitStoreOfScalar(exnLoad, destLV, /*isInit=*/true);
+      return;
+    }
+    case cir::TEK_Aggregate:
+      llvm_unreachable("evaluation kind filtered out!");
+    }
+
+    // Otherwise, it returns a pointer into the exception object.
+    llvm_unreachable("bad evaluation kind");
+  }
+
+  cgf.cgm.errorNYI(loc, "initCatchParam: cir::TEK_Aggregate");
+}
+
 /// Begins a catch statement by initializing the catch variable and
 /// calling __cxa_begin_catch.
 void CIRGenItaniumCXXABI::emitBeginCatch(CIRGenFunction &cgf,
@@ -2362,5 +2411,28 @@ void CIRGenItaniumCXXABI::emitBeginCatch(CIRGenFunction 
&cgf,
     return;
   }
 
-  cgf.cgm.errorNYI("emitBeginCatch: catch with exception decl");
+  auto getCatchParamAllocaIP = [&]() {
+    auto currIns = cgf.getBuilder().saveInsertionPoint();
+    mlir::Operation *currParent = currIns.getBlock()->getParentOp();
+
+    mlir::Block *insertBlock = nullptr;
+    if (auto scopeOp = currParent->getParentOfType<cir::ScopeOp>()) {
+      insertBlock = &scopeOp.getScopeRegion().getBlocks().back();
+    } else if (auto fnOp = currParent->getParentOfType<cir::FuncOp>()) {
+      insertBlock = &fnOp.getRegion().getBlocks().back();
+    } else {
+      llvm_unreachable("unknown outermost scope-like parent");
+    }
+    return cgf.getBuilder().getBestAllocaInsertPoint(insertBlock);
+  };
+
+  // Emit the local. Make sure the alloca's superseed the current scope, since
+  // these are going to be consumed by `cir.catch`, which is not within the
+  // current scope.
+
+  CIRGenFunction::AutoVarEmission var =
+      cgf.emitAutoVarAlloca(*catchParam, getCatchParamAllocaIP());
+  initCatchParam(cgf, *catchParam, var.getObjectAddress(cgf),
+                 catchStmt->getBeginLoc());
+  cgf.emitAutoVarCleanups(var);
 }
diff --git a/clang/test/CIR/CodeGen/try-catch-tmp.cpp 
b/clang/test/CIR/CodeGen/try-catch-tmp.cpp
index e6188e52603ff..9e7d4e9a95fe7 100644
--- a/clang/test/CIR/CodeGen/try-catch-tmp.cpp
+++ b/clang/test/CIR/CodeGen/try-catch-tmp.cpp
@@ -56,6 +56,7 @@ void call_function_inside_try_catch_with_exception_type() {
 // CIR:     %[[CALL:.*]] = cir.call @_Z8divisionv() : () -> !s32i
 // CIR:     cir.yield
 // CIR:   } catch [type #cir.global_view<@_ZTIi> : !cir.ptr<!u8i>] {
+// CIR:     %[[CATCH_PARAM:.*]] = cir.catch_param : !cir.ptr<!s32i>
 // CIR:     cir.yield
 // CIR:   } unwind {
 // CIR:     cir.resume

>From d5a660ef666ceaebb336cee123c4d672cb57c743 Mon Sep 17 00:00:00 2001
From: Amr Hesham <[email protected]>
Date: Fri, 12 Dec 2025 18:29:46 +0100
Subject: [PATCH 5/8] Address code review comments

---
 clang/lib/CIR/CodeGen/CIRGenException.cpp | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/clang/lib/CIR/CodeGen/CIRGenException.cpp 
b/clang/lib/CIR/CodeGen/CIRGenException.cpp
index 05f2be6d077eb..88956cd150ba1 100644
--- a/clang/lib/CIR/CodeGen/CIRGenException.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenException.cpp
@@ -262,10 +262,9 @@ void CIRGenFunction::populateUnwindResumeBlock(bool 
isCleanup,
     return;
 
   // Emit cir.resume into the unwind region last block
-  cir::CIRBaseBuilderTy::InsertPoint ip = builder.saveInsertionPoint();
+  mlir::OpBuilder::InsertionGuard guard(builder);
   builder.setInsertionPointToStart(unwindResumeBlock);
   cir::ResumeOp::create(builder, tryOp.getLoc());
-  builder.restoreInsertionPoint(ip);
 }
 
 mlir::LogicalResult CIRGenFunction::emitCXXTryStmt(const CXXTryStmt &s) {
@@ -590,7 +589,6 @@ void CIRGenFunction::populateCatchHandlers(cir::TryOp 
tryOp) {
   // with function local static initializers).
   mlir::ArrayAttr handlerTypesAttr = tryOp.getHandlerTypesAttr();
   if (!handlerTypesAttr || handlerTypesAttr.empty()) {
-    // Accumulate all the handlers in scope.
     // Accumulate all the handlers in scope.
     bool hasCatchAll = false;
     llvm::SmallPtrSet<mlir::Attribute, 4> catchTypes;

>From 50349b103c6aa9a137f6e7dc622fcd2f6f76d441 Mon Sep 17 00:00:00 2001
From: Amr Hesham <[email protected]>
Date: Sun, 14 Dec 2025 20:31:54 +0100
Subject: [PATCH 6/8] Address code review comments

---
 clang/include/clang/CIR/Dialect/IR/CIROps.td  |  5 +-
 clang/lib/CIR/CodeGen/CIRGenException.cpp     | 46 +++++--------------
 clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp |  3 +-
 clang/lib/CIR/Dialect/IR/CIRDialect.cpp       | 18 --------
 clang/test/CIR/CodeGen/try-catch-tmp.cpp      |  5 ++
 clang/test/CIR/IR/try-catch.cir               | 34 --------------
 6 files changed, 20 insertions(+), 91 deletions(-)

diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td 
b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index d5a57db841d6c..0e91d008dc52d 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -837,7 +837,7 @@ def CIR_ConditionOp : CIR_Op<"condition", [
 
//===----------------------------------------------------------------------===//
 
 defvar CIR_YieldableScopes = [
-  "ArrayCtor", "ArrayDtor", "AwaitOp", "CallOp", "CaseOp", "DoWhileOp", 
"ForOp",
+  "ArrayCtor", "ArrayDtor", "AwaitOp", "CaseOp", "DoWhileOp", "ForOp",
   "GlobalOp", "IfOp", "ScopeOp", "SwitchOp", "TernaryOp", "WhileOp", "TryOp"
 ];
 
@@ -3031,7 +3031,6 @@ def CIR_CallOp : CIR_CallOpBase<"call", 
[NoRegionArguments]> {
 
   let results = (outs Optional<CIR_AnyType>:$result);
   let arguments = commonArgs;
-  let regions = (region AnyRegion:$cleanup);
 
   let skipDefaultBuilders = 1;
 
@@ -3043,8 +3042,6 @@ def CIR_CallOp : CIR_CallOpBase<"call", 
[NoRegionArguments]> {
         $_state.addAttribute("callee", callee);
       if (resType && !isa<VoidType>(resType))
         $_state.addTypes(resType);
-      // Create region placeholder for potential cleanups.
-      $_state.addRegion();
     }]>
   ];
 }
diff --git a/clang/lib/CIR/CodeGen/CIRGenException.cpp 
b/clang/lib/CIR/CodeGen/CIRGenException.cpp
index 88956cd150ba1..8a0fc1128fc66 100644
--- a/clang/lib/CIR/CodeGen/CIRGenException.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenException.cpp
@@ -381,41 +381,26 @@ static void emitCatchDispatchBlock(CIRGenFunction &cgf,
     return;
   }
 
-  unsigned int numHandlers = catchScope.getNumHandlers();
-  if (numHandlers == 1 && catchScope.getHandler(0).isCatchAll()) {
-    return;
-  }
-
-  // In traditional LLVM codegen, the right handler is selected (with
   // calls to eh_typeid_for) and the selector value is loaded. After that,
   // blocks get connected for later codegen. In CIR, these are all
   // implicit behaviors of cir.catch - not a lot of work to do.
   //
   // Test against each of the exception types we claim to catch.
-  for (unsigned i = 0;; ++i) {
-    assert(i < numHandlers && "ran off end of handlers!");
-    const EHCatchScope::Handler &handler = catchScope.getHandler(i);
+  for (const EHCatchScope::Handler &handler : catchScope) {
+    if (handler.isCatchAll())
+      return;
 
-    [[maybe_unused]] mlir::TypedAttr typeValue = handler.type.rtti;
+    mlir::TypedAttr typeValue = handler.type.rtti;
     assert(handler.type.flags == 0 && "catch handler flags not supported");
     assert(typeValue && "fell into catch-all case!");
 
     // Check for address space mismatch
     assert(!cir::MissingFeatures::addressSpace());
-
-    // If this is the last handler, we're at the end, and the next
-    // block is the block for the enclosing EH scope. Make sure to call
-    // populateEHCatchRegions for caching it.
-    if (i + 1 == numHandlers) {
-      cgf.populateEHCatchRegions(catchScope.getEnclosingEHScope(), tryOp);
-      return;
-    }
-
-    // If the next handler is a catch-all, we're at the end, and the
-    // next block is that handler.
-    if (catchScope.getHandler(i + 1).isCatchAll())
-      return;
   }
+
+  // There was no catch all handler, populate th EH regions for the enclosing
+  // scope.
+  cgf.populateEHCatchRegions(catchScope.getEnclosingEHScope(), tryOp);
 }
 
 void CIRGenFunction::enterCXXTryStmt(const CXXTryStmt &s, cir::TryOp tryOp,
@@ -635,15 +620,13 @@ void CIRGenFunction::populateCatchHandlers(cir::TryOp 
tryOp) {
         break;
     }
 
-    if (hasCatchAll) {
+    if (hasCatchAll)
       handlerAttrs.push_back(cir::CatchAllAttr::get(&getMLIRContext()));
-    }
 
     // If there's no catch_all, attach the unwind region. This needs to be the
     // last region in the TryOp catch list.
-    if (!hasCatchAll) {
+    if (!hasCatchAll)
       handlerAttrs.push_back(cir::UnwindAttr::get(&getMLIRContext()));
-    }
 
     // Add final array of clauses into TryOp.
     tryOp.setHandlerTypesAttr(
@@ -702,13 +685,8 @@ void 
CIRGenFunction::populateEHCatchRegions(EHScopeStack::stable_iterator scope,
       }
 
       assert(callWithExceptionCtx && "expected call information");
-      {
-        mlir::OpBuilder::InsertionGuard guard(builder);
-        assert(callWithExceptionCtx.getCleanup().empty() &&
-               "one per call: expected empty region at this point");
-        builder.createBlock(&callWithExceptionCtx.getCleanup());
-        builder.createYield(callWithExceptionCtx.getLoc());
-      }
+      // TODO(cir): In the incubator we create a new basic block with YieldOp
+      // inside the attached cleanup region, but this part will be redesigned
       break;
     }
     case EHScope::Cleanup: {
diff --git a/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp 
b/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp
index 7de2f32a28b0c..0d0d6c34a255a 100644
--- a/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp
@@ -2412,7 +2412,8 @@ void CIRGenItaniumCXXABI::emitBeginCatch(CIRGenFunction 
&cgf,
   }
 
   auto getCatchParamAllocaIP = [&]() {
-    auto currIns = cgf.getBuilder().saveInsertionPoint();
+    cir::CIRBaseBuilderTy::InsertPoint currIns =
+        cgf.getBuilder().saveInsertionPoint();
     mlir::Operation *currParent = currIns.getBlock()->getParentOp();
 
     mlir::Block *insertBlock = nullptr;
diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp 
b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
index d4464d77c972a..95fc3afffb156 100644
--- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
@@ -847,16 +847,6 @@ static mlir::ParseResult parseCallCommon(mlir::OpAsmParser 
&parser,
   if (parser.resolveOperands(ops, opsFnTy.getInputs(), opsLoc, 
result.operands))
     return mlir::failure();
 
-  // If exception is present and there are cleanups, this should be latest 
thing
-  // present (after all attributes, etc).
-  if (!hasDestinationBlocks) {
-    mlir::Region *cleanupRegion = result.addRegion();
-    if (parser.parseOptionalKeyword("cleanup").succeeded()) {
-      if (parser.parseRegion(*cleanupRegion))
-        return failure();
-    }
-  }
-
   return mlir::success();
 }
 
@@ -909,14 +899,6 @@ static void printCallCommon(mlir::Operation *op,
   printer << " : ";
   printer.printFunctionalType(op->getOperands().getTypes(),
                               op->getResultTypes());
-
-  // If exception is present and there are cleanups, this should be latest 
thing
-  // present (after all attributes, etc).
-  auto call = dyn_cast<cir::CallOp>(op);
-  if (call && !call.getCleanup().empty()) {
-    printer << " cleanup ";
-    printer.printRegion(call.getCleanup());
-  }
 }
 
 mlir::ParseResult cir::CallOp::parse(mlir::OpAsmParser &parser,
diff --git a/clang/test/CIR/CodeGen/try-catch-tmp.cpp 
b/clang/test/CIR/CodeGen/try-catch-tmp.cpp
index 9e7d4e9a95fe7..a7e0cf986d85d 100644
--- a/clang/test/CIR/CodeGen/try-catch-tmp.cpp
+++ b/clang/test/CIR/CodeGen/try-catch-tmp.cpp
@@ -12,6 +12,7 @@ void call_function_inside_try_catch_all() {
   }
 }
 
+// CIR: cir.func {{.*}} @_Z34call_function_inside_try_catch_allv() 
personality(@__gxx_personality_v0)
 // CIR: cir.scope {
 // CIR:   cir.try {
 // CIR:       %[[CALL:.*]] = cir.call @_Z8divisionv() : () -> !s32i
@@ -22,6 +23,8 @@ void call_function_inside_try_catch_all() {
 // CIR:   }
 // CIR: }
 
+
+// OGCG: define {{.*}} void @_Z34call_function_inside_try_catch_allv() #0 
personality ptr @__gxx_personality_v0
 // OGCG:   %[[EXN_OBJ_ADDR:.*]] = alloca ptr, align 8
 // OGCG:   %[[EH_SELECTOR_ADDR:.*]] = alloca i32, align 4
 // OGCG:   %[[CALL:.*]] = invoke noundef i32 @_Z8divisionv()
@@ -51,6 +54,7 @@ void call_function_inside_try_catch_with_exception_type() {
   }
 }
 
+// CIR: cir.func {{.*}} 
@_Z50call_function_inside_try_catch_with_exception_typev() 
personality(@__gxx_personality_v0)
 // CIR: cir.scope {
 // CIR:   cir.try {
 // CIR:     %[[CALL:.*]] = cir.call @_Z8divisionv() : () -> !s32i
@@ -63,6 +67,7 @@ void call_function_inside_try_catch_with_exception_type() {
 // CIR:   }
 // CIR: }
 
+// OGCG: define {{.*}} void 
@_Z50call_function_inside_try_catch_with_exception_typev() #0 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 i32, align 4
diff --git a/clang/test/CIR/IR/try-catch.cir b/clang/test/CIR/IR/try-catch.cir
index 94368c46c6ba5..8ffce067ba043 100644
--- a/clang/test/CIR/IR/try-catch.cir
+++ b/clang/test/CIR/IR/try-catch.cir
@@ -1,7 +1,6 @@
 // RUN: cir-opt %s --verify-roundtrip | FileCheck %s
 
 !u8i = !cir.int<u, 8>
-!s32i = !cir.int<s, 32>
 
 module {
 
@@ -104,37 +103,4 @@ cir.func 
@empty_try_block_with_catch_unwind_contains_resume() {
 // CHECK:   cir.return
 // CHECK: }
 
-
-cir.func private @function_with_cleanup() -> !s32i
-
-// CHECK: cir.func private @function_with_cleanup() -> !s32i
-
-cir.func @try_catch_with_call_that_has_cleanup() {
-  cir.scope {
-    cir.try {
-      cir.call @function_with_cleanup() : () -> !s32i cleanup {
-        cir.yield
-      }
-      cir.yield
-    } unwind {
-      cir.resume
-    }
-  }
-  cir.return
-}
-
-// CHECK: cir.func @try_catch_with_call_that_has_cleanup() {
-// CHECK:   cir.scope {
-// CHECK:     cir.try {
-// CHECK:       cir.call @function_with_cleanup() : () -> !s32i cleanup {
-// CHECK:         cir.yield
-// CHECK:       }
-// CHECK:       cir.yield
-// CHECK:     } unwind {
-// CHECK:       cir.resume
-// CHECK:     }
-// CHECK:   }
-// CHECK:   cir.return
-// CHECK: }
-
 }

>From 69281715065ff1cebe34cfff99d84819a2fa3fd0 Mon Sep 17 00:00:00 2001
From: Amr Hesham <[email protected]>
Date: Mon, 15 Dec 2025 22:17:59 +0100
Subject: [PATCH 7/8] Extend the test cases & Address code review comments

---
 clang/lib/CIR/CodeGen/CIRGenCall.cpp      |  2 -
 clang/lib/CIR/CodeGen/CIRGenException.cpp | 31 ++++-------
 clang/lib/CIR/CodeGen/CIRGenFunction.h    |  1 -
 clang/test/CIR/CodeGen/try-catch-tmp.cpp  | 68 ++++++++++++++++++++++-
 4 files changed, 76 insertions(+), 26 deletions(-)

diff --git a/clang/lib/CIR/CodeGen/CIRGenCall.cpp 
b/clang/lib/CIR/CodeGen/CIRGenCall.cpp
index 3ef443962aaa7..17f0c6dbab35c 100644
--- a/clang/lib/CIR/CodeGen/CIRGenCall.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenCall.cpp
@@ -503,9 +503,7 @@ emitCallLikeOp(CIRGenFunction &cgf, mlir::Location callLoc,
     callOpWithExceptions =
         builder.createCallOp(callLoc, directFuncOp, cirCallArgs);
 
-    cgf.callWithExceptionCtx = callOpWithExceptions;
     cgf.populateCatchHandlersIfRequired(tryOp);
-    cgf.callWithExceptionCtx = nullptr;
     return callOpWithExceptions;
   }
 
diff --git a/clang/lib/CIR/CodeGen/CIRGenException.cpp 
b/clang/lib/CIR/CodeGen/CIRGenException.cpp
index 8a0fc1128fc66..a22166fa72e94 100644
--- a/clang/lib/CIR/CodeGen/CIRGenException.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenException.cpp
@@ -381,26 +381,16 @@ static void emitCatchDispatchBlock(CIRGenFunction &cgf,
     return;
   }
 
-  // calls to eh_typeid_for) and the selector value is loaded. After that,
-  // blocks get connected for later codegen. In CIR, these are all
-  // implicit behaviors of cir.catch - not a lot of work to do.
-  //
-  // Test against each of the exception types we claim to catch.
-  for (const EHCatchScope::Handler &handler : catchScope) {
-    if (handler.isCatchAll())
-      return;
-
-    mlir::TypedAttr typeValue = handler.type.rtti;
-    assert(handler.type.flags == 0 && "catch handler flags not supported");
-    assert(typeValue && "fell into catch-all case!");
-
-    // Check for address space mismatch
-    assert(!cir::MissingFeatures::addressSpace());
-  }
-
-  // There was no catch all handler, populate th EH regions for the enclosing
-  // scope.
-  cgf.populateEHCatchRegions(catchScope.getEnclosingEHScope(), tryOp);
+  assert(std::find_if(catchScope.begin(), catchScope.end(),
+                      [](const auto &handler) {
+                        return !handler.type.rtti && handler.type.flags != 0;
+                      }) == catchScope.end() &&
+         "catch handler without type value or with not supported flags");
+
+  // There was no catch all handler, populate th EH regions for the
+  // enclosing scope.
+  if (!std::prev(catchScope.end())->isCatchAll())
+    cgf.populateEHCatchRegions(catchScope.getEnclosingEHScope(), tryOp);
 }
 
 void CIRGenFunction::enterCXXTryStmt(const CXXTryStmt &s, cir::TryOp tryOp,
@@ -684,7 +674,6 @@ void 
CIRGenFunction::populateEHCatchRegions(EHScopeStack::stable_iterator scope,
         break;
       }
 
-      assert(callWithExceptionCtx && "expected call information");
       // TODO(cir): In the incubator we create a new basic block with YieldOp
       // inside the attached cleanup region, but this part will be redesigned
       break;
diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h 
b/clang/lib/CIR/CodeGen/CIRGenFunction.h
index a1c0ceed9db1b..cafbdb1471f2d 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.h
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h
@@ -974,7 +974,6 @@ class CIRGenFunction : public CIRGenTypeCache {
     return false;
   }
 
-  cir::CallOp callWithExceptionCtx = nullptr;
   void populateUnwindResumeBlock(bool isCleanup, cir::TryOp tryOp);
   void populateEHCatchRegions(EHScopeStack::stable_iterator scope,
                               cir::TryOp tryOp);
diff --git a/clang/test/CIR/CodeGen/try-catch-tmp.cpp 
b/clang/test/CIR/CodeGen/try-catch-tmp.cpp
index a7e0cf986d85d..78d8567e0760f 100644
--- a/clang/test/CIR/CodeGen/try-catch-tmp.cpp
+++ b/clang/test/CIR/CodeGen/try-catch-tmp.cpp
@@ -56,11 +56,14 @@ void call_function_inside_try_catch_with_exception_type() {
 
 // CIR: cir.func {{.*}} 
@_Z50call_function_inside_try_catch_with_exception_typev() 
personality(@__gxx_personality_v0)
 // CIR: cir.scope {
+// CIR:   %[[EXCEPTION_ADDR:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["e"]
 // CIR:   cir.try {
 // CIR:     %[[CALL:.*]] = cir.call @_Z8divisionv() : () -> !s32i
 // CIR:     cir.yield
 // CIR:   } catch [type #cir.global_view<@_ZTIi> : !cir.ptr<!u8i>] {
 // CIR:     %[[CATCH_PARAM:.*]] = cir.catch_param : !cir.ptr<!s32i>
+// CIR      %[[TMP_CATCH_PARAM:.*]] = cir.load {{.*}} %[[CATCH_PRAM]] : 
!cir.ptr<!s32i>, !s32i
+// CIR      cir.store {{.*}} %[[TMP_CATCH_PARAM]], %[[EXCEPTION_ADDR]] : 
!s32i, !cir.ptr<!s32i>
 // CIR:     cir.yield
 // CIR:   } unwind {
 // CIR:     cir.resume
@@ -94,8 +97,8 @@ void call_function_inside_try_catch_with_exception_type() {
 // OGCG:   %[[TMP_BEGIN_CATCH:.*]] = load i32, ptr %[[BEGIN_CATCH]], align 4
 // OGCG:   store i32 %[[TMP_BEGIN_CATCH]], ptr %[[E_ADDR]], align 4
 // OGCG:   call void @__cxa_end_catch()
-// OGCG:   br label %[[TRY_NORMA:.*]]
-// OGCG: [[TRY_NORMA]]:
+// OGCG:   br label %[[TRY_CONT:.*]]
+// OGCG: [[TRY_CONT]]:
 // OGCG:   ret void
 // OGCG: [[EH_RESUME]]:
 // OGCG:   %[[TMP_EXCEPTION:.*]] = load ptr, ptr %[[EXCEPTION_ADDR]], align 8
@@ -103,3 +106,64 @@ void call_function_inside_try_catch_with_exception_type() {
 // 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]]
+
+void call_function_inside_try_catch_with_exception_type_and_catch_all() {
+  try {
+    division();
+  } catch (int e) {
+  } catch (...) {
+  }
+}
+
+// CIR: cir.func {{.*}} 
@_Z64call_function_inside_try_catch_with_exception_type_and_catch_allv() 
personality(@__gxx_personality_v0)
+// CIR: cir.scope {
+// CIR:   %[[EXCEPTION_ADDR:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["e"]
+// CIR:   cir.try {
+// CIR:     %[[CALL:.*]] = cir.call @_Z8divisionv() : () -> !s32i
+// CIR:     cir.yield
+// CIR:   } catch [type #cir.global_view<@_ZTIi> : !cir.ptr<!u8i>] {
+// CIR:     %[[CATCH_PARAM:.*]] = cir.catch_param : !cir.ptr<!s32i>
+// CIR      %[[TMP_CATCH_PARAM:.*]] = cir.load {{.*}} %[[CATCH_PRAM]] : 
!cir.ptr<!s32i>, !s32i
+// CIR      cir.store {{.*}} %[[TMP_CATCH_PARAM]], %[[EXCEPTION_ADDR]] : 
!s32i, !cir.ptr<!s32i>
+// CIR:     cir.yield
+// CIR:   } catch all {
+// CIR:     %[[CATCH_PARAM]] = cir.catch_param : !cir.ptr<!void>
+// CIR:     cir.yield
+// CIR:   }
+// CIR: }
+
+// OGCG: define {{.*}} void 
@_Z64call_function_inside_try_catch_with_exception_type_and_catch_allv() #0 
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 i32, align 4
+// 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 @_ZTIi
+// 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 %[[EH_TYPE_ID_ADDR]], align 4
+// OGCG:   %[[EH_TYPE_ID:.*]] = call i32 @llvm.eh.typeid.for.p0(ptr @_ZTIi)
+// OGCG:   %[[TYPE_ID_EQ:.*]] = icmp eq i32 %[[TMP_EH_TYPE_ID]], 
%[[EH_TYPE_ID]]
+// OGCG:   br i1 %[[TYPE_ID_EQ]], label %[[CATCH_EXCEPTION:.*]], label 
%[[CATCH_ALL:.*]]
+// 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:   %[[TMP_BEGIN_CATCH:.*]] = load i32, ptr %[[BEGIN_CATCH]], align 4
+// OGCG:   store i32 %[[TMP_BEGIN_CATCH]], ptr %[[E_ADDR]], align 4
+// OGCG:   call void @__cxa_end_catch()
+// OGCG:   br label %[[TRY_CONT:.*]]
+// OGCG: [[TRY_CONT]]:
+// OGCG:   ret void
+// OGCG: [[CATCH_ALL]]:
+// OGCG:   %[[TMP_EXCEPTION:.*]] = load ptr, ptr %[[EXCEPTION_ADDR]], align 8
+// OGCG:   %[[BEGIN_CATCH:.*]] = call ptr @__cxa_begin_catch(ptr 
%[[TMP_EXCEPTION]])
+// OGCG:   call void @__cxa_end_catch()
+// OGCG:   br label %[[TRY_CONT]]

>From 78374141ff29ba21aa83252b81a73e94db8a88e7 Mon Sep 17 00:00:00 2001
From: Amr Hesham <[email protected]>
Date: Tue, 16 Dec 2025 14:05:03 +0100
Subject: [PATCH 8/8] Add missing feature for EHScope filter

---
 clang/include/clang/CIR/MissingFeatures.h | 1 +
 clang/lib/CIR/CodeGen/CIRGenException.cpp | 2 ++
 2 files changed, 3 insertions(+)

diff --git a/clang/include/clang/CIR/MissingFeatures.h 
b/clang/include/clang/CIR/MissingFeatures.h
index 75f3599875372..a5b04d305b3e7 100644
--- a/clang/include/clang/CIR/MissingFeatures.h
+++ b/clang/include/clang/CIR/MissingFeatures.h
@@ -263,6 +263,7 @@ struct MissingFeatures {
   static bool ehCleanupScope() { return false; }
   static bool ehCleanupScopeRequiresEHCleanup() { return false; }
   static bool ehCleanupBranchFixups() { return false; }
+  static bool ehScopeFilter() { return false; }
   static bool ehstackBranches() { return false; }
   static bool emitBranchThroughCleanup() { return false; }
   static bool emitCheckedInBoundsGEP() { return false; }
diff --git a/clang/lib/CIR/CodeGen/CIRGenException.cpp 
b/clang/lib/CIR/CodeGen/CIRGenException.cpp
index a22166fa72e94..b84b3a3c92015 100644
--- a/clang/lib/CIR/CodeGen/CIRGenException.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenException.cpp
@@ -613,6 +613,8 @@ void CIRGenFunction::populateCatchHandlers(cir::TryOp 
tryOp) {
     if (hasCatchAll)
       handlerAttrs.push_back(cir::CatchAllAttr::get(&getMLIRContext()));
 
+    assert(!cir::MissingFeatures::ehScopeFilter());
+
     // If there's no catch_all, attach the unwind region. This needs to be the
     // last region in the TryOp catch list.
     if (!hasCatchAll)

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to