[clang] [CIR] Upstream CIR Dialect TryOp with Catch Attrs (PR #162897)

Amr Hesham via cfe-commits cfe-commits at lists.llvm.org
Wed Oct 15 09:57:22 PDT 2025


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

>From 7837cc397473399ad1221f267b7d413c43718d4d Mon Sep 17 00:00:00 2001
From: Amr Hesham <amr96 at programmer.net>
Date: Fri, 10 Oct 2025 19:09:16 +0200
Subject: [PATCH 1/7] [CIR] Upstream CIR Dialect TryOp with Catch Attrs

---
 .../include/clang/CIR/Dialect/IR/CIRAttrs.td  |  15 ++
 clang/include/clang/CIR/Dialect/IR/CIROps.td  |  63 ++++++++-
 clang/lib/CIR/Dialect/IR/CIRDialect.cpp       | 132 ++++++++++++++++++
 clang/test/CIR/IR/try-catch.cir               |  84 +++++++++++
 4 files changed, 292 insertions(+), 2 deletions(-)
 create mode 100644 clang/test/CIR/IR/try-catch.cir

diff --git a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
index 610e349717e12..e739378e3969c 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
@@ -968,4 +968,19 @@ def CIR_TypeInfoAttr : CIR_Attr<"TypeInfo", "typeinfo", [TypedAttrInterface]> {
   }];
 }
 
+//===----------------------------------------------------------------------===//
+// CatchAllAttr & CatchUnwindAttr
+//===----------------------------------------------------------------------===//
+
+// Represents the unwind region where unwind continues or
+// the program std::terminate's.
+def CIR_CatchUnwindAttr : CIR_UnitAttr<"CatchUnwind", "unwind"> {
+  let storageType = [{ CatchUnwind }];
+}
+
+// Represents the catch_all region.
+def CIR_CatchAllAttr : CIR_UnitAttr<"CatchAll", "all"> {
+  let storageType = [{ CatchAllAttr }];
+}
+
 #endif // CLANG_CIR_DIALECT_IR_CIRATTRS_TD
diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index baab156726a2b..44e8363ee3f45 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -644,7 +644,7 @@ def CIR_StoreOp : CIR_Op<"store", [
 
 defvar CIR_ReturnableScopes = [
   "FuncOp", "ScopeOp", "IfOp", "SwitchOp", "CaseOp",
-  "DoWhileOp", "WhileOp", "ForOp"
+  "DoWhileOp", "WhileOp", "ForOp", "TryOp"
 ];
 
 def CIR_ReturnOp : CIR_Op<"return", [
@@ -791,7 +791,7 @@ def CIR_ConditionOp : CIR_Op<"condition", [
 
 defvar CIR_YieldableScopes = [
   "ArrayCtor", "ArrayDtor", "CaseOp", "DoWhileOp", "ForOp", "GlobalOp", "IfOp",
-  "ScopeOp", "SwitchOp", "TernaryOp", "WhileOp"
+  "ScopeOp", "SwitchOp", "TernaryOp", "WhileOp", "TryOp"
 ];
 
 def CIR_YieldOp : CIR_Op<"yield", [
@@ -4325,6 +4325,65 @@ def CIR_AllocExceptionOp : CIR_Op<"alloc.exception"> {
   }];
 }
 
+//===----------------------------------------------------------------------===//
+// TryOp
+//===----------------------------------------------------------------------===//
+
+def CIR_TryOp : CIR_Op<"try",[
+  DeclareOpInterfaceMethods<RegionBranchOpInterface>,
+  RecursivelySpeculatable, AutomaticAllocationScope, NoRegionArguments
+]> {
+  let summary = "C++ try block";
+  let description = [{
+    Holds the lexical scope of `try {}`. Note that resources used on catch
+    clauses are usually allocated in the same parent as `cir.try`.
+
+    `synthetic`: use `cir.try` to represent try/catches not originally
+    present in the source code (e.g. `g = new Class` under `-fexceptions`).
+
+    `cleanup`: signal to targets (LLVM for now) that this try/catch, needs
+    to specially tag their landing pads as needing "cleanup".
+
+    Example:
+
+    ```mlir
+    %0 = cir.alloc.exception 16 -> !cir.ptr<!some_record>
+    %1 = cir.get_global @d2 : !cir.ptr<!some_record>
+    cir.try synthetic cleanup {
+      cir.call exception @_ZN7test2_DC1ERKS_(%0, %1)
+            : (!cir.ptr<!some_record>, !cir.ptr<!some_record>) -> () cleanup {
+        %2 = cir.cast bitcast %0 : !cir.ptr<!some_record> -> !cir.ptr<!void>
+        cir.free.exception %2
+        cir.yield
+      }
+      ...
+    }
+    ```
+  }];
+
+  let arguments = (ins UnitAttr:$synthetic, UnitAttr:$cleanup,
+                       OptionalAttr<ArrayAttr>:$catch_types);
+  let regions = (region AnyRegion:$try_region,
+                        VariadicRegion<AnyRegion>:$catch_regions);
+
+  let assemblyFormat = [{
+    (`synthetic` $synthetic^)?
+    (`cleanup` $cleanup^)?
+    $try_region
+    custom<CatchRegions>($catch_regions, $catch_types)
+    attr-dict
+  }];
+
+  // Everything already covered elsewhere.
+  let builders = [OpBuilder<(ins
+      "llvm::function_ref<void(mlir::OpBuilder &, "
+        "mlir::Location)>":$tryBuilder,
+      "llvm::function_ref<void(mlir::OpBuilder &, mlir::Location, "
+        "mlir::OperationState &)>":$catchBuilder)>];
+
+  let hasLLVMLowering = false;
+}
+
 //===----------------------------------------------------------------------===//
 // Atomic operations
 //===----------------------------------------------------------------------===//
diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
index 7af3dc1f84955..2f5a93450ab88 100644
--- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
@@ -2914,6 +2914,138 @@ LogicalResult cir::TypeInfoAttr::verify(
   return success();
 }
 
+//===----------------------------------------------------------------------===//
+// TryOp
+//===----------------------------------------------------------------------===//
+
+void cir::TryOp::build(
+    OpBuilder &builder, OperationState &result,
+    function_ref<void(OpBuilder &, Location)> tryBuilder,
+    function_ref<void(OpBuilder &, Location, OperationState &)> catchBuilder) {
+  assert(tryBuilder && "expected builder callback for 'cir.try' body");
+  assert(catchBuilder && "expected builder callback for 'catch' body");
+
+  OpBuilder::InsertionGuard guard(builder);
+
+  // Try body region
+  Region *tryBodyRegion = result.addRegion();
+
+  // Create try body region and set insertion point
+  builder.createBlock(tryBodyRegion);
+  tryBuilder(builder, result.location);
+  catchBuilder(builder, result.location, result);
+}
+
+void cir::TryOp::getSuccessorRegions(
+    mlir::RegionBranchPoint point, SmallVectorImpl<RegionSuccessor> &regions) {
+  // If any index all the underlying regions branch back to the parent
+  // operation.
+  if (!point.isParent()) {
+    regions.push_back(RegionSuccessor());
+    return;
+  }
+
+  // If the condition isn't constant, both regions may be executed.
+  regions.push_back(RegionSuccessor(&getTryRegion()));
+
+  // FIXME: optimize, ideas include:
+  // - If we know a target function never throws a specific type, we can
+  //   remove the catch handler.
+  for (mlir::Region &r : this->getCatchRegions())
+    regions.push_back(RegionSuccessor(&r));
+}
+
+static void printCatchRegions(OpAsmPrinter &printer, cir::TryOp op,
+                              mlir::MutableArrayRef<::mlir::Region> regions,
+                              mlir::ArrayAttr catchersAttr) {
+  if (!catchersAttr)
+    return;
+
+  int currCatchIdx = 0;
+  printer << "catch [";
+  llvm::interleaveComma(catchersAttr, printer, [&](const Attribute &a) {
+    if (mlir::isa<cir::CatchUnwindAttr>(a)) {
+      printer.printAttribute(a);
+      printer << " ";
+    } else if (!a) {
+      printer << "all";
+    } else {
+      printer << "type ";
+      printer.printAttribute(a);
+      printer << " ";
+    }
+    printer.printRegion(regions[currCatchIdx], /*printEntryBLockArgs=*/false,
+                        /*printBlockTerminators=*/true);
+    currCatchIdx++;
+  });
+
+  printer << "]";
+}
+
+static ParseResult parseCatchRegions(
+    OpAsmParser &parser,
+    llvm::SmallVectorImpl<std::unique_ptr<::mlir::Region>> &regions,
+    ::mlir::ArrayAttr &catchersAttr) {
+  if (parser.parseKeyword("catch").failed())
+    return parser.emitError(parser.getCurrentLocation(),
+                            "expected 'catch' keyword here");
+
+  auto parseAndCheckRegion = [&]() -> ParseResult {
+    // Parse region attached to catch
+    regions.emplace_back(new Region);
+    Region &currRegion = *regions.back();
+    SMLoc parserLoc = parser.getCurrentLocation();
+    if (parser.parseRegion(currRegion)) {
+      regions.clear();
+      return failure();
+    }
+
+    if (currRegion.empty()) {
+      return parser.emitError(parser.getCurrentLocation(),
+                              "catch region shall not be empty");
+    }
+
+    if (!(currRegion.back().mightHaveTerminator() &&
+          currRegion.back().getTerminator()))
+      return parser.emitError(
+          parserLoc, "blocks are expected to be explicitly terminated");
+
+    return success();
+  };
+
+  llvm::SmallVector<mlir::Attribute, 4> catchList;
+  auto parseCatchEntry = [&]() -> ParseResult {
+    mlir::Attribute exceptionTypeInfo;
+
+    if (parser.parseOptionalAttribute(exceptionTypeInfo).has_value()) {
+      catchList.push_back(exceptionTypeInfo);
+    } else {
+      ::llvm::StringRef attrStr;
+      if (parser.parseOptionalKeyword(&attrStr, {"all"}).succeeded()) {
+        // "all" keyword found, exceptionTypeInfo remains null
+      } else if (parser.parseOptionalKeyword("type").succeeded()) {
+        if (parser.parseAttribute(exceptionTypeInfo).failed())
+          return parser.emitError(parser.getCurrentLocation(),
+                                  "expected valid RTTI info attribute");
+      } else {
+        return parser.emitError(parser.getCurrentLocation(),
+                                "expected attribute, 'all', or 'type' keyword");
+      }
+      catchList.push_back(exceptionTypeInfo);
+    }
+    return parseAndCheckRegion();
+  };
+
+  if (parser
+          .parseCommaSeparatedList(OpAsmParser::Delimiter::Square,
+                                   parseCatchEntry, " in catch list")
+          .failed())
+    return failure();
+
+  catchersAttr = parser.getBuilder().getArrayAttr(catchList);
+  return ::mlir::success();
+}
+
 //===----------------------------------------------------------------------===//
 // TableGen'd op method definitions
 //===----------------------------------------------------------------------===//
diff --git a/clang/test/CIR/IR/try-catch.cir b/clang/test/CIR/IR/try-catch.cir
new file mode 100644
index 0000000000000..7bc71ff84d4ae
--- /dev/null
+++ b/clang/test/CIR/IR/try-catch.cir
@@ -0,0 +1,84 @@
+// RUN: cir-opt %s --verify-roundtrip | FileCheck %s
+
+!u8i = !cir.int<u, 8>
+
+module {
+
+cir.global "private" constant external @_ZTIi : !cir.ptr<!u8i>
+cir.global "private" constant external @_ZTIPKc : !cir.ptr<!u8i>
+
+cir.func dso_local @empty_try_block_with_catch_all() {
+  cir.scope {
+    cir.try {
+      cir.yield
+    } catch [type #cir.all {
+      cir.yield
+    }]
+  }
+  cir.return
+}
+
+// CHECK:  cir.func dso_local @empty_try_block_with_catch_all() {
+// CHECK:    cir.scope {
+// CHECK:      cir.try {
+// CHECK:        cir.yield
+// CHECK:      } catch [type #cir.all {
+// CHECK:        cir.yield
+// CHECK:      }]
+// CHECK:    }
+// CHECK:    cir.return
+// CHECK:  }
+
+cir.func dso_local @empty_try_block_with_catch_unwind() {
+  cir.scope {
+    cir.try {
+      cir.yield
+    } catch [#cir.unwind {
+      cir.yield
+    }]
+  }
+  cir.return
+}
+
+// CHECK: cir.func dso_local @empty_try_block_with_catch_unwind() {
+// CHECK:  cir.scope {
+// CHECK:    cir.try {
+// CHECK:      cir.yield
+// CHECK:    } catch [#cir.unwind {
+// CHECK:      cir.yield
+// CHECK:    }]
+// CHECK:  }
+// CHECK:  cir.return
+// CHECK: }
+
+cir.func dso_local @empty_try_block_with_catch_ist() {
+  cir.scope {
+    cir.try {
+      cir.yield
+    } catch [type #cir.global_view<@_ZTIi> : !cir.ptr<!u8i> {
+      cir.yield
+    }, type #cir.global_view<@_ZTIPKc> : !cir.ptr<!u8i> {
+      cir.yield
+    }, #cir.unwind {
+      cir.yield
+    }]
+  }
+  cir.return
+}
+
+// CHECK: cir.func dso_local @empty_try_block_with_catch_ist() {
+// CHECK:   cir.scope {
+// CHECK:     cir.try {
+// CHECK:       cir.yield
+// CHECK:     } catch [type #cir.global_view<@_ZTIi> : !cir.ptr<!u8i> {
+// CHECK:       cir.yield
+// CHECK:     }, type #cir.global_view<@_ZTIPKc> : !cir.ptr<!u8i> {
+// CHECK:       cir.yield
+// CHECK:     }, #cir.unwind {
+// CHECK:       cir.yield
+// CHECK:     }]
+// CHECK:   }
+// CHECK:   cir.return
+// CHECK: }
+
+}

>From 05e1171d8553f1e810d9d60ca413144e1e13026b Mon Sep 17 00:00:00 2001
From: Amr Hesham <amr96 at programmer.net>
Date: Fri, 10 Oct 2025 21:14:15 +0200
Subject: [PATCH 2/7] Address code review comments

