[clang] [CIR] Introduce cir.construct_catch_param (PR #195283)

Andy Kaylor via cfe-commits cfe-commits at lists.llvm.org
Mon May 4 11:48:28 PDT 2026


https://github.com/andykaylor updated https://github.com/llvm/llvm-project/pull/195283

>From 269fc8648a11db1a07640218c1c7d9e6a188ef56 Mon Sep 17 00:00:00 2001
From: Andy Kaylor <akaylor at nvidia.com>
Date: Thu, 30 Apr 2026 17:30:02 -0700
Subject: [PATCH 1/2] [CIR] Introduce cir.construct_catch_param

Add a new CIR operation, `cir.construct_catch_param`, which abstractly
represents the target-specific operations that must performed before
`cir.begin_catch` to bind an in-flight exception object to the local
alloca for a catch parameter.

Generation and lowering of this operation is deferred to follow-up changes.

Assisted-by: Cursor / claude-opus-4.7-thinking-xhigh
---
 clang/include/clang/CIR/Dialect/IR/CIROps.td  |  51 +++++
 clang/lib/CIR/Dialect/IR/CIRDialect.cpp       |  39 +++-
 clang/test/CIR/IR/construct-catch-param.cir   |  63 ++++++
 .../CIR/IR/invalid-construct-catch-param.cir  | 212 ++++++++++++++++++
 4 files changed, 364 insertions(+), 1 deletion(-)
 create mode 100644 clang/test/CIR/IR/construct-catch-param.cir
 create mode 100644 clang/test/CIR/IR/invalid-construct-catch-param.cir

diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index 97d623ba5e6d9..bf0b895a55d4c 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -7704,6 +7704,57 @@ def CIR_InitCatchParamOp : CIR_Op<"init_catch_param"> {
   let hasLLVMLowering = false;
 }
 
+//===----------------------------------------------------------------------===//
+// EH Operations: ConstructCatchParamOp
+//===----------------------------------------------------------------------===//
+
+def CIR_ConstructCatchParamOp : CIR_Op<"construct_catch_param", [
+    DeclareOpInterfaceMethods<SymbolUserOpInterface>
+  ]> {
+  let summary = "Construct a catch parameter from the in-flight exception";
+  let description = [{
+    `cir.construct_catch_param` abstractly represents the target-specific work
+    that must be performed before `cir.begin_catch` to bind the in-flight
+    exception object to the local alloca used for the catch parameter.
+
+    For example, for non-pointer, non-reference catch parameters whose type has
+    a non-trivial copy constructor, the Itanium C++ ABI requires
+    calling `__cxa_get_exception_ptr` to obtain the adjusted exception pointer
+    and then invoking the catch parameter's copy constructor to create a local
+    copy of the object before `__cxa_begin_catch` is invoked.
+
+    This operation takes a `!cir.eh_token` that represents the in-flight
+    exception and the alloca value that is used for the local copy of the
+    exception object. The `copy_fn` attribute is a flat symbol reference to a
+    `cir.func` thunk that copies the exception object to a local alloca value.
+
+    This operation is replaced with a target-specific representation during
+    the EHABI lowering pass. For some targets, such as the Microsoft ABI,
+    this operation is a no-op and is simply erased during lowering.
+
+    Example:
+
+    ```
+    cir.construct_catch_param non_trivial_copy %eh_token to %param_addr
+      copy_fn = @__clang_cir_catch_init_T : !cir.eh_token, !cir.ptr<!rec_T>
+    ```
+  }];
+
+  let arguments = (ins
+      CIR_EhTokenType:$eh_token,
+      CIR_PointerType:$param_addr,
+      CIR_InitCatchKind:$kind,
+      FlatSymbolRefAttr:$copy_fn
+  );
+
+  let assemblyFormat = [{
+    $kind $eh_token `to` $param_addr `:` qualified(type($eh_token)) `,`
+      qualified(type($param_addr)) `,` `copy_fn` `=` $copy_fn attr-dict
+  }];
+
+  let hasLLVMLowering = false;
+}
+
 //===----------------------------------------------------------------------===//
 // Atomic operations
 //===----------------------------------------------------------------------===//
diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
index 7386819d8fce9..9bf750eb9a125 100644
--- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
@@ -4138,7 +4138,15 @@ LogicalResult cir::TryOp::verify() {
     if (mlir::isa<cir::UnwindAttr>(typeAttr))
       continue;
 
-    if (entryBlock.empty() || !mlir::isa<cir::BeginCatchOp>(entryBlock.front()))
+    // A catch handler region must start with cir.begin_catch, optionally
+    // preceded by a single cir.construct_catch_param that performs any
+    // pre-begin_catch initialization for the catch parameter.
+    if (entryBlock.empty())
+      return emitOpError("catch handler region must not be empty");
+    mlir::Operation *firstOp = &entryBlock.front();
+    if (mlir::isa<cir::ConstructCatchParamOp>(firstOp))
+      firstOp = firstOp->getNextNode();
+    if (!firstOp || !mlir::isa<cir::BeginCatchOp>(firstOp))
       return emitOpError(
           "catch handler region must start with 'cir.begin_catch'");
   }
@@ -4285,6 +4293,35 @@ cir::EhTypeIdOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
   return success();
 }
 
