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

>From 67e5912e9dafb86758980363d7006af6bac5312a Mon Sep 17 00:00:00 2001
From: Andy Kaylor <[email protected]>
Date: Wed, 29 Apr 2026 16:24:29 -0700
Subject: [PATCH 1/2] [CIR] Implement copy construction of EH catch values

This change implements handling of exception variables that require
copy construction (on Itanium targets) before they can be used in a
catch handler, using the cir.contruct_catch_param operation.

Some targets, such as MSABI, do not need to perform an explicit copy.
The construct_catch_param operation is effectively a noop for those
cases and will be lowered as such when the EHABI lowering is implemented
for those targets.

Assisted-by: Cursor / claude-opus-4.7-thinking-xhigh
---
 clang/lib/CIR/CodeGen/CIRGenException.cpp     | 105 +++-
 .../CodeGen/try-catch-non-trivial-copy.cpp    | 563 ++++++++++++++++++
 2 files changed, 665 insertions(+), 3 deletions(-)
 create mode 100644 clang/test/CIR/CodeGen/try-catch-non-trivial-copy.cpp

diff --git a/clang/lib/CIR/CodeGen/CIRGenException.cpp 
b/clang/lib/CIR/CodeGen/CIRGenException.cpp
index 3c956801f6b52..054a6003ae762 100644
--- a/clang/lib/CIR/CodeGen/CIRGenException.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenException.cpp
@@ -298,6 +298,87 @@ static mlir::Value callBeginCatch(CIRGenFunction &cgf, 
mlir::Value ehToken,
   return beginCatch.getExnPtr();
 }
 
+/// Get or create the catch-init copy thunk for \p catchParam.
+///
+/// The copy thunk has signature `void(T*, T*)` (where `T` is the catch
+/// parameter type) and contains the normal aggregate emission of the catch
+/// parameter's init expression.
+///
+/// The thunk name is keyed off the catch parameter's canonical type mangled
+/// name, so a single translation unit emits at most one thunk per catch type.
+static cir::FuncOp getOrCreateCopyThunk(CIRGenFunction &cgf,
+                                        const VarDecl &catchParam,
+                                        cir::PointerType paramAddrType,
+                                        mlir::Location loc) {
+  CIRGenModule &cgm = cgf.cgm;
+  CIRGenBuilderTy &builder = cgm.getBuilder();
+  mlir::ModuleOp mod = cgm.getModule();
+
+  const Expr *copyExpr = catchParam.getInit();
+  assert(copyExpr && "non-trivial copy expects a copy expression");
+
+  llvm::SmallString<128> thunkName;
+  llvm::raw_svector_ostream thunkNameStream(thunkName);
+  thunkNameStream << "__clang_cir_catch_copy_";
+  cgm.getCXXABI().getMangleContext().mangleCanonicalTypeName(
+      catchParam.getType(), thunkNameStream);
+
+  if (cir::FuncOp existing = cgm.lookupFuncOp(thunkName))
+    return existing;
+
+  mlir::Type voidTy = cir::VoidType::get(builder.getContext());
+  auto thunkTy = cir::FuncType::get({paramAddrType, paramAddrType}, voidTy,
+                                    /*isVarArg=*/false);
+
+  mlir::OpBuilder::InsertionGuard guard(builder);
+  builder.setInsertionPointToEnd(mod.getBody());
+  cir::FuncOp thunk = cir::FuncOp::create(builder, loc, thunkName, thunkTy);
+  cgm.insertGlobalSymbol(thunk);
+  thunk.setLinkage(cir::GlobalLinkageKind::LinkOnceODRLinkage);
+  thunk.setGlobalVisibility(cir::VisibilityKind::Hidden);
+  thunk->setAttr(cir::CIRDialect::getCatchCopyThunkAttrName(),
+                 builder.getUnitAttr());
+
+  mlir::Block *entry = thunk.addEntryBlock();
+  builder.setInsertionPointToStart(entry);
+
+  // Use a fresh CIRGenFunction to drive the body emission. We need just enough
+  // state for emitAggExpr / emitCXXConstructorCall to compute the call-site
+  // argument attributes; the helper has no AST decl, no exception scopes, and
+  // no return value, so we bypass the full startFunction/finishFunction
+  // machinery.
+  CIRGenFunction subCgf(cgm, builder);
+  subCgf.curFn = thunk;
+
+  // Some emission paths (e.g. materializing temporaries for default args via
+  // emitAnyExprToTemp) need both a current source location and a lexical
+  // scope to anchor allocas. Since we bypass startFunction, install both
+  // explicitly for the lifetime of the thunk's body emission.
+  CIRGenFunction::SourceLocRAIIObject thunkLoc(subCgf, loc);
+  CIRGenFunction::LexicalScope thunkScope(subCgf, loc, entry);
+
+  // Bind the OpaqueValueExpr at the source position of the catch parameter's
+  // copy expression to an LValue at the thunk's `src` block argument.
+  LValue srcLV = subCgf.makeNaturalAlignAddrLValue(entry->getArgument(1),
+                                                   catchParam.getType());
+  CIRGenFunction::OpaqueValueMapping opaqueValue(
+      subCgf, OpaqueValueExpr::findInCopyConstruct(copyExpr), srcLV);
+
+  // Drive the construction into the helper's `dest` block argument via the
+  // normal aggregate-emission machinery so that `ExprWithCleanups`,
+  // converting/inheriting constructors, and any future copy-construction
+  // shapes flow through unchanged.
+  Address destAddr = subCgf.makeNaturalAddressForPointer(
+      entry->getArgument(0), catchParam.getType(), clang::CharUnits::Zero());
+  subCgf.emitAggExpr(
+      copyExpr, AggValueSlot::forAddr(
+                    destAddr, Qualifiers(), AggValueSlot::IsNotDestructed,
+                    AggValueSlot::IsNotAliased, AggValueSlot::DoesNotOverlap));
+
+  cir::ReturnOp::create(builder, loc);
+  return thunk;
+}
+
 /// A "special initializer" callback for initializing a catch
 /// parameter during catch initialization.
 static void initCatchParam(CIRGenFunction &cgf, CIRGenBuilderTy &builder,
@@ -339,10 +420,28 @@ static void initCatchParam(CIRGenFunction &cgf, 
CIRGenBuilderTy &builder,
     }
   }
 
-  mlir::Value exnPtr = callBeginCatch(cgf, ehToken, builder.getVoidPtrTy());
   CIRGenFunction::AutoVarEmission var = cgf.emitAutoVarAlloca(catchParam);