---
 clang/include/clang/CIR/Dialect/IR/CIROps.td | 20 +++++-
 clang/lib/CIR/Dialect/IR/CIRDialect.cpp      | 18 -----
 clang/test/CIR/IR/invalid-try-catch.cir      | 75 ++++++++++++++++++++
 3 files changed, 93 insertions(+), 20 deletions(-)
 create mode 100644 clang/test/CIR/IR/invalid-try-catch.cir

diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index 44e8363ee3f45..11097299212d8 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -4375,11 +4375,27 @@ def CIR_TryOp : CIR_Op<"try",[
   }];
 
   // Everything already covered elsewhere.
-  let builders = [OpBuilder<(ins
+  let builders = [
+    OpBuilder<(ins
       "llvm::function_ref<void(mlir::OpBuilder &, "
         "mlir::Location)>":$tryBuilder,
       "llvm::function_ref<void(mlir::OpBuilder &, mlir::Location, "
-        "mlir::OperationState &)>":$catchBuilder)>];
+        "mlir::OperationState &)>":$catchBuilder),
+    [{
+      assert(tryBuilder && "expected builder callback for 'cir.try' body");
+      assert(catchBuilder && "expected builder callback for 'catch' body");
+
+      OpBuilder::InsertionGuard guard($_builder);
+
+      // Try body region
+      Region *tryBodyRegion = $_state.addRegion();
+
+      // Create try body region and set insertion point
+      $_builder.createBlock(tryBodyRegion);
+      tryBuilder($_builder, $_state.location);
+      catchBuilder($_builder, $_state.location, $_state);
+    }]>
+  ];
 
   let hasLLVMLowering = false;
 }
diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
index 2f5a93450ab88..40587fef47f7b 100644
--- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
@@ -2918,24 +2918,6 @@ LogicalResult cir::TypeInfoAttr::verify(
 // TryOp
 //===----------------------------------------------------------------------===//
 
-void cir::TryOp::build(
-    OpBuilder &builder, OperationState &result,
-    function_ref<void(OpBuilder &, Location)> tryBuilder,
-    function_ref<void(OpBuilder &, Location, OperationState &)> catchBuilder) {
-  assert(tryBuilder && "expected builder callback for 'cir.try' body");
-  assert(catchBuilder && "expected builder callback for 'catch' body");
-
-  OpBuilder::InsertionGuard guard(builder);
-
-  // Try body region
-  Region *tryBodyRegion = result.addRegion();
-
-  // Create try body region and set insertion point
-  builder.createBlock(tryBodyRegion);
-  tryBuilder(builder, result.location);
-  catchBuilder(builder, result.location, result);
-}
-
 void cir::TryOp::getSuccessorRegions(
     mlir::RegionBranchPoint point, SmallVectorImpl<RegionSuccessor> &regions) {
   // If any index all the underlying regions branch back to the parent
diff --git a/clang/test/CIR/IR/invalid-try-catch.cir b/clang/test/CIR/IR/invalid-try-catch.cir
new file mode 100644
index 0000000000000..57863af13d20b
--- /dev/null
+++ b/clang/test/CIR/IR/invalid-try-catch.cir
@@ -0,0 +1,75 @@
+// RUN: cir-opt %s -verify-diagnostics -split-input-file
+
+module {
+
+cir.func dso_local @invalid_catch_without_all_or_type() {
+  cir.scope {
+    cir.try {
+      cir.yield
+     // expected-error @below {{'cir.try' expected attribute, 'all', or 'type' keyword}}
+    } catch [invalid_keyword {
+      cir.yield
+    }]
+  }
+  cir.return
+}
+
+}
+
+// -----
+
+module {
+
+cir.func dso_local @invalid_catch_rtti_type() {
+  cir.scope {
+    cir.try {
+      cir.yield
+     // expected-error @below {{expected attribute value}}
+     // expected-error @below {{'cir.try' expected valid RTTI info attribute}}
+    } catch [type invalid_type {
+      cir.yield
+    }]
+  }
+  cir.return
+}
+
+}
+
+// -----
+
+module {
+
+cir.func dso_local @invalid_catch_empty_block() {
+  cir.scope {
+    cir.try {
+      cir.yield
+    } catch [type #cir.all {
+      // expected-error @below {{'cir.try' catch region shall not be empty}}
+    }]
+  }
+  cir.return
+}
+
+}
+
+// -----
+
+!s32i = !cir.int<s, 32>
+
+module {
+
+cir.func dso_local @invalid_catch_not_terminated() {
+  %a = cir.alloca !s32i, !cir.ptr<!s32i>, ["a", init]
+  cir.scope {
+    cir.try {
+      cir.yield
+    } 
+    // expected-error @below {{'cir.try' blocks are expected to be explicitly terminated}}
+    catch [type #cir.all {
+       %tmp_a = cir.load %a : !cir.ptr<!s32i>, !s32i
+    }]
+  }
+  cir.return
+}
+
+}

>From 77397f86a820186d9675a3ebcd1ec947b610acf5 Mon Sep 17 00:00:00 2001
From: Amr Hesham <amr96 at programmer.net>
Date: Sat, 11 Oct 2025 00:05:22 +0200
Subject: [PATCH 3/7] Address code review comments

---
 clang/include/clang/CIR/Dialect/IR/CIROps.td | 26 +++++++++++---------
 1 file changed, 14 insertions(+), 12 deletions(-)

diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index 11097299212d8..d4b335d023c02 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -4339,24 +4339,26 @@ def CIR_TryOp : CIR_Op<"try",[
     clauses are usually allocated in the same parent as `cir.try`.
 
     `synthetic`: use `cir.try` to represent try/catches not originally
-    present in the source code (e.g. `g = new Class` under `-fexceptions`).
+    present in the source code. For example, a synthetic `cir.try` region
+    is created around the constructor call when `operator new` is used
+    so that the memory allocated will be freed if the constructor throws
+    an exception.
 
-    `cleanup`: signal to targets (LLVM for now) that this try/catch, needs
-    to specially tag their landing pads as needing "cleanup".
+    `cleanup`: indicates that there are cleanups that must be performed
+    when exiting the try region via exception, even if the exception is not
+    caught.
 
     Example:
 
     ```mlir
-    %0 = cir.alloc.exception 16 -> !cir.ptr<!some_record>
-    %1 = cir.get_global @d2 : !cir.ptr<!some_record>
-    cir.try synthetic cleanup {
-      cir.call exception @_ZN7test2_DC1ERKS_(%0, %1)
-            : (!cir.ptr<!some_record>, !cir.ptr<!some_record>) -> () cleanup {
-        %2 = cir.cast bitcast %0 : !cir.ptr<!some_record> -> !cir.ptr<!void>
-        cir.free.exception %2
-        cir.yield
-      }
+    cir.try {
+      cir.call exception @function() : () -> ()
+      cir.yield
+    } catch [type #cir.global_view<@_ZTIPf> : !cir.ptr<!u8i>] {
       ...
+      cir.yield
+    } unwind {
+      cir.resume
     }
     ```
   }];