+//===----------------------------------------------------------------------===//
+// ConstructCatchParamOp
+//===----------------------------------------------------------------------===//
+
+LogicalResult cir::ConstructCatchParamOp::verifySymbolUses(
+    SymbolTableCollection &symbolTable) {
+  auto fn =
+      symbolTable.lookupNearestSymbolFrom<cir::FuncOp>(*this, getCopyFnAttr());
+  if (!fn)
+    return emitOpError("'")
+           << getCopyFn() << "' does not reference a valid cir.func";
+
+  cir::FuncType fnType = fn.getFunctionType();
+  if (fnType.getNumInputs() != 2 || !fnType.hasVoidReturn())
+    return emitOpError("catch-init copy_fn must take two pointer arguments and "
+                       "return void");
+
+  if (fnType.getInput(0) != getParamAddr().getType())
+    return emitOpError("first argument of catch-init copy_fn must match the "
+                       "type of 'param_addr'");
+
+  if (fnType.getInput(1) != getParamAddr().getType())
+    return emitOpError(
+        "second argument of catch-init copy_fn must be a pointer "
+        "to the catch type");
+
+  return success();
+}
+
 //===----------------------------------------------------------------------===//
 // EhDispatchOp
 //===----------------------------------------------------------------------===//
diff --git a/clang/test/CIR/IR/construct-catch-param.cir b/clang/test/CIR/IR/construct-catch-param.cir
new file mode 100644
index 0000000000000..609de91461c10
--- /dev/null
+++ b/clang/test/CIR/IR/construct-catch-param.cir
@@ -0,0 +1,63 @@
+// RUN: cir-opt %s --verify-roundtrip | FileCheck %s
+
+!s8i = !cir.int<s, 8>
+!u8i = !cir.int<u, 8>
+!void = !cir.void
+!rec_E = !cir.record<struct "E" padded {!u8i}>
+
+module {
+
+cir.global "private" constant external @_ZTI1E : !cir.ptr<!u8i>
+
+// A CIRGen-style catch-init helper thunk: takes (dest, src) and returns void.
+// `cir.construct_catch_param` references this function via its `copy_fn`
+// attribute; the verifier checks the symbol resolves and matches the
+// (T*, T*) -> void signature.
+cir.func linkonce_odr hidden @__clang_cir_catch_copy__ZTS1E(
+    %arg0: !cir.ptr<!rec_E>, %arg1: !cir.ptr<!rec_E>) {
+  cir.return
+}
+
+// CHECK: cir.func linkonce_odr hidden @__clang_cir_catch_copy__ZTS1E(
+// CHECK:   cir.return
+// CHECK: }
+
+// Positive shape: a `cir.try` whose typed catch handler region begins with
+// `cir.construct_catch_param` (referring to an alloca defined in the
+// enclosing scope) followed by `cir.begin_catch`.
+cir.func @construct_catch_param_basic() {
+  cir.scope {
+    %param = cir.alloca !rec_E, !cir.ptr<!rec_E>, ["e"] {alignment = 1 : i64}
+    cir.try {
+      cir.yield
+    } catch [type #cir.global_view<@_ZTI1E> : !cir.ptr<!u8i>]
+        (%eh_token: !cir.eh_token) {
+      cir.construct_catch_param non_trivial_copy %eh_token to %param
+        : !cir.eh_token, !cir.ptr<!rec_E>,
+          copy_fn = @__clang_cir_catch_copy__ZTS1E
+      %catch_token, %exn_ptr = cir.begin_catch %eh_token
+        : !cir.eh_token -> (!cir.catch_token, !cir.ptr<!void>)
+      cir.cleanup.scope {
+        cir.yield
+      } cleanup eh {
+        cir.end_catch %catch_token : !cir.catch_token
+        cir.yield
+      }
+      cir.yield
+    }
+  }
+  cir.return
+}
+
+// CHECK-LABEL: cir.func @construct_catch_param_basic()
+// CHECK:         %[[E:.*]] = cir.alloca !rec_E, !cir.ptr<!rec_E>, ["e"]
+// CHECK:         cir.try {
+// CHECK:           cir.yield
+// CHECK:         } catch [type #cir.global_view<@_ZTI1E> : !cir.ptr<!u8i>]
+// CHECK-SAME:        (%[[EH:.*]]: !cir.eh_token) {
+// CHECK:           cir.construct_catch_param non_trivial_copy %[[EH]] to %[[E]]
+// CHECK-SAME:        : !cir.eh_token, !cir.ptr<!rec_E>,
+// CHECK-SAME:          copy_fn = @__clang_cir_catch_copy__ZTS1E
+// CHECK:           cir.begin_catch %[[EH]]
+
+}
diff --git a/clang/test/CIR/IR/invalid-construct-catch-param.cir b/clang/test/CIR/IR/invalid-construct-catch-param.cir
new file mode 100644
index 0000000000000..8a22d590589f6
--- /dev/null
+++ b/clang/test/CIR/IR/invalid-construct-catch-param.cir
@@ -0,0 +1,212 @@
+// RUN: cir-opt %s -verify-diagnostics -split-input-file
+
+!u8i = !cir.int<u, 8>
+!s32i = !cir.int<s, 32>
+!void = !cir.void
+!rec_E = !cir.record<struct "E" padded {!u8i}>
+
+module {
+
+cir.global "private" constant external @_ZTI1E : !cir.ptr<!u8i>
+
+cir.func @copy_fn_missing() {
+  cir.scope {
+    %p = cir.alloca !rec_E, !cir.ptr<!rec_E>, ["e"] {alignment = 1 : i64}
+    cir.try {
+      cir.yield
+    } catch [type #cir.global_view<@_ZTI1E> : !cir.ptr<!u8i>]
+        (%eh_token: !cir.eh_token) {
+      // expected-error @below {{'__not_a_func' does not reference a valid cir.func}}
+      cir.construct_catch_param non_trivial_copy %eh_token to %p
+        : !cir.eh_token, !cir.ptr<!rec_E>, copy_fn = @__not_a_func
+      %catch_token, %exn_ptr = cir.begin_catch %eh_token
+        : !cir.eh_token -> (!cir.catch_token, !cir.ptr<!void>)
+      cir.end_catch %catch_token : !cir.catch_token
+      cir.yield
+    }
+  }
+  cir.return
+}
+
+}
+
+// -----
+
+!u8i = !cir.int<u, 8>
+!void = !cir.void
+!rec_E = !cir.record<struct "E" padded {!u8i}>
+
+module {
+
+cir.global "private" constant external @_ZTI1E : !cir.ptr<!u8i>
+
+// copy_fn takes only one argument (should be two).
+cir.func private @bad_copy_fn_arity(!cir.ptr<!rec_E>)
+
+cir.func @copy_fn_wrong_arity() {
+  cir.scope {
+    %p = cir.alloca !rec_E, !cir.ptr<!rec_E>, ["e"] {alignment = 1 : i64}
+    cir.try {
+      cir.yield
+    } catch [type #cir.global_view<@_ZTI1E> : !cir.ptr<!u8i>]
+        (%eh_token: !cir.eh_token) {
+      // expected-error @below {{catch-init copy_fn must take two pointer arguments and return void}}
+      cir.construct_catch_param non_trivial_copy %eh_token to %p
+        : !cir.eh_token, !cir.ptr<!rec_E>, copy_fn = @bad_copy_fn_arity
+      %catch_token, %exn_ptr = cir.begin_catch %eh_token
+        : !cir.eh_token -> (!cir.catch_token, !cir.ptr<!void>)
+      cir.end_catch %catch_token : !cir.catch_token
+      cir.yield
+    }
+  }
+  cir.return
+}
+
+}
+
+// -----
+
+!u8i = !cir.int<u, 8>
+!s32i = !cir.int<s, 32>
+!void = !cir.void
+!rec_E = !cir.record<struct "E" padded {!u8i}>
+
+module {
+
+cir.global "private" constant external @_ZTI1E : !cir.ptr<!u8i>
+
+// copy_fn returns a non-void type.
+cir.func private @bad_copy_fn_ret(
+    !cir.ptr<!rec_E>, !cir.ptr<!rec_E>) -> !s32i
+
+cir.func @copy_fn_non_void_return() {
+  cir.scope {
+    %p = cir.alloca !rec_E, !cir.ptr<!rec_E>, ["e"] {alignment = 1 : i64}
+    cir.try {
+      cir.yield
+    } catch [type #cir.global_view<@_ZTI1E> : !cir.ptr<!u8i>]
+        (%eh_token: !cir.eh_token) {
+      // expected-error @below {{catch-init copy_fn must take two pointer arguments and return void}}
+      cir.construct_catch_param non_trivial_copy %eh_token to %p
+        : !cir.eh_token, !cir.ptr<!rec_E>, copy_fn = @bad_copy_fn_ret
+      %catch_token, %exn_ptr = cir.begin_catch %eh_token
+        : !cir.eh_token -> (!cir.catch_token, !cir.ptr<!void>)
+      cir.end_catch %catch_token : !cir.catch_token
+      cir.yield
+    }
+  }
+  cir.return
+}
+
+}
+
+// -----
+
+!u8i = !cir.int<u, 8>
+!s32i = !cir.int<s, 32>
+!void = !cir.void
+!rec_E = !cir.record<struct "E" padded {!u8i}>
+
+module {
+
+cir.global "private" constant external @_ZTI1E : !cir.ptr<!u8i>
+
+// copy_fn's first parameter does not match the catch parameter pointer
+// type (!cir.ptr<!s32i> vs !cir.ptr<!rec_E>).
+cir.func private @bad_copy_fn_first_arg(
+    !cir.ptr<!s32i>, !cir.ptr<!rec_E>)
+
+cir.func @copy_fn_first_arg_mismatch() {
+  cir.scope {
+    %p = cir.alloca !rec_E, !cir.ptr<!rec_E>, ["e"] {alignment = 1 : i64}
+    cir.try {
+      cir.yield
+    } catch [type #cir.global_view<@_ZTI1E> : !cir.ptr<!u8i>]
+        (%eh_token: !cir.eh_token) {
+      // expected-error @below {{first argument of catch-init copy_fn must match the type of 'param_addr'}}
+      cir.construct_catch_param non_trivial_copy %eh_token to %p
+        : !cir.eh_token, !cir.ptr<!rec_E>, copy_fn = @bad_copy_fn_first_arg
+      %catch_token, %exn_ptr = cir.begin_catch %eh_token
+        : !cir.eh_token -> (!cir.catch_token, !cir.ptr<!void>)
+      cir.end_catch %catch_token : !cir.catch_token
+      cir.yield
+    }
+  }
+  cir.return
+}
+
+}
+
+// -----
+
+!u8i = !cir.int<u, 8>
+!s32i = !cir.int<s, 32>
+!void = !cir.void
+!rec_E = !cir.record<struct "E" padded {!u8i}>
+
+module {
+
+cir.global "private" constant external @_ZTI1E : !cir.ptr<!u8i>
+
+// copy_fn's second parameter does not match the catch parameter pointer
+// type (the source argument must also be !cir.ptr<!rec_E>).
+cir.func private @bad_copy_fn_second_arg(
+    !cir.ptr<!rec_E>, !cir.ptr<!s32i>)
+
+cir.func @copy_fn_second_arg_mismatch() {
+  cir.scope {
+    %p = cir.alloca !rec_E, !cir.ptr<!rec_E>, ["e"] {alignment = 1 : i64}
+    cir.try {
+      cir.yield
+    } catch [type #cir.global_view<@_ZTI1E> : !cir.ptr<!u8i>]
+        (%eh_token: !cir.eh_token) {
+      // expected-error @below {{second argument of catch-init copy_fn must be a pointer to the catch type}}
+      cir.construct_catch_param non_trivial_copy %eh_token to %p
+        : !cir.eh_token, !cir.ptr<!rec_E>, copy_fn = @bad_copy_fn_second_arg
+      %catch_token, %exn_ptr = cir.begin_catch %eh_token
+        : !cir.eh_token -> (!cir.catch_token, !cir.ptr<!void>)
+      cir.end_catch %catch_token : !cir.catch_token
+      cir.yield
+    }
+  }
+  cir.return
+}
+
+}
+
+// -----
+
+!u8i = !cir.int<u, 8>
+!void = !cir.void
+!rec_E = !cir.record<struct "E" padded {!u8i}>
+
+module {
+
+cir.global "private" constant external @_ZTI1E : !cir.ptr<!u8i>
+
+cir.func linkonce_odr hidden @__clang_cir_catch_copy__ZTS1E(
+    %arg0: !cir.ptr<!rec_E>, %arg1: !cir.ptr<!rec_E>) {
+  cir.return
+}
+
+// `cir.construct_catch_param` itself verifies, but `cir.try` rejects the
+// catch handler because the op after `cir.construct_catch_param` is not
+// `cir.begin_catch`.
+cir.func @construct_not_followed_by_begin_catch() {
+  cir.scope {
+    %p = cir.alloca !rec_E, !cir.ptr<!rec_E>, ["e"] {alignment = 1 : i64}
+    // expected-error @below {{catch handler region must start with 'cir.begin_catch'}}
+    cir.try {
+      cir.yield
+    } catch [type #cir.global_view<@_ZTI1E> : !cir.ptr<!u8i>]
+        (%eh_token: !cir.eh_token) {
+      cir.construct_catch_param non_trivial_copy %eh_token to %p
+        : !cir.eh_token, !cir.ptr<!rec_E>,
+          copy_fn = @__clang_cir_catch_copy__ZTS1E
+      cir.yield
+    }
+  }
+  cir.return
+}
+
+}

>From 5ef4b86313634922e161f88be1a144bf64096022 Mon Sep 17 00:00:00 2001
From: Andy Kaylor <akaylor at nvidia.com>
Date: Mon, 4 May 2026 11:48:00 -0700
Subject: [PATCH 2/2] Address review feedback

---
 clang/include/clang/CIR/Dialect/IR/CIROps.td  |  8 +++---
 clang/lib/CIR/Dialect/IR/CIRDialect.cpp       |  2 +-
 clang/test/CIR/IR/construct-catch-param.cir   |  6 ++---
 .../CIR/IR/invalid-construct-catch-param.cir  | 25 +++++++++----------
 4 files changed, 19 insertions(+), 22 deletions(-)

diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index bf0b895a55d4c..8ead23c83cb50 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -7717,7 +7717,7 @@ def CIR_ConstructCatchParamOp : CIR_Op<"construct_catch_param", [
     that must be performed before `cir.begin_catch` to bind the in-flight
     exception object to the local alloca used for the catch parameter.
 
-    For example, for non-pointer, non-reference catch parameters whose type has
+    For example: for non-pointer, non-reference catch parameters whose type has
     a non-trivial copy constructor, the Itanium C++ ABI requires
     calling `__cxa_get_exception_ptr` to obtain the adjusted exception pointer
     and then invoking the catch parameter's copy constructor to create a local
@@ -7736,7 +7736,7 @@ def CIR_ConstructCatchParamOp : CIR_Op<"construct_catch_param", [
 
     ```
     cir.construct_catch_param non_trivial_copy %eh_token to %param_addr
-      copy_fn = @__clang_cir_catch_init_T : !cir.eh_token, !cir.ptr<!rec_T>
+      using @__clang_cir_catch_init_T : !cir.ptr<!rec_T>
     ```
   }];
 
@@ -7748,8 +7748,8 @@ def CIR_ConstructCatchParamOp : CIR_Op<"construct_catch_param", [
   );
 
   let assemblyFormat = [{
-    $kind $eh_token `to` $param_addr `:` qualified(type($eh_token)) `,`
-      qualified(type($param_addr)) `,` `copy_fn` `=` $copy_fn attr-dict
+    $kind $eh_token `to` $param_addr `using` $copy_fn `:`
+      qualified(type($param_addr)) attr-dict
   }];
 
   let hasLLVMLowering = false;
diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
index 9bf750eb9a125..47ccb291ea745 100644
--- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
@@ -4144,7 +4144,7 @@ LogicalResult cir::TryOp::verify() {
     if (entryBlock.empty())
       return emitOpError("catch handler region must not be empty");
     mlir::Operation *firstOp = &entryBlock.front();
-    if (mlir::isa<cir::ConstructCatchParamOp>(firstOp))
+    if (mlir::isa_and_present<cir::ConstructCatchParamOp>(firstOp))
       firstOp = firstOp->getNextNode();
     if (!firstOp || !mlir::isa<cir::BeginCatchOp>(firstOp))
       return emitOpError(
diff --git a/clang/test/CIR/IR/construct-catch-param.cir b/clang/test/CIR/IR/construct-catch-param.cir
index 609de91461c10..805d917aef30b 100644
--- a/clang/test/CIR/IR/construct-catch-param.cir
+++ b/clang/test/CIR/IR/construct-catch-param.cir
@@ -33,8 +33,7 @@ cir.func @construct_catch_param_basic() {
     } catch [type #cir.global_view<@_ZTI1E> : !cir.ptr<!u8i>]
         (%eh_token: !cir.eh_token) {
       cir.construct_catch_param non_trivial_copy %eh_token to %param
-        : !cir.eh_token, !cir.ptr<!rec_E>,
-          copy_fn = @__clang_cir_catch_copy__ZTS1E
+        using @__clang_cir_catch_copy__ZTS1E : !cir.ptr<!rec_E>
       %catch_token, %exn_ptr = cir.begin_catch %eh_token
         : !cir.eh_token -> (!cir.catch_token, !cir.ptr<!void>)
       cir.cleanup.scope {
@@ -56,8 +55,7 @@ cir.func @construct_catch_param_basic() {
 // CHECK:         } catch [type #cir.global_view<@_ZTI1E> : !cir.ptr<!u8i>]
 // CHECK-SAME:        (%[[EH:.*]]: !cir.eh_token) {
 // CHECK:           cir.construct_catch_param non_trivial_copy %[[EH]] to %[[E]]
-// CHECK-SAME:        : !cir.eh_token, !cir.ptr<!rec_E>,
-// CHECK-SAME:          copy_fn = @__clang_cir_catch_copy__ZTS1E
+// CHECK-SAME:        using @__clang_cir_catch_copy__ZTS1E : !cir.ptr<!rec_E>
 // CHECK:           cir.begin_catch %[[EH]]
 
 }
diff --git a/clang/test/CIR/IR/invalid-construct-catch-param.cir b/clang/test/CIR/IR/invalid-construct-catch-param.cir
index 8a22d590589f6..6704b549e1ecd 100644
--- a/clang/test/CIR/IR/invalid-construct-catch-param.cir
+++ b/clang/test/CIR/IR/invalid-construct-catch-param.cir
@@ -17,8 +17,8 @@ cir.func @copy_fn_missing() {
     } catch [type #cir.global_view<@_ZTI1E> : !cir.ptr<!u8i>]
         (%eh_token: !cir.eh_token) {
       // expected-error @below {{'__not_a_func' does not reference a valid cir.func}}
-      cir.construct_catch_param non_trivial_copy %eh_token to %p
-        : !cir.eh_token, !cir.ptr<!rec_E>, copy_fn = @__not_a_func
+      cir.construct_catch_param non_trivial_copy %eh_token to %p using @__not_a_func
+        : !cir.ptr<!rec_E>
       %catch_token, %exn_ptr = cir.begin_catch %eh_token
         : !cir.eh_token -> (!cir.catch_token, !cir.ptr<!void>)
       cir.end_catch %catch_token : !cir.catch_token
@@ -51,8 +51,8 @@ cir.func @copy_fn_wrong_arity() {
     } catch [type #cir.global_view<@_ZTI1E> : !cir.ptr<!u8i>]
         (%eh_token: !cir.eh_token) {
       // expected-error @below {{catch-init copy_fn must take two pointer arguments and return void}}
-      cir.construct_catch_param non_trivial_copy %eh_token to %p
-        : !cir.eh_token, !cir.ptr<!rec_E>, copy_fn = @bad_copy_fn_arity
+      cir.construct_catch_param non_trivial_copy %eh_token to %p using @bad_copy_fn_arity
+        : !cir.ptr<!rec_E>
       %catch_token, %exn_ptr = cir.begin_catch %eh_token
         : !cir.eh_token -> (!cir.catch_token, !cir.ptr<!void>)
       cir.end_catch %catch_token : !cir.catch_token
@@ -87,8 +87,8 @@ cir.func @copy_fn_non_void_return() {
     } catch [type #cir.global_view<@_ZTI1E> : !cir.ptr<!u8i>]
         (%eh_token: !cir.eh_token) {
       // expected-error @below {{catch-init copy_fn must take two pointer arguments and return void}}
-      cir.construct_catch_param non_trivial_copy %eh_token to %p
-        : !cir.eh_token, !cir.ptr<!rec_E>, copy_fn = @bad_copy_fn_ret
+      cir.construct_catch_param non_trivial_copy %eh_token to %p using @bad_copy_fn_ret
+        : !cir.ptr<!rec_E>
       %catch_token, %exn_ptr = cir.begin_catch %eh_token
         : !cir.eh_token -> (!cir.catch_token, !cir.ptr<!void>)
       cir.end_catch %catch_token : !cir.catch_token
@@ -124,8 +124,8 @@ cir.func @copy_fn_first_arg_mismatch() {
     } catch [type #cir.global_view<@_ZTI1E> : !cir.ptr<!u8i>]
         (%eh_token: !cir.eh_token) {
       // expected-error @below {{first argument of catch-init copy_fn must match the type of 'param_addr'}}
-      cir.construct_catch_param non_trivial_copy %eh_token to %p
-        : !cir.eh_token, !cir.ptr<!rec_E>, copy_fn = @bad_copy_fn_first_arg
+      cir.construct_catch_param non_trivial_copy %eh_token to %p using @bad_copy_fn_first_arg
+        : !cir.ptr<!rec_E>
       %catch_token, %exn_ptr = cir.begin_catch %eh_token
         : !cir.eh_token -> (!cir.catch_token, !cir.ptr<!void>)
       cir.end_catch %catch_token : !cir.catch_token
@@ -161,8 +161,8 @@ cir.func @copy_fn_second_arg_mismatch() {
     } catch [type #cir.global_view<@_ZTI1E> : !cir.ptr<!u8i>]
         (%eh_token: !cir.eh_token) {
       // expected-error @below {{second argument of catch-init copy_fn must be a pointer to the catch type}}
-      cir.construct_catch_param non_trivial_copy %eh_token to %p
-        : !cir.eh_token, !cir.ptr<!rec_E>, copy_fn = @bad_copy_fn_second_arg
+      cir.construct_catch_param non_trivial_copy %eh_token to %p using @bad_copy_fn_second_arg
+        : !cir.ptr<!rec_E>
       %catch_token, %exn_ptr = cir.begin_catch %eh_token
         : !cir.eh_token -> (!cir.catch_token, !cir.ptr<!void>)
       cir.end_catch %catch_token : !cir.catch_token
@@ -200,9 +200,8 @@ cir.func @construct_not_followed_by_begin_catch() {
       cir.yield
     } catch [type #cir.global_view<@_ZTI1E> : !cir.ptr<!u8i>]
         (%eh_token: !cir.eh_token) {
-      cir.construct_catch_param non_trivial_copy %eh_token to %p
-        : !cir.eh_token, !cir.ptr<!rec_E>,
-          copy_fn = @__clang_cir_catch_copy__ZTS1E
+      cir.construct_catch_param non_trivial_copy %eh_token to %p using @__clang_cir_catch_copy__ZTS1E
+        : !cir.ptr<!rec_E>
       cir.yield
     }
   }



More information about the cfe-commits mailing list