-  cir::InitCatchParamOp::create(builder, cgf.getLoc(loc), exnPtr,
-                                var.getAllocatedAddress().getPointer(), kind);
+  Address paramAddr = var.getAllocatedAddress();
+  mlir::Location mloc = cgf.getLoc(loc);
+
+  if (kind == cir::InitCatchKind::NonTrivialCopy) {
+    // Sanitizer-checked construction (UBSan vptr/derived-class checks, etc.)
+    // would require additional adornments that cir.construct_catch_param does
+    // not yet carry.
+    assert(!cir::MissingFeatures::sanitizers());
+
+    auto paramAddrType =
+        mlir::cast<cir::PointerType>(paramAddr.getPointer().getType());
+    cir::FuncOp thunk =
+        getOrCreateCopyThunk(cgf, catchParam, paramAddrType, mloc);
+    cir::ConstructCatchParamOp::create(builder, mloc, ehToken,
+                                       paramAddr.getPointer(), kind,
+                                       thunk.getSymName());
+  }
+
+  mlir::Value exnPtr = callBeginCatch(cgf, ehToken, builder.getVoidPtrTy());
+  cir::InitCatchParamOp::create(builder, mloc, exnPtr, paramAddr.getPointer(),
+                                kind);
   cgf.emitAutoVarCleanups(var);
 }
 