>From 4cdea3f26bab4f3b0ddede1e4c5d0086f418c050 Mon Sep 17 00:00:00 2001
From: Amr Hesham <amr96 at programmer.net>
Date: Sat, 11 Oct 2025 13:25:55 +0200
Subject: [PATCH 4/7] TryOp & Catchers Parsers and printers

---
 .../CIR/Dialect/IR/CIRAttrConstraints.td      |  30 +++-
 .../include/clang/CIR/Dialect/IR/CIRAttrs.td  |  14 +-
 clang/include/clang/CIR/Dialect/IR/CIROps.td  |  17 +-
 clang/lib/CIR/Dialect/IR/CIRDialect.cpp       | 152 +++++++++---------
 clang/test/CIR/IR/invalid-try-catch.cir       |  82 ++++++++--
 clang/test/CIR/IR/try-catch.cir               |  60 +++----
 6 files changed, 223 insertions(+), 132 deletions(-)

diff --git a/clang/include/clang/CIR/Dialect/IR/CIRAttrConstraints.td b/clang/include/clang/CIR/Dialect/IR/CIRAttrConstraints.td
index 8f72ff4d754ad..bab847ef621bf 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIRAttrConstraints.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIRAttrConstraints.td
@@ -38,14 +38,32 @@ def CIR_AnyIntOrFloatAttr : AnyAttrOf<[CIR_AnyIntAttr, CIR_AnyFPAttr],
   string cppType = "::mlir::TypedAttr";
 }
 
+//===----------------------------------------------------------------------===//
+// Exceptions constraints
+//===----------------------------------------------------------------------===//
+
+def CIR_AnyCatchAllAttr
+    : CIR_AttrConstraint<"::cir::CatchAllAttr", "catch all attribute">;
+
+def CIR_AnyUnwindAttr
+    : CIR_AttrConstraint<"::cir::UnwindAttr", "unwind attribute">;
+
 //===----------------------------------------------------------------------===//
 // GlobalViewAttr constraints
 //===----------------------------------------------------------------------===//
 
-def CIR_AnyGlobalViewAttr : CIR_AttrConstraint<"::cir::GlobalViewAttr", "GlobalView attribute">;
+def CIR_AnyGlobalViewAttr
+    : CIR_AttrConstraint<"::cir::GlobalViewAttr", "GlobalView attribute">;
 
-def CIR_AnyIntOrGlobalViewAttr : AnyAttrOf<[CIR_AnyIntAttr, CIR_AnyGlobalViewAttr],
-    "integer or global view attribute"> {
+def CIR_AnyIntOrGlobalViewAttr
+    : AnyAttrOf<[CIR_AnyIntAttr, CIR_AnyGlobalViewAttr],
+                "integer or global view attribute"> {
+  string cppType = "::mlir::TypedAttr";
+}
+
+def CIR_AnyGlobalViewOrCatchAllOrUnwindAttr
+    : AnyAttrOf<[CIR_AnyGlobalViewAttr, CIR_AnyCatchAllAttr, CIR_AnyUnwindAttr],
+                "catch all or unwind or global view attribute"> {
   string cppType = "::mlir::TypedAttr";
 }
 
@@ -61,4 +79,8 @@ def CIR_IntOrGlobalViewArrayAttr : TypedArrayAttrBase<CIR_AnyIntOrGlobalViewAttr
   string cppType = "::mlir::ArrayAttr";
 }
 
-#endif // CLANG_CIR_DIALECT_IR_CIRATTRCONSTRAINTS_TD
\ No newline at end of file
+def CIR_GlobalViewOrCatchAllOrUnwindArrayAttr
+    : TypedArrayAttrBase<CIR_AnyGlobalViewOrCatchAllOrUnwindAttr,
+                         "catch all or unwind or global view array attribute">;
+
+#endif // CLANG_CIR_DIALECT_IR_CIRATTRCONSTRAINTS_TD
diff --git a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
index e739378e3969c..69dbad3ba1cde 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
@@ -969,18 +969,18 @@ def CIR_TypeInfoAttr : CIR_Attr<"TypeInfo", "typeinfo", [TypedAttrInterface]> {
 }
 
 //===----------------------------------------------------------------------===//
-// CatchAllAttr & CatchUnwindAttr
+// CatchAllAttr & UnwindAttr
 //===----------------------------------------------------------------------===//
 
-// Represents the unwind region where unwind continues or
-// the program std::terminate's.
-def CIR_CatchUnwindAttr : CIR_UnitAttr<"CatchUnwind", "unwind"> {
-  let storageType = [{ CatchUnwind }];
-}
-
 // Represents the catch_all region.
 def CIR_CatchAllAttr : CIR_UnitAttr<"CatchAll", "all"> {
   let storageType = [{ CatchAllAttr }];
 }
 
+// Represents the unwind region where unwind continues or
+// the program std::terminate's.
+def CIR_UnwindAttr : CIR_UnitAttr<"Unwind", "unwind"> {
+  let storageType = [{ CatchUnwind }];
+}
+
 #endif // CLANG_CIR_DIALECT_IR_CIRATTRS_TD
diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index d4b335d023c02..a321ef2ceb41d 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -4363,10 +4363,16 @@ def CIR_TryOp : CIR_Op<"try",[
     ```
   }];
 
-  let arguments = (ins UnitAttr:$synthetic, UnitAttr:$cleanup,
-                       OptionalAttr<ArrayAttr>:$catch_types);
-  let regions = (region AnyRegion:$try_region,
-                        VariadicRegion<AnyRegion>:$catch_regions);
+  let arguments = (ins
+    UnitAttr:$synthetic,
+    UnitAttr:$cleanup,
+    CIR_GlobalViewOrCatchAllOrUnwindArrayAttr:$catch_types
+  );
+
+  let regions = (region
+    AnyRegion:$try_region,
+    VariadicRegion<MinSizedRegion<1>>:$catch_regions
+  );
 
   let assemblyFormat = [{
     (`synthetic` $synthetic^)?
@@ -4376,7 +4382,6 @@ def CIR_TryOp : CIR_Op<"try",[
     attr-dict
   }];
 
-  // Everything already covered elsewhere.
   let builders = [
     OpBuilder<(ins
       "llvm::function_ref<void(mlir::OpBuilder &, "
@@ -4390,7 +4395,7 @@ def CIR_TryOp : CIR_Op<"try",[
       OpBuilder::InsertionGuard guard($_builder);
 
       // Try body region
-      Region *tryBodyRegion = $_state.addRegion();
+      mlir::Region *tryBodyRegion = $_state.addRegion();
 
       // Create try body region and set insertion point
       $_builder.createBlock(tryBodyRegion);
diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
index 40587fef47f7b..1ff0a784e4eda 100644
--- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
@@ -2919,113 +2919,117 @@ LogicalResult cir::TypeInfoAttr::verify(
 //===----------------------------------------------------------------------===//
 
 void cir::TryOp::getSuccessorRegions(
-    mlir::RegionBranchPoint point, SmallVectorImpl<RegionSuccessor> &regions) {
-  // If any index all the underlying regions branch back to the parent
-  // operation.
+    mlir::RegionBranchPoint point,
+    llvm::SmallVectorImpl<mlir::RegionSuccessor> &regions) {
+  // The `try` and the `catchers` region branch back to the parent operation.
   if (!point.isParent()) {
-    regions.push_back(RegionSuccessor());
+    regions.push_back(mlir::RegionSuccessor());
     return;
   }
 
-  // If the condition isn't constant, both regions may be executed.
-  regions.push_back(RegionSuccessor(&getTryRegion()));
+  regions.push_back(mlir::RegionSuccessor(&getTryRegion()));
 
-  // FIXME: optimize, ideas include:
-  // - If we know a target function never throws a specific type, we can
-  //   remove the catch handler.
-  for (mlir::Region &r : this->getCatchRegions())
-    regions.push_back(RegionSuccessor(&r));
+  // TODO(CIR): If we know a target function never throws a specific type, we
+  // can remove the catch handler.
+  for (mlir::Region &region : this->getCatchRegions())
+    regions.push_back(mlir::RegionSuccessor(&region));
 }
 
-static void printCatchRegions(OpAsmPrinter &printer, cir::TryOp op,
-                              mlir::MutableArrayRef<::mlir::Region> regions,
+static void printCatchRegions(mlir::OpAsmPrinter &printer, cir::TryOp op,
+                              mlir::MutableArrayRef<mlir::Region> regions,
                               mlir::ArrayAttr catchersAttr) {
   if (!catchersAttr)
     return;
 
-  int currCatchIdx = 0;
-  printer << "catch [";
-  llvm::interleaveComma(catchersAttr, printer, [&](const Attribute &a) {
-    if (mlir::isa<cir::CatchUnwindAttr>(a)) {
-      printer.printAttribute(a);
+  for (const auto [catcherIdx, catcherAttr] : llvm::enumerate(catchersAttr)) {
+    if (catcherIdx)
       printer << " ";
-    } else if (!a) {
-      printer << "all";
+
+    if (mlir::isa<cir::CatchAllAttr>(catcherAttr)) {
+      printer << "catch all ";
+    } else if (mlir::isa<cir::UnwindAttr>(catcherAttr)) {
+      printer << "unwind ";
     } else {
-      printer << "type ";
-      printer.printAttribute(a);
-      printer << " ";
+      printer << "catch [type ";
+      printer.printAttribute(catcherAttr);
+      printer << "] ";
     }
-    printer.printRegion(regions[currCatchIdx], /*printEntryBLockArgs=*/false,
-                        /*printBlockTerminators=*/true);
-    currCatchIdx++;
-  });
 
-  printer << "]";
+    printer.printRegion(regions[catcherIdx], /*printEntryBLockArgs=*/false,
+                        /*printBlockTerminators=*/true);
+  }
 }
 
-static ParseResult parseCatchRegions(
-    OpAsmParser &parser,
-    llvm::SmallVectorImpl<std::unique_ptr<::mlir::Region>> &regions,
-    ::mlir::ArrayAttr &catchersAttr) {
-  if (parser.parseKeyword("catch").failed())
-    return parser.emitError(parser.getCurrentLocation(),
-                            "expected 'catch' keyword here");
+static mlir::ParseResult
+parseCatchRegions(mlir::OpAsmParser &parser,
+                  llvm::SmallVectorImpl<std::unique_ptr<mlir::Region>> &regions,
+                  mlir::ArrayAttr &catchersAttr) {
 
-  auto parseAndCheckRegion = [&]() -> ParseResult {
-    // Parse region attached to catch
-    regions.emplace_back(new Region);
-    Region &currRegion = *regions.back();
-    SMLoc parserLoc = parser.getCurrentLocation();
+  auto parseCheckedCatcherRegion = [&]() -> mlir::ParseResult {
+    regions.emplace_back(new mlir::Region);
+
+    mlir::Region &currRegion = *regions.back();
+    mlir::SMLoc regionLoc = parser.getCurrentLocation();
     if (parser.parseRegion(currRegion)) {
       regions.clear();
       return failure();
     }
 
-    if (currRegion.empty()) {
-      return parser.emitError(parser.getCurrentLocation(),
-                              "catch region shall not be empty");
-    }
-
-    if (!(currRegion.back().mightHaveTerminator() &&
-          currRegion.back().getTerminator()))
+    if (!currRegion.empty() && !(currRegion.back().mightHaveTerminator() &&
+                                 currRegion.back().getTerminator()))
       return parser.emitError(
-          parserLoc, "blocks are expected to be explicitly terminated");
+          regionLoc, "blocks are expected to be explicitly terminated");
 
     return success();
   };
 
-  llvm::SmallVector<mlir::Attribute, 4> catchList;
-  auto parseCatchEntry = [&]() -> ParseResult {
-    mlir::Attribute exceptionTypeInfo;
+  bool hasCatchAll = false;
+  llvm::SmallVector<mlir::Attribute, 4> catcherAttrs;
+  while (parser.parseOptionalKeyword("catch").succeeded()) {
+    bool hasLSquare = parser.parseOptionalLSquare().succeeded();
 
-    if (parser.parseOptionalAttribute(exceptionTypeInfo).has_value()) {
-      catchList.push_back(exceptionTypeInfo);
-    } else {
-      ::llvm::StringRef attrStr;
-      if (parser.parseOptionalKeyword(&attrStr, {"all"}).succeeded()) {
-        // "all" keyword found, exceptionTypeInfo remains null
-      } else if (parser.parseOptionalKeyword("type").succeeded()) {
-        if (parser.parseAttribute(exceptionTypeInfo).failed())
-          return parser.emitError(parser.getCurrentLocation(),
-                                  "expected valid RTTI info attribute");
-      } else {
+    llvm::StringRef attrStr;
+    if (parser.parseOptionalKeyword(&attrStr, {"all", "type"}).failed())
+      return parser.emitError(parser.getCurrentLocation(),
+                              "expected 'all' or 'type' keyword");
+
+    bool isCatchAll = attrStr == "all";
+    if (isCatchAll) {
+      if (hasCatchAll)
         return parser.emitError(parser.getCurrentLocation(),
-                                "expected attribute, 'all', or 'type' keyword");
-      }
-      catchList.push_back(exceptionTypeInfo);
+                                "can't have more than one catch all");
+      hasCatchAll = true;
     }
-    return parseAndCheckRegion();
-  };
 
-  if (parser
-          .parseCommaSeparatedList(OpAsmParser::Delimiter::Square,
-                                   parseCatchEntry, " in catch list")
-          .failed())
-    return failure();
+    mlir::Attribute exceptionRTTIAttr;
+    if (!isCatchAll && parser.parseAttribute(exceptionRTTIAttr).failed())
+      return parser.emitError(parser.getCurrentLocation(),
+                              "expected valid RTTI info attribute");
 
-  catchersAttr = parser.getBuilder().getArrayAttr(catchList);
-  return ::mlir::success();
+    catcherAttrs.push_back(isCatchAll
+                               ? cir::CatchAllAttr::get(parser.getContext())
+                               : exceptionRTTIAttr);
+
+    if (hasLSquare && isCatchAll)
+      return parser.emitError(parser.getCurrentLocation(),
+                              "catch all dosen't need RTTI info attribute");
+
+    if (hasLSquare && parser.parseRSquare().failed())
+      return parser.emitError(parser.getCurrentLocation(),
+                              "expected `]` after RTTI info attribute");
+
+    if (parseCheckedCatcherRegion().failed())
+      return mlir::failure();
+  }
+
+  if (parser.parseOptionalKeyword("unwind").succeeded()) {
+    catcherAttrs.push_back(cir::UnwindAttr::get(parser.getContext()));
+    if (parseCheckedCatcherRegion().failed())
+      return mlir::failure();
+  }
+
+  catchersAttr = parser.getBuilder().getArrayAttr(catcherAttrs);
+  return mlir::success();
 }
 
 //===----------------------------------------------------------------------===//
diff --git a/clang/test/CIR/IR/invalid-try-catch.cir b/clang/test/CIR/IR/invalid-try-catch.cir
index 57863af13d20b..40eaa7b06e3c3 100644
--- a/clang/test/CIR/IR/invalid-try-catch.cir
+++ b/clang/test/CIR/IR/invalid-try-catch.cir
@@ -6,10 +6,10 @@ cir.func dso_local @invalid_catch_without_all_or_type() {
   cir.scope {
     cir.try {
       cir.yield
-     // expected-error @below {{'cir.try' expected attribute, 'all', or 'type' keyword}}
+     // expected-error @below {{'cir.try' expected 'all' or 'type' keyword}}
     } catch [invalid_keyword {
       cir.yield
-    }]
+    }
   }
   cir.return
 }
@@ -22,13 +22,12 @@ module {
 
 cir.func dso_local @invalid_catch_rtti_type() {
   cir.scope {
+    // expected-error @below {{'cir.try' op attribute 'catch_types' failed to satisfy constraint: catch all or unwind or global view array attribute}}
     cir.try {
       cir.yield
-     // expected-error @below {{expected attribute value}}
-     // expected-error @below {{'cir.try' expected valid RTTI info attribute}}
-    } catch [type invalid_type {
+    } catch [type #cir.undef] {
       cir.yield
-    }]
+    }
   }
   cir.return
 }
@@ -41,11 +40,11 @@ module {
 
 cir.func dso_local @invalid_catch_empty_block() {
   cir.scope {
+    // expected-error @below {{'cir.try' op region #1 ('catch_regions') failed to verify constraint: region with at least 1 blocks}}
     cir.try {
       cir.yield
-    } catch [type #cir.all {
-      // expected-error @below {{'cir.try' catch region shall not be empty}}
-    }]
+    } catch all {
+    }
   }
   cir.return
 }
@@ -65,11 +64,72 @@ cir.func dso_local @invalid_catch_not_terminated() {
       cir.yield
     } 
     // expected-error @below {{'cir.try' blocks are expected to be explicitly terminated}}
-    catch [type #cir.all {
+    catch all {
        %tmp_a = cir.load %a : !cir.ptr<!s32i>, !s32i
-    }]
+    }
   }
   cir.return
 }
 
 }
+
+// -----
+
+module {
+
+cir.func dso_local @invalid_catch_multiple_catch_all() {
+  cir.scope {
+    cir.try {
+      cir.yield
+    } catch all {
+      cir.yield
+    } 
+    // expected-error @below {{op 'cir.try' can't have more than one catch all}}
+    catch all {
+      cir.yield
+    }
+  }
+  cir.return
+}
+
+}
+
+// -----
+
+module {
+
+cir.func dso_local @invalid_catch_without_type_info() {
+  cir.scope {
+    cir.try {
+      cir.yield
+    } 
+    // expected-error @below {{expected attribute value}}
+    // expected-error @below {{op 'cir.try' expected valid RTTI info attribute}}
+    catch [type] {
+      cir.yield
+    }
+  }
+  cir.return
+}
+
+}
+
+// -----
+
+module {
+
+cir.func dso_local @invalid_catch_all_with_type_info() {
+  cir.scope {
+    cir.try {
+      cir.yield
+    } 
+    // expected-error @below {{op 'cir.try' catch all dosen't need RTTI info attribute}}
+    catch [all] {
+      cir.yield
+    }
+  }
+  cir.return
+}
+
+}
+
diff --git a/clang/test/CIR/IR/try-catch.cir b/clang/test/CIR/IR/try-catch.cir
index 7bc71ff84d4ae..7becd0b559f5e 100644
--- a/clang/test/CIR/IR/try-catch.cir
+++ b/clang/test/CIR/IR/try-catch.cir
@@ -11,57 +11,57 @@ cir.func dso_local @empty_try_block_with_catch_all() {
   cir.scope {
     cir.try {
       cir.yield
-    } catch [type #cir.all {
+    } catch all {
       cir.yield
-    }]
+    }
   }
   cir.return
 }
 
-// CHECK:  cir.func dso_local @empty_try_block_with_catch_all() {
-// CHECK:    cir.scope {
-// CHECK:      cir.try {
-// CHECK:        cir.yield
-// CHECK:      } catch [type #cir.all {
-// CHECK:        cir.yield
-// CHECK:      }]
-// CHECK:    }
-// CHECK:    cir.return
-// CHECK:  }
+// CHECK: cir.func dso_local @empty_try_block_with_catch_all() {
+// CHECK:   cir.scope {
+// CHECK:     cir.try {
+// CHECK:       cir.yield
+// CHECK:     } catch all {
+// CHECK:       cir.yield
+// CHECK:     }
+// CHECK:   }
+// CHECK:   cir.return
+// CHECK: }
 
 cir.func dso_local @empty_try_block_with_catch_unwind() {
   cir.scope {
     cir.try {
       cir.yield
-    } catch [#cir.unwind {
+    } unwind {
       cir.yield
-    }]
+    }
   }
   cir.return
 }
 
 // CHECK: cir.func dso_local @empty_try_block_with_catch_unwind() {
-// CHECK:  cir.scope {
-// CHECK:    cir.try {
-// CHECK:      cir.yield
-// CHECK:    } catch [#cir.unwind {
-// CHECK:      cir.yield
-// CHECK:    }]
-// CHECK:  }
-// CHECK:  cir.return
+// CHECK:   cir.scope {
+// CHECK:     cir.try {
+// CHECK:       cir.yield
+// CHECK:     } unwind {
+// CHECK:       cir.yield
+// CHECK:     }
+// CHECK:   }
+// CHECK:   cir.return
 // CHECK: }
 
 cir.func dso_local @empty_try_block_with_catch_ist() {
   cir.scope {
     cir.try {
       cir.yield
-    } catch [type #cir.global_view<@_ZTIi> : !cir.ptr<!u8i> {
+    } catch [type #cir.global_view<@_ZTIi> : !cir.ptr<!u8i>] {
       cir.yield
-    }, type #cir.global_view<@_ZTIPKc> : !cir.ptr<!u8i> {
+    } catch [type #cir.global_view<@_ZTIPKc> : !cir.ptr<!u8i>] {
       cir.yield
-    }, #cir.unwind {
+    } unwind {
       cir.yield
-    }]
+    }
   }
   cir.return
 }
@@ -70,13 +70,13 @@ cir.func dso_local @empty_try_block_with_catch_ist() {
 // CHECK:   cir.scope {
 // CHECK:     cir.try {
 // CHECK:       cir.yield
-// CHECK:     } catch [type #cir.global_view<@_ZTIi> : !cir.ptr<!u8i> {
+// CHECK:     } catch [type #cir.global_view<@_ZTIi> : !cir.ptr<!u8i>] {
 // CHECK:       cir.yield
-// CHECK:     }, type #cir.global_view<@_ZTIPKc> : !cir.ptr<!u8i> {
+// CHECK:     } catch [type #cir.global_view<@_ZTIPKc> : !cir.ptr<!u8i>] {
 // CHECK:       cir.yield
-// CHECK:     }, #cir.unwind {
+// CHECK:     } unwind {
 // CHECK:       cir.yield
-// CHECK:     }]
+// CHECK:     }
 // CHECK:   }
 // CHECK:   cir.return
 // CHECK: }

>From 53690902122b9e1d69dc579e5e5eaf6a8a69800f Mon Sep 17 00:00:00 2001
From: Amr Hesham <amr96 at programmer.net>
Date: Sun, 12 Oct 2025 17:44:44 +0200
Subject: [PATCH 5/7] Add error message for using unwind with catch all

---
 clang/lib/CIR/Dialect/IR/CIRDialect.cpp |  4 ++++
 clang/test/CIR/IR/invalid-try-catch.cir | 23 ++++++++++++++++++++++-
 2 files changed, 26 insertions(+), 1 deletion(-)

diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
index 1ff0a784e4eda..3733ca1cbd777 100644
--- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
@@ -3023,6 +3023,10 @@ parseCatchRegions(mlir::OpAsmParser &parser,
   }
 
   if (parser.parseOptionalKeyword("unwind").succeeded()) {
+    if (hasCatchAll)
+      return parser.emitError(parser.getCurrentLocation(),
+                              "unwind can't be used with catch all");
+
     catcherAttrs.push_back(cir::UnwindAttr::get(parser.getContext()));
     if (parseCheckedCatcherRegion().failed())
       return mlir::failure();
diff --git a/clang/test/CIR/IR/invalid-try-catch.cir b/clang/test/CIR/IR/invalid-try-catch.cir
index 40eaa7b06e3c3..4c4187d346846 100644
--- a/clang/test/CIR/IR/invalid-try-catch.cir
+++ b/clang/test/CIR/IR/invalid-try-catch.cir
@@ -122,7 +122,7 @@ cir.func dso_local @invalid_catch_all_with_type_info() {
   cir.scope {
     cir.try {
       cir.yield
-    } 
+    }
     // expected-error @below {{op 'cir.try' catch all dosen't need RTTI info attribute}}
     catch [all] {
       cir.yield
@@ -133,3 +133,24 @@ cir.func dso_local @invalid_catch_all_with_type_info() {
 
 }
 
+// -----
+
+module {
+
+cir.func dso_local @invalid_unwind_with_catch_all() {
+  cir.scope {
+    cir.try {
+      cir.yield
+    }
+    catch all {
+      cir.yield
+    }
+    // expected-error @below {{op 'cir.try' unwind can't be used with catch all}}
+    unwind {
+
+    }
+  }
+  cir.return
+}
+
+}

>From 01e63fb8456a669f972ce571d6934c2077bb7b90 Mon Sep 17 00:00:00 2001
From: Amr Hesham <amr96 at programmer.net>
Date: Mon, 13 Oct 2025 19:55:58 +0200
Subject: [PATCH 6/7] Rename catch_regions to handlers to act as general eh
 regions

---
 clang/include/clang/CIR/Dialect/IR/CIROps.td | 4 ++--
 clang/lib/CIR/Dialect/IR/CIRDialect.cpp      | 4 ++--
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index a321ef2ceb41d..28cf3292c083d 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -4371,14 +4371,14 @@ def CIR_TryOp : CIR_Op<"try",[
 
   let regions = (region
     AnyRegion:$try_region,
-    VariadicRegion<MinSizedRegion<1>>:$catch_regions
+    VariadicRegion<MinSizedRegion<1>>:$handlers
   );
 
   let assemblyFormat = [{
     (`synthetic` $synthetic^)?
     (`cleanup` $cleanup^)?
     $try_region
-    custom<CatchRegions>($catch_regions, $catch_types)
+    custom<CatchRegions>($handlers, $catch_types)
     attr-dict
   }];
 
diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
index 3733ca1cbd777..ab2a1156c9f22 100644
--- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
@@ -2931,8 +2931,8 @@ void cir::TryOp::getSuccessorRegions(
 
   // TODO(CIR): If we know a target function never throws a specific type, we
   // can remove the catch handler.
-  for (mlir::Region &region : this->getCatchRegions())
-    regions.push_back(mlir::RegionSuccessor(&region));
+  for (mlir::Region &handler : this->getHandlers())
+    regions.push_back(mlir::RegionSuccessor(&handler));
 }
 
 static void printCatchRegions(mlir::OpAsmPrinter &printer, cir::TryOp op,

>From 905b0dbc8e71f6ee07690ca61b64f1d49401f060 Mon Sep 17 00:00:00 2001
From: Amr Hesham <amr96 at programmer.net>
Date: Wed, 15 Oct 2025 18:55:47 +0200
Subject: [PATCH 7/7] Address code review comments

---
 .../CIR/Dialect/IR/CIRAttrConstraints.td      |  5 +--
 clang/include/clang/CIR/Dialect/IR/CIROps.td  | 13 +++---
 clang/lib/CIR/Dialect/IR/CIRDialect.cpp       | 42 ++++++++++---------
 clang/test/CIR/IR/invalid-try-catch.cir       |  4 +-
 4 files changed, 33 insertions(+), 31 deletions(-)

diff --git a/clang/include/clang/CIR/Dialect/IR/CIRAttrConstraints.td b/clang/include/clang/CIR/Dialect/IR/CIRAttrConstraints.td
index bab847ef621bf..2548d464fb07f 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIRAttrConstraints.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIRAttrConstraints.td
@@ -61,7 +61,7 @@ def CIR_AnyIntOrGlobalViewAttr
   string cppType = "::mlir::TypedAttr";
 }
 
-def CIR_AnyGlobalViewOrCatchAllOrUnwindAttr
+def CIR_TryHandlerAttr
     : AnyAttrOf<[CIR_AnyGlobalViewAttr, CIR_AnyCatchAllAttr, CIR_AnyUnwindAttr],
                 "catch all or unwind or global view attribute"> {
   string cppType = "::mlir::TypedAttr";
@@ -79,8 +79,7 @@ def CIR_IntOrGlobalViewArrayAttr : TypedArrayAttrBase<CIR_AnyIntOrGlobalViewAttr
   string cppType = "::mlir::ArrayAttr";
 }
 
-def CIR_GlobalViewOrCatchAllOrUnwindArrayAttr
-    : TypedArrayAttrBase<CIR_AnyGlobalViewOrCatchAllOrUnwindAttr,
+def CIR_TryHandlerArrayAttr : TypedArrayAttrBase<CIR_TryHandlerAttr,
                          "catch all or unwind or global view array attribute">;
 
 #endif // CLANG_CIR_DIALECT_IR_CIRATTRCONSTRAINTS_TD
diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index 28cf3292c083d..4b26f814cbbe9 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -4366,19 +4366,19 @@ def CIR_TryOp : CIR_Op<"try",[
   let arguments = (ins
     UnitAttr:$synthetic,
     UnitAttr:$cleanup,
-    CIR_GlobalViewOrCatchAllOrUnwindArrayAttr:$catch_types
+    CIR_TryHandlerArrayAttr:$handler_types
   );
 
   let regions = (region
     AnyRegion:$try_region,
-    VariadicRegion<MinSizedRegion<1>>:$handlers
+    VariadicRegion<MinSizedRegion<1>>:$handler_regions
   );
 
   let assemblyFormat = [{
     (`synthetic` $synthetic^)?
     (`cleanup` $cleanup^)?
     $try_region
-    custom<CatchRegions>($handlers, $catch_types)
+    custom<TryHandlerRegions>($handler_regions, $handler_types)
     attr-dict
   }];
 
@@ -4387,10 +4387,11 @@ def CIR_TryOp : CIR_Op<"try",[
       "llvm::function_ref<void(mlir::OpBuilder &, "
         "mlir::Location)>":$tryBuilder,
       "llvm::function_ref<void(mlir::OpBuilder &, mlir::Location, "
-        "mlir::OperationState &)>":$catchBuilder),
+        "mlir::OperationState &)>":$handlersBuilder),
     [{
       assert(tryBuilder && "expected builder callback for 'cir.try' body");
-      assert(catchBuilder && "expected builder callback for 'catch' body");
+      assert(handlersBuilder
+        && "expected builder callback for 'handlers' body");
 
       OpBuilder::InsertionGuard guard($_builder);
 
@@ -4400,7 +4401,7 @@ def CIR_TryOp : CIR_Op<"try",[
       // Create try body region and set insertion point
       $_builder.createBlock(tryBodyRegion);
       tryBuilder($_builder, $_state.location);
-      catchBuilder($_builder, $_state.location, $_state);
+      handlersBuilder($_builder, $_state.location, $_state);
     }]>
   ];
 
diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
index ab2a1156c9f22..0712de2d2f182 100644
--- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
@@ -2931,47 +2931,49 @@ void cir::TryOp::getSuccessorRegions(
 
   // TODO(CIR): If we know a target function never throws a specific type, we
   // can remove the catch handler.
-  for (mlir::Region &handler : this->getHandlers())
-    regions.push_back(mlir::RegionSuccessor(&handler));
+  for (mlir::Region &handlerRegion : this->getHandlerRegions())
+    regions.push_back(mlir::RegionSuccessor(&handlerRegion));
 }
 
-static void printCatchRegions(mlir::OpAsmPrinter &printer, cir::TryOp op,
-                              mlir::MutableArrayRef<mlir::Region> regions,
-                              mlir::ArrayAttr catchersAttr) {
-  if (!catchersAttr)
+static void
+printTryHandlerRegions(mlir::OpAsmPrinter &printer, cir::TryOp op,
+                       mlir::MutableArrayRef<mlir::Region> handlerRegions,
+                       mlir::ArrayAttr handlerTypes) {
+  if (!handlerTypes)
     return;
 
-  for (const auto [catcherIdx, catcherAttr] : llvm::enumerate(catchersAttr)) {
-    if (catcherIdx)
+  for (const auto [typeIdx, typeAttr] : llvm::enumerate(handlerTypes)) {
+    if (typeIdx)
       printer << " ";
 
-    if (mlir::isa<cir::CatchAllAttr>(catcherAttr)) {
+    if (mlir::isa<cir::CatchAllAttr>(typeAttr)) {
       printer << "catch all ";
-    } else if (mlir::isa<cir::UnwindAttr>(catcherAttr)) {
+    } else if (mlir::isa<cir::UnwindAttr>(typeAttr)) {
       printer << "unwind ";
     } else {
       printer << "catch [type ";
-      printer.printAttribute(catcherAttr);
+      printer.printAttribute(typeAttr);
       printer << "] ";
     }
 
-    printer.printRegion(regions[catcherIdx], /*printEntryBLockArgs=*/false,
+    printer.printRegion(handlerRegions[typeIdx],
+                        /*printEntryBLockArgs=*/false,
                         /*printBlockTerminators=*/true);
   }
 }
 
-static mlir::ParseResult
-parseCatchRegions(mlir::OpAsmParser &parser,
-                  llvm::SmallVectorImpl<std::unique_ptr<mlir::Region>> &regions,
-                  mlir::ArrayAttr &catchersAttr) {
+static mlir::ParseResult parseTryHandlerRegions(
+    mlir::OpAsmParser &parser,
+    llvm::SmallVectorImpl<std::unique_ptr<mlir::Region>> &handlerRegions,
+    mlir::ArrayAttr &handlerTypes) {
 
   auto parseCheckedCatcherRegion = [&]() -> mlir::ParseResult {
-    regions.emplace_back(new mlir::Region);
+    handlerRegions.emplace_back(new mlir::Region);
 
-    mlir::Region &currRegion = *regions.back();
+    mlir::Region &currRegion = *handlerRegions.back();
     mlir::SMLoc regionLoc = parser.getCurrentLocation();
     if (parser.parseRegion(currRegion)) {
-      regions.clear();
+      handlerRegions.clear();
       return failure();
     }
 
@@ -3032,7 +3034,7 @@ parseCatchRegions(mlir::OpAsmParser &parser,
       return mlir::failure();
   }
 
-  catchersAttr = parser.getBuilder().getArrayAttr(catcherAttrs);
+  handlerTypes = parser.getBuilder().getArrayAttr(catcherAttrs);
   return mlir::success();
 }
 
diff --git a/clang/test/CIR/IR/invalid-try-catch.cir b/clang/test/CIR/IR/invalid-try-catch.cir
index 4c4187d346846..04a4d2543b8e1 100644
--- a/clang/test/CIR/IR/invalid-try-catch.cir
+++ b/clang/test/CIR/IR/invalid-try-catch.cir
@@ -22,7 +22,7 @@ module {
 
 cir.func dso_local @invalid_catch_rtti_type() {
   cir.scope {
-    // expected-error @below {{'cir.try' op attribute 'catch_types' failed to satisfy constraint: catch all or unwind or global view array attribute}}
+    // expected-error @below {{'cir.try' op attribute 'handler_types' failed to satisfy constraint: catch all or unwind or global view array attribute}}
     cir.try {
       cir.yield
     } catch [type #cir.undef] {
@@ -40,7 +40,7 @@ module {
 
 cir.func dso_local @invalid_catch_empty_block() {
   cir.scope {
-    // expected-error @below {{'cir.try' op region #1 ('catch_regions') failed to verify constraint: region with at least 1 blocks}}
+    // expected-error @below {{'cir.try' op region #1 ('handler_regions') failed to verify constraint: region with at least 1 blocks}}
     cir.try {
       cir.yield
     } catch all {



More information about the cfe-commits mailing list