diff --git a/clang/test/CIR/CodeGen/try-catch-non-trivial-copy.cpp 
b/clang/test/CIR/CodeGen/try-catch-non-trivial-copy.cpp
new file mode 100644
index 0000000000000..c1413700e0c70
--- /dev/null
+++ b/clang/test/CIR/CodeGen/try-catch-non-trivial-copy.cpp
@@ -0,0 +1,563 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fcxx-exceptions 
-fexceptions -fclangir -emit-cir %s -o %t.cir
+// RUN: FileCheck --input-file=%t.cir %s -check-prefix=CIR
+// RUN: cir-opt -cir-hoist-allocas -cir-flatten-cfg %t.cir -o %t.flat.cir
+// RUN: FileCheck --input-file=%t.flat.cir %s -check-prefix=CIR-FLAT
+// RUN: cir-opt -cir-hoist-allocas -cir-flatten-cfg -cir-eh-abi-lowering 
%t.cir -o %t.eh.cir
+// RUN: FileCheck --input-file=%t.eh.cir %s -check-prefix=CIR-AFTER-EHABI
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fcxx-exceptions 
-fexceptions -fclangir -emit-llvm %s -o %t-cir.ll
+// RUN: FileCheck --input-file=%t-cir.ll %s -check-prefix=LLVM
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fcxx-exceptions 
-fexceptions -emit-llvm %s -o %t.ll
+// RUN: FileCheck --input-file=%t.ll %s -check-prefix=OGCG
+
+void mayThrow();
+
+//===----------------------------------------------------------------------===//
+// Case 1: Plain non-trivial copy constructor `T(const T &)`.
+//===----------------------------------------------------------------------===//
+
+struct MyException {
+  MyException();
+  MyException(const MyException &);
+  ~MyException();
+  int get();
+};
+
+int test_non_trivial_exception_copy() {
+  int rv = 0;
+  try {
+    mayThrow();
+  } catch (MyException e) {
+    rv = e.get();
+  }
+  return rv;
+}
+
+// --- CIR (out of CodeGen, before any pre-lowering passes) ---
+//
+// The catch-binding step is `cir.construct_catch_param non_trivial_copy`,
+// which references a CIRGen-synthesized helper thunk via `copy_fn`. The
+// helper is keyed off the catch type's mangled typeinfo name, has
+// `linkonce_odr` linkage, hidden visibility, and the
+// `cir.eh.catch_copy_thunk` attribute so EHABI lowering can find or remove
+// it later.
+
+// CIR-LABEL: cir.func {{.*}} @_Z31test_non_trivial_exception_copyv()
+// CIR:         %[[RETVAL:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, 
["__retval"]
+// CIR:         %[[RV:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["rv", init]
+// CIR:         cir.scope {
+// CIR:           %[[E:.*]] = cir.alloca !rec_MyException, 
!cir.ptr<!rec_MyException>, ["e"]
+// CIR:           cir.try {
+// CIR:             cir.call @_Z8mayThrowv() : () -> ()
+// CIR:           } catch [type #cir.global_view<@_ZTI11MyException> : 
!cir.ptr<!u8i>] (%arg0: !cir.eh_token {{.*}}) {
+// CIR:             cir.construct_catch_param non_trivial_copy %arg0 to %[[E]] 
using @__clang_cir_catch_copy__ZTS11MyException : !cir.ptr<!rec_MyException>
+// CIR:             %catch_token, %exn_ptr = cir.begin_catch %arg0 : 
!cir.eh_token -> (!cir.catch_token, !cir.ptr<!void>)
+// CIR:             cir.cleanup.scope {
+// CIR:               cir.init_catch_param non_trivial_copy %exn_ptr to %[[E]] 
: !cir.ptr<!void>, !cir.ptr<!rec_MyException>
+// CIR:               cir.cleanup.scope {
+// CIR:                 %[[GET:.*]] = cir.call @_ZN11MyException3getEv(%[[E]]) 
: (!cir.ptr<!rec_MyException> {{.*}}) -> (!s32i {{.*}})
+// CIR:                 cir.store{{.*}} %[[GET]], %[[RV]]
+// CIR:                 cir.yield
+// CIR:               } cleanup all {
+// CIR:                 cir.call @_ZN11MyExceptionD1Ev(%[[E]]) nothrow
+// CIR:                 cir.yield
+// CIR:               }
+// CIR:               cir.yield
+// CIR:             } cleanup all {
+// CIR:               cir.end_catch %catch_token : !cir.catch_token
+// CIR:               cir.yield
+// CIR:             }
+// CIR:           } unwind (%arg0: !cir.eh_token {{.*}}) {
+// CIR:             cir.resume %arg0 : !cir.eh_token
+// CIR:           }
+// CIR:         }
+// CIR:         cir.return
+
+// CIR-LABEL: cir.func linkonce_odr hidden 
@__clang_cir_catch_copy__ZTS11MyException
+// CIR-SAME:    attributes {cir.eh.catch_copy_thunk}
+// CIR:         cir.call @_ZN11MyExceptionC1ERKS_(%arg0, %arg1)
+// CIR:         cir.return
+
+// --- CIR-FLAT (after hoist-allocas + flatten-cfg) ---
+//
+// Regions are inlined into a flat CFG. The catch-binding op survives
+// flattening unchanged; its `copy_fn` symbol reference is preserved.
+//
+// Pure-fallthrough blocks (just a `cir.br` to the next block) are skipped in
+// the checks; we only verify branch terminators with non-trivial successors
+// and the labels of blocks that carry real work.
+
+// CIR-FLAT-LABEL: cir.func {{.*}} @_Z31test_non_trivial_exception_copyv()
+// CIR-FLAT:         cir.try_call @_Z8mayThrowv() ^[[T1F_CONT:bb[0-9]+]], 
^[[T1F_LPAD:bb[0-9]+]] : () -> ()
+
+// On the unwind edge: initiate the in-flight exception and feed it to the
+// dispatch block.
+// CIR-FLAT:       ^[[T1F_LPAD]]:
+// CIR-FLAT:         %[[T1F_TOK:.*]] = cir.eh.initiate : !cir.eh_token
+// CIR-FLAT:         cir.br ^[[T1F_DISP:bb[0-9]+]](%[[T1F_TOK]] : 
!cir.eh_token)
+
+// Dispatch matches the in-flight exception against `MyException` and falls
+// through to the resume block on a miss.
+// CIR-FLAT:       ^[[T1F_DISP]](%{{.*}}: !cir.eh_token):
+// CIR-FLAT:         cir.eh.dispatch %{{.*}} : !cir.eh_token  [
+// CIR-FLAT:           catch(#cir.global_view<@_ZTI11MyException> : 
!cir.ptr<!u8i>) : ^[[T1F_CATCH:bb[0-9]+]],
+// CIR-FLAT:           unwind : ^[[T1F_RESUME:bb[0-9]+]]
+// CIR-FLAT:         ]
+
+// Catch handler: bind exception via the helper thunk, begin the catch,
+// initialize the catch parameter, run the body.
+// CIR-FLAT:       ^[[T1F_CATCH]](%{{.*}}: !cir.eh_token):
+// CIR-FLAT:         cir.construct_catch_param non_trivial_copy %{{.*}} to 
%{{.*}} using @__clang_cir_catch_copy__ZTS11MyException : 
!cir.ptr<!rec_MyException>
+// CIR-FLAT:         cir.begin_catch %{{.*}} : !cir.eh_token -> 
(!cir.catch_token, !cir.ptr<!void>)
+// CIR-FLAT:         cir.init_catch_param non_trivial_copy %{{.*}} to %{{.*}} 
: !cir.ptr<!void>, !cir.ptr<!rec_MyException>
+// CIR-FLAT:         cir.try_call @_ZN11MyException3getEv(%{{.*}}) 
^[[T1F_GET_OK:bb[0-9]+]], ^[[T1F_GET_LPAD:bb[0-9]+]]
+
+// Normal path of `e.get()`: store result and run `e`'s dtor.
+// CIR-FLAT:       ^[[T1F_GET_OK]]:
+// CIR-FLAT:         cir.store align(4) %{{.*}}
+// CIR-FLAT:         cir.call @_ZN11MyExceptionD1Ev(%{{.*}}) nothrow
+
+// Unwind path of `e.get()`: initiate cleanup, run `e`'s dtor, end cleanup.
+// CIR-FLAT:       ^[[T1F_GET_LPAD]]:
+// CIR-FLAT:         %[[T1F_CL_TOK:.*]] = cir.eh.initiate cleanup : 
!cir.eh_token
+// CIR-FLAT:         cir.br ^[[T1F_CL_DTOR:bb[0-9]+]](%[[T1F_CL_TOK]] : 
!cir.eh_token)
+
+// CIR-FLAT:       ^[[T1F_CL_DTOR]](%[[T1F_CL_TOK2:.*]]: !cir.eh_token):
+// CIR-FLAT:         cir.begin_cleanup %[[T1F_CL_TOK2]] : !cir.eh_token -> 
!cir.cleanup_token
+// CIR-FLAT:         cir.call @_ZN11MyExceptionD1Ev(%{{.*}}) nothrow
+// CIR-FLAT:         cir.end_cleanup %{{.*}} : !cir.cleanup_token
+// CIR-FLAT:         cir.br ^[[T1F_CL_END:bb[0-9]+]](%[[T1F_CL_TOK2]] : 
!cir.eh_token)
+
+// Normal-path end_catch (after the catch body completed).
+// CIR-FLAT:         cir.end_catch
+
+// End of the catch's unwind path: end_catch then resume.
+// CIR-FLAT:       ^[[T1F_CL_END]](%[[T1F_RES_TOK:.*]]: !cir.eh_token):
+// CIR-FLAT:         cir.begin_cleanup
+// CIR-FLAT:         cir.end_catch
+// CIR-FLAT:         cir.end_cleanup
+// CIR-FLAT:         cir.resume %[[T1F_RES_TOK]] : !cir.eh_token
+
+// The outer dispatch unwind block (unmatched type).
+// CIR-FLAT:       ^[[T1F_RESUME]](%[[T1F_OUT_TOK:.*]]: !cir.eh_token):
+// CIR-FLAT:         cir.resume %[[T1F_OUT_TOK]] : !cir.eh_token
+
+// Final return.
+// CIR-FLAT:         cir.return %{{.*}} : !s32i
+
+// --- CIR-AFTER-EHABI ---
+//
+// EH ABI lowering replaces:
+//  - `cir.eh.initiate`            -> `cir.eh.inflight_exception [@RTTI]`
+//  - `cir.eh.dispatch`            -> `cir.eh.typeid` + `cir.cmp` + 
`cir.brcond`
+//  - `cir.construct_catch_param`  -> `__cxa_get_exception_ptr` + the thunk's
+//                                    body cloned inline. Plain `cir.call`s
+//                                    inside the cloned body that may unwind
+//                                    are wrapped in a `cir.try_call` whose
+//                                    unwind edge is a terminate block;
+//                                    any `cir.resume.flat` in the inlined
+//                                    body is rewritten to a direct call to
+//                                    `__clang_call_terminate`. After this
+//                                    pass the thunk function itself is dead
+//                                    and is removed by the post-lowering
+//                                    sweep.
+//  - `cir.begin_catch`            -> `__cxa_get_exception_ptr` (preceding the
+//                                    inlined copy) + `__cxa_begin_catch`
+//                                    (after)
+//  - `cir.end_catch`              -> `__cxa_end_catch`
+//  - `cir.resume`                 -> `cir.resume.flat`
+
+// CIR-AFTER-EHABI-LABEL: cir.func {{.*}} 
@_Z31test_non_trivial_exception_copyv()
+// CIR-AFTER-EHABI:         cir.try_call @_Z8mayThrowv() 
^[[T1E_CONT:bb[0-9]+]], ^[[T1E_LPAD:bb[0-9]+]]
+
+// CIR-AFTER-EHABI:       ^[[T1E_LPAD]]:
+// CIR-AFTER-EHABI:         %[[T1E_EXN:exception_ptr]], %[[T1E_TID:type_id]] = 
cir.eh.inflight_exception [@_ZTI11MyException]
+// CIR-AFTER-EHABI:         cir.br ^{{bb[0-9]+}}(%[[T1E_EXN]], %[[T1E_TID]] : 
!cir.ptr<!void>, !u32i)
+
+// At the dispatch: compare type_ids and branch to either the catch or resume.
+// CIR-AFTER-EHABI:         %[[T1E_TYPEID:.*]] = cir.eh.typeid 
@_ZTI11MyException
+// CIR-AFTER-EHABI:         %[[T1E_EQ:.*]] = cir.cmp eq %{{.*}}, 
%[[T1E_TYPEID]] : !u32i
+// CIR-AFTER-EHABI:         cir.brcond %[[T1E_EQ]] 
^[[T1E_CATCH:bb[0-9]+]](%{{.*}}, %{{.*}} : !cir.ptr<!void>, !u32i), 
^[[T1E_RESUME:bb[0-9]+]](%{{.*}}, %{{.*}} : !cir.ptr<!void>, !u32i)
+
+// In the catch block: get the adjusted exception pointer, then invoke the
+// inlined copy ctor directly. The normal-edge target is a pure-fallthrough
+// block that we don't pin; the unwind-edge target is the terminate handler.
+// CIR-AFTER-EHABI:       ^[[T1E_CATCH]](%[[T1E_RAW:.*]]: !cir.ptr<!void>, 
%{{.*}}: !u32i):
+// CIR-AFTER-EHABI:         %[[T1E_ADJ:.*]] = cir.call 
@__cxa_get_exception_ptr(%[[T1E_RAW]]) nothrow : (!cir.ptr<!void>) -> 
!cir.ptr<!u8i>
+// CIR-AFTER-EHABI:         %[[T1E_ADJT:.*]] = cir.cast bitcast %[[T1E_ADJ]] : 
!cir.ptr<!u8i> -> !cir.ptr<!rec_MyException>
+// CIR-AFTER-EHABI:         cir.try_call @_ZN11MyExceptionC1ERKS_(%{{.*}}, 
%[[T1E_ADJT]]) ^{{bb[0-9]+}}, ^[[T1E_TERM:bb[0-9]+]]
+
+// On the inlined copy's normal-edge fallthrough chain: __cxa_begin_catch and
+// run the catch body.
+// CIR-AFTER-EHABI:         cir.call @__cxa_begin_catch(%[[T1E_RAW]]) : 
(!cir.ptr<!void>) -> !cir.ptr<!u8i>
+// CIR-AFTER-EHABI:         cir.try_call @_ZN11MyException3getEv(%{{.*}}) 
^[[T1E_GET_OK:bb[0-9]+]], ^[[T1E_GET_LPAD:bb[0-9]+]]
+
+// Normal path: store get's result, dtor, end_catch, fall through.
+// CIR-AFTER-EHABI:       ^[[T1E_GET_OK]]:
+// CIR-AFTER-EHABI:         cir.store align(4) %{{.*}}
+// CIR-AFTER-EHABI:         cir.call @_ZN11MyExceptionD1Ev(%{{.*}}) nothrow
+
+// Unwind path: inflight_exception cleanup, dtor, end_catch, resume.
+// CIR-AFTER-EHABI:       ^[[T1E_GET_LPAD]]:
+// CIR-AFTER-EHABI:         %{{.*}}, %{{.*}} = cir.eh.inflight_exception 
cleanup
+// CIR-AFTER-EHABI:         cir.call @_ZN11MyExceptionD1Ev(%{{.*}}) nothrow
+// CIR-AFTER-EHABI:         cir.call @__cxa_end_catch() : () -> ()
+// CIR-AFTER-EHABI:         cir.call @__cxa_end_catch() : () -> ()
+// CIR-AFTER-EHABI:         cir.resume.flat %{{.*}}
+
+// Outer dispatch's resume.
+// CIR-AFTER-EHABI:       ^[[T1E_RESUME]](%{{.*}}: !cir.ptr<!void>, %{{.*}}: 
!u32i):
+// CIR-AFTER-EHABI:         cir.resume.flat %{{.*}}, %{{.*}}
+
+// CIR-AFTER-EHABI:         cir.return %{{.*}} : !s32i
+
+// Terminate landing pad.
+// CIR-AFTER-EHABI:       ^[[T1E_TERM]]:
+// CIR-AFTER-EHABI:         %{{.*}}, %{{.*}} = cir.eh.inflight_exception 
catch_all
+// CIR-AFTER-EHABI:         cir.call @__clang_call_terminate(%{{.*}}) nothrow 
{noreturn} : (!cir.ptr<!void>) -> ()
+// CIR-AFTER-EHABI:         cir.unreachable
+
+
+// The catch-copy thunk is fully inlined and removed by the post-lowering
+// sweep, so it is no longer present at this stage.
+// CIR-AFTER-EHABI-NOT: @__clang_cir_catch_copy__ZTS11MyException
+
+// --- LLVM (CIR -> LLVM IR via the full pipeline) ---
+
+// LLVM-LABEL: define dso_local noundef i32 
@_Z31test_non_trivial_exception_copyv() #{{[0-9]+}} personality ptr 
@__gxx_personality_v0
+// LLVM:         invoke void @_Z8mayThrowv()
+// LLVM:                 to label %[[T1L_CONT:.*]] unwind label 
%[[T1L_LPAD:.*]]
+
+// LLVM:       [[T1L_LPAD]]:
+// LLVM:         landingpad { ptr, i32 }
+// LLVM:                 catch ptr @_ZTI11MyException
+
+// Type-id dispatch.
+// LLVM:         %[[T1L_TYPEID:.*]] = call i32 @llvm.eh.typeid.for.p0(ptr 
@_ZTI11MyException)
+// LLVM:         %[[T1L_MATCH:.*]] = icmp eq i32 %{{.*}}, %[[T1L_TYPEID]]
+// LLVM:         br i1 %[[T1L_MATCH]], label %[[T1L_CATCH:.*]], label 
%[[T1L_RESUME:.*]]
+
+// Catch handler: __cxa_get_exception_ptr followed by the inlined copy ctor
+// invoke (the catch-copy thunk has been inlined away, so the ctor is called
+// directly with a terminate landing pad). The normal-edge target is a
+// pure-fallthrough block that we don't pin.
+// LLVM:       [[T1L_CATCH]]:
+// LLVM:         %[[T1L_ADJ:.*]] = call ptr @__cxa_get_exception_ptr(
+// LLVM:         invoke void @_ZN11MyExceptionC1ERKS_(ptr {{.*}}, ptr{{.*}} 
%[[T1L_ADJ]])
+// LLVM:                 to label %{{.*}} unwind label %[[T1L_TERM:.*]]
+
+// On the inlined copy's normal-edge fallthrough chain: __cxa_begin_catch.
+// LLVM:         call ptr @__cxa_begin_catch(
+// LLVM:         invoke noundef i32 @_ZN11MyException3getEv(
+// LLVM:                 to label %[[T1L_GET_OK:.*]] unwind label 
%[[T1L_GET_LPAD:.*]]
+
+// LLVM:       [[T1L_GET_OK]]:
+// LLVM:         store i32 %{{.*}}
+// LLVM:         call void @_ZN11MyExceptionD1Ev(
+
+// LLVM:       [[T1L_GET_LPAD]]:
+// LLVM:         landingpad { ptr, i32 }
+// LLVM:                 cleanup
+// LLVM:         call void @_ZN11MyExceptionD1Ev(
+// LLVM:         call void @__cxa_end_catch()
+// LLVM:         call void @__cxa_end_catch()
+// LLVM:         resume { ptr, i32 }
+
+// LLVM:       [[T1L_RESUME]]:
+// LLVM:         resume { ptr, i32 }
+// LLVM:         ret i32
+
+// LLVM:       [[T1L_TERM]]:
+// LLVM:         landingpad { ptr, i32 }
+// LLVM:                 catch ptr null
+// LLVM:         call void @__clang_call_terminate(
+// LLVM:         unreachable
+
+// The catch-copy thunk is inlined away during EHABI lowering, so it should
+// not appear in the LLVM IR.
+// LLVM-NOT: @__clang_cir_catch_copy__ZTS11MyException
+
+// --- OGCG (classic CodeGen reference) ---
+//
+// Classic CodeGen does not synthesize a catch-init thunk; it inlines the
+// `__cxa_get_exception_ptr` + copy ctor invocation at the catch site, with a
+// terminate landing pad on the copy's unwind edge.
+
+// OGCG-LABEL: define {{.*}} i32 @_Z31test_non_trivial_exception_copyv()
+// OGCG:       entry:
+// OGCG:         %[[O1_RV:.*]] = alloca i32
+// OGCG:         %[[O1_E:.*]] = alloca %struct.MyException
+// OGCG:         store i32 0, ptr %[[O1_RV]]
+// OGCG:         invoke void @_Z8mayThrowv()
+// OGCG:                 to label %[[O1_CONT:.*]] unwind label %[[O1_LPAD:.*]]
+
+// OGCG:       [[O1_LPAD]]:
+// OGCG:         landingpad { ptr, i32 }
+// OGCG:                 catch ptr @_ZTI11MyException
+
+// OGCG:       catch.dispatch:
+// OGCG:         %[[O1_TYPEID:.*]] = call i32 @llvm.eh.typeid.for.p0(ptr 
@_ZTI11MyException)
+// OGCG:         %[[O1_MATCH:.*]] = icmp eq i32 %{{.*}}, %[[O1_TYPEID]]
+// OGCG:         br i1 %[[O1_MATCH]], label %[[O1_CATCH:.*]], label %eh.resume
+
+// OGCG:       [[O1_CATCH]]:
+// OGCG:         %[[O1_ADJ:.*]] = call ptr @__cxa_get_exception_ptr(ptr 
%{{.*}})
+// OGCG:         invoke void @_ZN11MyExceptionC1ERKS_(ptr noundef nonnull 
align 1 dereferenceable(1) %[[O1_E]], ptr noundef nonnull align 1 
dereferenceable(1) %[[O1_ADJ]])
+// OGCG:                 to label %[[O1_INVOKE_CONT1:.*]] unwind label 
%[[O1_TERM:.*]]
+
+// OGCG:       [[O1_INVOKE_CONT1]]:
+// OGCG:         call ptr @__cxa_begin_catch(
+// OGCG:         invoke noundef i32 @_ZN11MyException3getEv(ptr noundef 
nonnull align 1 dereferenceable(1) %[[O1_E]])
+// OGCG:                 to label %[[O1_INVOKE_CONT3:.*]] unwind label 
%[[O1_LPAD2:.*]]
+
+// OGCG:       [[O1_INVOKE_CONT3]]:
+// OGCG:         store i32 %{{.*}}, ptr %[[O1_RV]]
+// OGCG:         call void @_ZN11MyExceptionD1Ev(ptr noundef nonnull align 1 
dereferenceable(1) %[[O1_E]])
+// OGCG:         call void @__cxa_end_catch()
+// OGCG:         br label %[[O1_TRY_CONT:.*]]
+
+// OGCG:       [[O1_TRY_CONT]]:
+// OGCG:         load i32, ptr %[[O1_RV]]
+// OGCG:         ret i32
+
+// OGCG:       [[O1_LPAD2]]:
+// OGCG:         landingpad { ptr, i32 }
+// OGCG:                 cleanup
+// OGCG:         call void @_ZN11MyExceptionD1Ev(ptr noundef nonnull align 1 
dereferenceable(1) %[[O1_E]])
+// OGCG:         invoke void @__cxa_end_catch()
+// OGCG:                 to label %{{.*}} unwind label %[[O1_TERM]]
+
+// OGCG:       eh.resume:
+// OGCG:         resume { ptr, i32 }
+
+// OGCG:       [[O1_TERM]]:
+// OGCG:         landingpad { ptr, i32 }
+// OGCG:                 catch ptr null
+// OGCG:         call void @__clang_call_terminate(
+// OGCG:         unreachable
+
+//===----------------------------------------------------------------------===//
+// Case 2: Copy constructor with extra (default) arguments.
+//
+// `WithDefault(const WithDefault &, int = 42)` is a valid copy constructor
+// per [class.copy.ctor]/1 since the only non-`const T &` parameter has a
+// default argument. emitAggExpr lets the CXXDefaultArgExpr fill-in flow
+// through naturally; the thunk body materializes the `42` constant before
+// calling the underlying ctor.
+//===----------------------------------------------------------------------===//
+
+struct WithDefault {
+  WithDefault();
+  WithDefault(const WithDefault &, int = 42);
+  ~WithDefault();
+};
+
+int test_copy_ctor_extra_args() {
+  try {
+    mayThrow();
+  } catch (WithDefault w) {
+    return 0;
+  }
+  return -1;
+}
+
+// --- CIR ---
+
+// CIR-LABEL: cir.func {{.*}} @_Z25test_copy_ctor_extra_argsv()
+// CIR:         cir.construct_catch_param non_trivial_copy %{{.*}} to %{{.*}} 
using @__clang_cir_catch_copy__ZTS11WithDefault : !cir.ptr<!rec_WithDefault>
+
+// CIR-LABEL: cir.func linkonce_odr hidden 
@__clang_cir_catch_copy__ZTS11WithDefault(
+// CIR-SAME:    attributes {cir.eh.catch_copy_thunk}
+// CIR:         %[[FORTYTWO:.*]] = cir.const #cir.int<42> : !s32i
+// CIR:         cir.call @_ZN11WithDefaultC1ERKS_i({{.*}}, {{.*}}, 
%[[FORTYTWO]])
+// CIR:         cir.return
+
+// --- CIR-FLAT ---
+//
+// Because the catch handler does `return 0`, the function uses a
+// `__cleanup_dest_slot` to dispatch through the catch end_catch and into
+// either the inner-`return 0` or the outer-`return -1`. We don't pin the
+// exact switch shape here, but we do verify the EH-relevant control flow.
+
+// CIR-FLAT-LABEL: cir.func {{.*}} @_Z25test_copy_ctor_extra_argsv()
+// CIR-FLAT:         %{{.*}} = cir.alloca !s32i, !cir.ptr<!s32i>, 
["__cleanup_dest_slot", cleanup_dest_slot]
+// CIR-FLAT:         cir.try_call @_Z8mayThrowv() ^[[T2F_CONT:bb[0-9]+]], 
^[[T2F_LPAD:bb[0-9]+]]
+
+// CIR-FLAT:       ^[[T2F_LPAD]]:
+// CIR-FLAT:         %[[T2F_TOK:.*]] = cir.eh.initiate : !cir.eh_token
+// CIR-FLAT:         cir.br ^[[T2F_DISP:bb[0-9]+]](%[[T2F_TOK]] : 
!cir.eh_token)
+
+// CIR-FLAT:       ^[[T2F_DISP]](%{{.*}}: !cir.eh_token):
+// CIR-FLAT:         cir.eh.dispatch %{{.*}} : !cir.eh_token  [
+// CIR-FLAT:           catch(#cir.global_view<@_ZTI11WithDefault> : 
!cir.ptr<!u8i>) : ^[[T2F_CATCH:bb[0-9]+]],
+// CIR-FLAT:           unwind : ^[[T2F_RESUME:bb[0-9]+]]
+// CIR-FLAT:         ]
+
+// CIR-FLAT:       ^[[T2F_CATCH]](%{{.*}}: !cir.eh_token):
+// CIR-FLAT:         cir.construct_catch_param non_trivial_copy %{{.*}} to 
%{{.*}} using @__clang_cir_catch_copy__ZTS11WithDefault : 
!cir.ptr<!rec_WithDefault>
+// CIR-FLAT:         cir.begin_catch %{{.*}} : !cir.eh_token -> 
(!cir.catch_token, !cir.ptr<!void>)
+// CIR-FLAT:         cir.init_catch_param non_trivial_copy %{{.*}} to %{{.*}}
+
+// Catch body sets retval=0 and cleanup_dest=1.
+// CIR-FLAT:         cir.store %{{.*}}
+// CIR-FLAT:         cir.store %{{.*}}
+
+// `w`'s destructor.
+// CIR-FLAT:         cir.call @_ZN11WithDefaultD1Ev(%{{.*}}) nothrow
+
+// Cleanup-dest dispatch and end_catch.
+// CIR-FLAT:         cir.switch.flat
+// CIR-FLAT:         cir.end_catch
+
+// Return-or-fallthrough switch on cleanup_dest_slot.
+// CIR-FLAT:         cir.switch.flat
+// CIR-FLAT:         cir.load %{{.*}} : !cir.ptr<!s32i>, !s32i
+// CIR-FLAT:         cir.return %{{.*}} : !s32i
+
+// CIR-FLAT:       ^[[T2F_RESUME]](%[[T2F_OUT_TOK:.*]]: !cir.eh_token):
+// CIR-FLAT:         cir.resume %[[T2F_OUT_TOK]] : !cir.eh_token
+
+// Tail of the function (when the try doesn't catch):
+// CIR-FLAT:         cir.return %{{.*}} : !s32i
+
+// --- CIR-AFTER-EHABI ---
+
+// CIR-AFTER-EHABI-LABEL: cir.func {{.*}} @_Z25test_copy_ctor_extra_argsv()
+// CIR-AFTER-EHABI:         cir.try_call @_Z8mayThrowv() 
^[[T2E_CONT:bb[0-9]+]], ^[[T2E_LPAD:bb[0-9]+]]
+
+// CIR-AFTER-EHABI:       ^[[T2E_LPAD]]:
+// CIR-AFTER-EHABI:         %{{.*}}, %{{.*}} = cir.eh.inflight_exception 
[@_ZTI11WithDefault]
+
+// CIR-AFTER-EHABI:         %[[T2E_TYPEID:.*]] = cir.eh.typeid 
@_ZTI11WithDefault
+// CIR-AFTER-EHABI:         %[[T2E_EQ:.*]] = cir.cmp eq %{{.*}}, 
%[[T2E_TYPEID]]
+// CIR-AFTER-EHABI:         cir.brcond %[[T2E_EQ]] 
^[[T2E_CATCH:bb[0-9]+]](%{{.*}}, %{{.*}} : !cir.ptr<!void>, !u32i), 
^[[T2E_RESUME:bb[0-9]+]](%{{.*}}, %{{.*}} : !cir.ptr<!void>, !u32i)
+
+// In the catch block: get the adjusted exception pointer, materialize the
+// `42` default argument, and invoke the inlined copy ctor directly. The
+// thunk has been inlined into the catch handler, so the constant comes from
+// the cloned thunk body. The normal-edge target is a pure-fallthrough block
+// that we don't pin; the unwind-edge target is the terminate handler.
+// CIR-AFTER-EHABI:       ^[[T2E_CATCH]](%[[T2E_RAW:.*]]: !cir.ptr<!void>, 
%{{.*}}: !u32i):
+// CIR-AFTER-EHABI:         %[[T2E_ADJ:.*]] = cir.call 
@__cxa_get_exception_ptr(%[[T2E_RAW]]) nothrow
+// CIR-AFTER-EHABI:         %[[T2E_ADJT:.*]] = cir.cast bitcast %[[T2E_ADJ]] : 
!cir.ptr<!u8i> -> !cir.ptr<!rec_WithDefault>
+// CIR-AFTER-EHABI:         %[[T2E_FORTYTWO:.*]] = cir.const #cir.int<42> : 
!s32i
+// CIR-AFTER-EHABI:         cir.try_call @_ZN11WithDefaultC1ERKS_i(%{{.*}}, 
%[[T2E_ADJT]], %[[T2E_FORTYTWO]]) ^{{bb[0-9]+}}, ^[[T2E_TERM:bb[0-9]+]]
+
+// On the inlined copy's normal-edge fallthrough chain: __cxa_begin_catch.
+// CIR-AFTER-EHABI:         cir.call @__cxa_begin_catch(%[[T2E_RAW]])
+
+// Catch body and dispatch out via cleanup_dest_slot.
+// CIR-AFTER-EHABI:         cir.call @_ZN11WithDefaultD1Ev(%{{.*}}) nothrow
+// CIR-AFTER-EHABI:         cir.switch.flat
+// CIR-AFTER-EHABI:         cir.call @__cxa_end_catch()
+// CIR-AFTER-EHABI:         cir.switch.flat
+// CIR-AFTER-EHABI:         cir.return %{{.*}} : !s32i
+
+// CIR-AFTER-EHABI:       ^[[T2E_RESUME]](%{{.*}}: !cir.ptr<!void>, %{{.*}}: 
!u32i):
+// CIR-AFTER-EHABI:         cir.resume.flat %{{.*}}, %{{.*}}
+
+// CIR-AFTER-EHABI:         cir.return %{{.*}} : !s32i
+
+// Terminate landing pad.
+// CIR-AFTER-EHABI:       ^[[T2E_TERM]]:
+// CIR-AFTER-EHABI:         cir.eh.inflight_exception catch_all
+// CIR-AFTER-EHABI:         cir.call @__clang_call_terminate(
+
+// The catch-copy thunk is fully inlined and removed.
+// CIR-AFTER-EHABI-NOT: @__clang_cir_catch_copy__ZTS11WithDefault
+
+// --- LLVM ---
+
+// LLVM-LABEL: define dso_local noundef i32 @_Z25test_copy_ctor_extra_argsv()
+// LLVM:         invoke void @_Z8mayThrowv()
+// LLVM:                 to label %[[T2L_CONT:.*]] unwind label 
%[[T2L_LPAD:.*]]
+
+// LLVM:       [[T2L_LPAD]]:
+// LLVM:         landingpad { ptr, i32 }
+// LLVM:                 catch ptr @_ZTI11WithDefault
+
+// LLVM:         %[[T2L_TYPEID:.*]] = call i32 @llvm.eh.typeid.for.p0(ptr 
@_ZTI11WithDefault)
+// LLVM:         icmp eq i32 %{{.*}}, %[[T2L_TYPEID]]
+// LLVM:         br i1 %{{.*}}, label %[[T2L_CATCH:.*]], label 
%[[T2L_RESUME:.*]]
+
+// LLVM:       [[T2L_CATCH]]:
+// LLVM:         %[[T2L_ADJ:.*]] = call ptr @__cxa_get_exception_ptr(
+// LLVM:         invoke void @_ZN11WithDefaultC1ERKS_i(ptr {{.*}}, ptr {{.*}} 
%[[T2L_ADJ]], i32 {{.*}} 42)
+// LLVM:                 to label %{{.*}} unwind label %[[T2L_TERM:.*]]
+
+// On the inlined copy's normal-edge fallthrough chain: __cxa_begin_catch.
+// LLVM:         call ptr @__cxa_begin_catch(
+
+// LLVM:         call void @_ZN11WithDefaultD1Ev(
+// LLVM:         switch i32 %{{.*}}
+// LLVM:         call void @__cxa_end_catch()
+// LLVM:         switch i32 %{{.*}}
+// LLVM:         ret i32 %{{.*}}
+
+// LLVM:       [[T2L_RESUME]]:
+// LLVM:         resume { ptr, i32 }
+// LLVM:         ret i32
+
+// LLVM:       [[T2L_TERM]]:
+// LLVM:         landingpad { ptr, i32 }
+// LLVM:                 catch ptr null
+// LLVM:         call void @__clang_call_terminate(
+// LLVM:         unreachable
+
+// The catch-copy thunk is inlined away; no separate function definition.
+// LLVM-NOT: @__clang_cir_catch_copy__ZTS11WithDefault
+
+// --- OGCG ---
+
+// OGCG-LABEL: define {{.*}} i32 @_Z25test_copy_ctor_extra_argsv()
+// OGCG:       entry:
+// OGCG:         invoke void @_Z8mayThrowv()
+// OGCG:                 to label %[[O2_CONT:.*]] unwind label %[[O2_LPAD:.*]]
+
+// OGCG:       [[O2_LPAD]]:
+// OGCG:         landingpad { ptr, i32 }
+// OGCG:                 catch ptr @_ZTI11WithDefault
+
+// OGCG:       catch.dispatch:
+// OGCG:         %[[O2_TYPEID:.*]] = call i32 @llvm.eh.typeid.for.p0(ptr 
@_ZTI11WithDefault)
+// OGCG:         icmp eq i32 %{{.*}}, %[[O2_TYPEID]]
+// OGCG:         br i1 %{{.*}}, label %[[O2_CATCH:.*]], label %eh.resume
+
+// OGCG:       [[O2_CATCH]]:
+// OGCG:         %[[O2_ADJ:.*]] = call ptr @__cxa_get_exception_ptr(ptr 
%{{.*}})
+// OGCG:         invoke void @_ZN11WithDefaultC1ERKS_i(ptr {{.*}} %{{.*}}, ptr 
{{.*}} %[[O2_ADJ]], i32 {{.*}} 42)
+// OGCG:                 to label %[[O2_INVOKE_CONT1:.*]] unwind label 
%[[O2_TERM:.*]]
+
+// OGCG:       [[O2_INVOKE_CONT1]]:
+// OGCG:         call ptr @__cxa_begin_catch(
+// OGCG:         store i32 0, ptr %{{.*}}
+// OGCG:         call void @_ZN11WithDefaultD1Ev(
+// OGCG:         call void @__cxa_end_catch()
+// OGCG:         br label %return
+
+// OGCG:       try.cont:
+// OGCG:         store i32 -1, ptr %{{.*}}
+// OGCG:         br label %return
+
+// OGCG:       return:
+// OGCG:         load i32, ptr %{{.*}}
+// OGCG:         ret i32
+
+// OGCG:       eh.resume:
+// OGCG:         resume { ptr, i32 }
+
+// OGCG:       [[O2_TERM]]:
+// OGCG:         landingpad { ptr, i32 }
+// OGCG:                 catch ptr null
+// OGCG:         call void @__clang_call_terminate(
+
+//===----------------------------------------------------------------------===//
+// Module-level checks (runtime helpers materialized by EHABI lowering).
+//
+// These come last so they aren't partitioned by any per-function LABEL.
+//===----------------------------------------------------------------------===//
+
+// CIR-AFTER-EHABI: cir.func private @__cxa_begin_catch(
+// CIR-AFTER-EHABI: cir.func private @__cxa_end_catch()
+// CIR-AFTER-EHABI: cir.func private @__cxa_get_exception_ptr(
+// CIR-AFTER-EHABI: cir.func linkonce_odr hidden @__clang_call_terminate(
+// CIR-AFTER-EHABI: cir.func private @_ZSt9terminatev()

>From f43b903c8ae59021297f8d5a58a4740086edfe65 Mon Sep 17 00:00:00 2001
From: Andy Kaylor <[email protected]>
Date: Fri, 8 May 2026 13:47:28 -0700
Subject: [PATCH 2/2] Address review feedback

---
 .../CodeGen/try-catch-non-trivial-copy.cpp    | 52 ++++++-------------
 1 file changed, 15 insertions(+), 37 deletions(-)

diff --git a/clang/test/CIR/CodeGen/try-catch-non-trivial-copy.cpp 
b/clang/test/CIR/CodeGen/try-catch-non-trivial-copy.cpp
index c1413700e0c70..af458bdb0f73d 100644
--- a/clang/test/CIR/CodeGen/try-catch-non-trivial-copy.cpp
+++ b/clang/test/CIR/CodeGen/try-catch-non-trivial-copy.cpp
@@ -48,11 +48,11 @@ int test_non_trivial_exception_copy() {
 // CIR:           %[[E:.*]] = cir.alloca !rec_MyException, 
!cir.ptr<!rec_MyException>, ["e"]
 // CIR:           cir.try {
 // CIR:             cir.call @_Z8mayThrowv() : () -> ()
-// CIR:           } catch [type #cir.global_view<@_ZTI11MyException> : 
!cir.ptr<!u8i>] (%arg0: !cir.eh_token {{.*}}) {
-// CIR:             cir.construct_catch_param non_trivial_copy %arg0 to %[[E]] 
using @__clang_cir_catch_copy__ZTS11MyException : !cir.ptr<!rec_MyException>
-// CIR:             %catch_token, %exn_ptr = cir.begin_catch %arg0 : 
!cir.eh_token -> (!cir.catch_token, !cir.ptr<!void>)
+// CIR:           } catch [type #cir.global_view<@_ZTI11MyException> : 
!cir.ptr<!u8i>] (%[[EH_TOKEN:.*]]: !cir.eh_token {{.*}}) {
+// CIR:             cir.construct_catch_param non_trivial_copy %[[EH_TOKEN]] 
to %[[E]] using @__clang_cir_catch_copy__ZTS11MyException : 
!cir.ptr<!rec_MyException>
+// CIR:             %[[CATCH_TOKEN:.*]], %[[EXN_PTR:.*]] = cir.begin_catch 
%[[EH_TOKEN]] : !cir.eh_token -> (!cir.catch_token, !cir.ptr<!void>)
 // CIR:             cir.cleanup.scope {
-// CIR:               cir.init_catch_param non_trivial_copy %exn_ptr to %[[E]] 
: !cir.ptr<!void>, !cir.ptr<!rec_MyException>
+// CIR:               cir.init_catch_param non_trivial_copy %[[EXN_PTR]] to 
%[[E]] : !cir.ptr<!void>, !cir.ptr<!rec_MyException>
 // CIR:               cir.cleanup.scope {
 // CIR:                 %[[GET:.*]] = cir.call @_ZN11MyException3getEv(%[[E]]) 
: (!cir.ptr<!rec_MyException> {{.*}}) -> (!s32i {{.*}})
 // CIR:                 cir.store{{.*}} %[[GET]], %[[RV]]
@@ -63,18 +63,18 @@ int test_non_trivial_exception_copy() {
 // CIR:               }
 // CIR:               cir.yield
 // CIR:             } cleanup all {
-// CIR:               cir.end_catch %catch_token : !cir.catch_token
+// CIR:               cir.end_catch %[[CATCH_TOKEN]] : !cir.catch_token
 // CIR:               cir.yield
 // CIR:             }
-// CIR:           } unwind (%arg0: !cir.eh_token {{.*}}) {
-// CIR:             cir.resume %arg0 : !cir.eh_token
+// CIR:           } unwind (%[[EH_TOKEN:.*]]: !cir.eh_token {{.*}}) {
+// CIR:             cir.resume %[[EH_TOKEN]] : !cir.eh_token
 // CIR:           }
 // CIR:         }
 // CIR:         cir.return
 
 // CIR-LABEL: cir.func linkonce_odr hidden 
@__clang_cir_catch_copy__ZTS11MyException
 // CIR-SAME:    attributes {cir.eh.catch_copy_thunk}
-// CIR:         cir.call @_ZN11MyExceptionC1ERKS_(%arg0, %arg1)
+// CIR:         cir.call @_ZN11MyExceptionC1ERKS_(%{{.*}}, %{{.*}})
 // CIR:         cir.return
 
 // --- CIR-FLAT (after hoist-allocas + flatten-cfg) ---
@@ -144,28 +144,6 @@ int test_non_trivial_exception_copy() {
 // Final return.
 // CIR-FLAT:         cir.return %{{.*}} : !s32i
 
-// --- CIR-AFTER-EHABI ---
-//
-// EH ABI lowering replaces:
-//  - `cir.eh.initiate`            -> `cir.eh.inflight_exception [@RTTI]`
-//  - `cir.eh.dispatch`            -> `cir.eh.typeid` + `cir.cmp` + 
`cir.brcond`
-//  - `cir.construct_catch_param`  -> `__cxa_get_exception_ptr` + the thunk's
-//                                    body cloned inline. Plain `cir.call`s
-//                                    inside the cloned body that may unwind
-//                                    are wrapped in a `cir.try_call` whose
-//                                    unwind edge is a terminate block;
-//                                    any `cir.resume.flat` in the inlined
-//                                    body is rewritten to a direct call to
-//                                    `__clang_call_terminate`. After this
-//                                    pass the thunk function itself is dead
-//                                    and is removed by the post-lowering
-//                                    sweep.
-//  - `cir.begin_catch`            -> `__cxa_get_exception_ptr` (preceding the
-//                                    inlined copy) + `__cxa_begin_catch`
-//                                    (after)
-//  - `cir.end_catch`              -> `__cxa_end_catch`
-//  - `cir.resume`                 -> `cir.resume.flat`
-
 // CIR-AFTER-EHABI-LABEL: cir.func {{.*}} 
@_Z31test_non_trivial_exception_copyv()
 // CIR-AFTER-EHABI:         cir.try_call @_Z8mayThrowv() 
^[[T1E_CONT:bb[0-9]+]], ^[[T1E_LPAD:bb[0-9]+]]
 
@@ -297,7 +275,7 @@ int test_non_trivial_exception_copy() {
 // OGCG:       catch.dispatch:
 // OGCG:         %[[O1_TYPEID:.*]] = call i32 @llvm.eh.typeid.for.p0(ptr 
@_ZTI11MyException)
 // OGCG:         %[[O1_MATCH:.*]] = icmp eq i32 %{{.*}}, %[[O1_TYPEID]]
-// OGCG:         br i1 %[[O1_MATCH]], label %[[O1_CATCH:.*]], label %eh.resume
+// OGCG:         br i1 %[[O1_MATCH]], label %[[O1_CATCH:.*]], label 
%[[EH_RESUME:.*]]
 
 // OGCG:       [[O1_CATCH]]:
 // OGCG:         %[[O1_ADJ:.*]] = call ptr @__cxa_get_exception_ptr(ptr 
%{{.*}})
@@ -326,7 +304,7 @@ int test_non_trivial_exception_copy() {
 // OGCG:         invoke void @__cxa_end_catch()
 // OGCG:                 to label %{{.*}} unwind label %[[O1_TERM]]
 
-// OGCG:       eh.resume:
+// OGCG:       [[EH_RESUME]]:
 // OGCG:         resume { ptr, i32 }
 
 // OGCG:       [[O1_TERM]]:
@@ -520,7 +498,7 @@ int test_copy_ctor_extra_args() {
 // OGCG:       catch.dispatch:
 // OGCG:         %[[O2_TYPEID:.*]] = call i32 @llvm.eh.typeid.for.p0(ptr 
@_ZTI11WithDefault)
 // OGCG:         icmp eq i32 %{{.*}}, %[[O2_TYPEID]]
-// OGCG:         br i1 %{{.*}}, label %[[O2_CATCH:.*]], label %eh.resume
+// OGCG:         br i1 %{{.*}}, label %[[O2_CATCH:.*]], label %[[EH_RESUME:.*]]
 
 // OGCG:       [[O2_CATCH]]:
 // OGCG:         %[[O2_ADJ:.*]] = call ptr @__cxa_get_exception_ptr(ptr 
%{{.*}})
@@ -532,13 +510,13 @@ int test_copy_ctor_extra_args() {
 // OGCG:         store i32 0, ptr %{{.*}}
 // OGCG:         call void @_ZN11WithDefaultD1Ev(
 // OGCG:         call void @__cxa_end_catch()
-// OGCG:         br label %return
+// OGCG:         br label %[[RETURN:.*]]
 
-// OGCG:       try.cont:
+// OGCG:       [[TRY_CONT:.*]]:
 // OGCG:         store i32 -1, ptr %{{.*}}
-// OGCG:         br label %return
+// OGCG:         br label %[[RETURN:.*]]
 
-// OGCG:       return:
+// OGCG:       [[RETURN]]:
 // OGCG:         load i32, ptr %{{.*}}
 // OGCG:         ret i32
 

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

Reply via email to