https://github.com/erichkeane updated 
https://github.com/llvm/llvm-project/pull/229436

>From a357737d99bfe560a4dab013d47a8925282a8747 Mon Sep 17 00:00:00 2001
From: erichkeane <[email protected]>
Date: Tue, 6 Oct 2026 07:12:56 -0700
Subject: [PATCH 1/2] [CIR] Implement ctor-try-body rethrow

This came up in a test suite, but we weren't properly re-throwing
exceptions when they were in the body of a constructor's try-body.  This
patch mirrors classic-codegen's behavior reasonably well, implementing
this behavior properly.

Side note: this mirrors classic codegen's behavior of including
dtor-try-bodies too, but that isn't implemented yet, so those will just
be an NYI for now.
---
 clang/lib/CIR/CodeGen/CIRGenException.cpp | 20 +++++--
 clang/lib/CIR/CodeGen/CIRGenFunction.cpp  |  3 +-
 clang/lib/CIR/CodeGen/CIRGenFunction.h    |  3 +-
 clang/test/CIR/CodeGen/ctor-try-body.cpp  | 70 ++++++++++++++++++++++-
 4 files changed, 87 insertions(+), 9 deletions(-)

diff --git a/clang/lib/CIR/CodeGen/CIRGenException.cpp 
b/clang/lib/CIR/CodeGen/CIRGenException.cpp
index bd3e2014756e68..14afb80967be9f 100644
--- a/clang/lib/CIR/CodeGen/CIRGenException.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenException.cpp
@@ -609,9 +609,8 @@ void CIRGenFunction::emitBeginCatch(const CXXCatchStmt 
*catchStmt,
                  catchStmt->getBeginLoc());
 }
 
-mlir::LogicalResult
-CIRGenFunction::emitCXXTryStmt(const CXXTryStmt &s,
-                               cxxTryBodyEmitter &bodyCallback) {
+mlir::LogicalResult CIRGenFunction::emitCXXTryStmt(
+    const CXXTryStmt &s, cxxTryBodyEmitter &bodyCallback, bool isFnTryBlock) {
   mlir::Location loc = getLoc(s.getSourceRange());
 
   // Create a scope to hold try local storage for catch params.
@@ -700,6 +699,12 @@ CIRGenFunction::emitCXXTryStmt(const CXXTryStmt &s,
   tryOp.setHandlerTypesAttr(
       mlir::ArrayAttr::get(&getMLIRContext(), handlerAttrs));
 
+  // Determine if we need an implicit rethrow for all these catch handlers;
+  // see the comment below.
+  const bool doImplicitRethrow =
+      isFnTryBlock && (isa<CXXConstructorDecl>(curCodeDecl) ||
+                       isa<CXXDestructorDecl>(curCodeDecl));
+
   // Emit the catch handler bodies. This has to be done after the try op is
   // created and in place so that we can find the insertion point for the
   // catch parameter alloca.
@@ -736,8 +741,13 @@ CIRGenFunction::emitCXXTryStmt(const CXXTryStmt &s,
     //   The currently handled exception is rethrown if control
     //   reaches the end of a handler of the function-try-block of a
     //   constructor or destructor.
-
-    // TODO(cir): Handle implicit rethrow?
+    //
+    // It is important that we only do this on fallthrough and not on
+    // return.  Note that it's illegal to put a return in a
+    // constructor function-try-block's catch handler (p14), so this
+    // really only applies to destructors.
+    if (doImplicitRethrow && haveInsertPoint())
+      cgm.getCXXABI().emitRethrow(*this, /*isNoReturn=*/true);
 
     // Fall out through the catch cleanups.
     handlerScope.forceCleanup();
diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp 
b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
index 382a0008113e22..b6dedcc913d5be 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
@@ -881,7 +881,8 @@ void CIRGenFunction::emitConstructorBody(FunctionArgList 
&args) {
 
   ctorTryBodyEmitter emitter{ctor, ctorType, args, isTryBody, body};
   mlir::LogicalResult bodyRes =
-      isTryBody ? emitCXXTryStmt(*cast<CXXTryStmt>(body), emitter)
+      isTryBody ? emitCXXTryStmt(*cast<CXXTryStmt>(body), emitter,
+                                 /*isFnTryBlock=*/true)
                 : emitter(*this);
 
   // TODO(cir): propagate this result via mlir::logical result. Just
diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h 
b/clang/lib/CIR/CodeGen/CIRGenFunction.h
index c6427d60a37926..f715f661f8e125 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.h
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h
@@ -2159,7 +2159,8 @@ class CIRGenFunction : public CIRGenTypeCache {
   void emitBeginCatch(const CXXCatchStmt *catchStmt, mlir::Value ehToken);
 
   mlir::LogicalResult emitCXXTryStmt(const clang::CXXTryStmt &s,
-                                     cxxTryBodyEmitter &bodyCallback);
+                                     cxxTryBodyEmitter &bodyCallback,
+                                     bool isFnTryBlock = false);
   mlir::LogicalResult emitCXXTryStmt(const clang::CXXTryStmt &s);
 
   void emitCtorPrologue(const clang::CXXConstructorDecl *ctor,
diff --git a/clang/test/CIR/CodeGen/ctor-try-body.cpp 
b/clang/test/CIR/CodeGen/ctor-try-body.cpp
index 730d736ecd8b0e..83659aaf9527a0 100644
--- a/clang/test/CIR/CodeGen/ctor-try-body.cpp
+++ b/clang/test/CIR/CodeGen/ctor-try-body.cpp
@@ -5,6 +5,64 @@
 // RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fexceptions 
-fcxx-exceptions -emit-llvm %s -o %t.ll
 // RUN: FileCheck --input-file=%t.ll %s --check-prefix=LLVM,OGCG
 
+void mayThrow();
+
+struct S {
+  S(int) {}
+  S();
+  ~S() {}
+};
+
+S::S() try : S(1) {
+  mayThrow();
+} catch (...) {
+}
+
+// CIR: cir.func {{.*}} @_ZN1SC2Ev(
+// CIR:   cir.scope {
+// CIR:     cir.try {
+// CIR:       cir.call @_ZN1SC2Ei(
+// CIR:       cir.cleanup.scope {
+// CIR:         cir.call @_Z8mayThrowv() : () -> ()
+// CIR:         cir.yield
+// CIR:       } cleanup eh {
+// CIR:         cir.call @_ZN1SD2Ev({{.*}}) nothrow
+// CIR:         cir.yield
+// CIR:       }
+// CIR:       cir.yield
+// CIR:     } catch all ({{.*}}: !cir.eh_token{{.*}}) {
+// CIR:       %[[CATCH_TOK:.*]], %[[EXN_PTR:.*]] = cir.begin_catch {{.*}} : 
!cir.eh_token -> (!cir.catch_token, !cir.ptr<!void>)
+// CIR:       cir.cleanup.scope {
+// CIR:         cir.throw
+// CIR:         cir.unreachable
+// CIR:       ^bb1:
+// CIR:         cir.yield
+// CIR:       } cleanup all {
+// CIR:         cir.end_catch %[[CATCH_TOK]] : !cir.catch_token
+// CIR:         cir.yield
+// CIR:       }
+// CIR:       cir.yield
+// CIR:     }
+// CIR:   }
+// CIR:   cir.return
+// CIR: }
+
+// LLVM: define {{.*}} void @_ZN1SC2Ev(
+// LLVM:   invoke void @_ZN1SC2Ei(
+// LLVM:   invoke void @_Z8mayThrowv()
+// LLVM:   call void @_ZN1SD2Ev({{.*}})
+// LLVM:   call ptr @__cxa_begin_catch(
+// LLVM:   invoke void @__cxa_rethrow()
+// LLVM:     to label %[[UNREACHABLE_DEST:.*]] unwind label 
%[[CLEANUP_LPAD:.*]]
+// LLVM: [[CLEANUP_LPAD]]:
+// LLVM:   landingpad { ptr, i32 }
+// LLVM:     cleanup
+// LLVMCIR:   call void @__cxa_end_catch()
+// OGCG:   invoke void @__cxa_end_catch()
+// LLVM:   resume { ptr, i32 }
+// LLVM: [[UNREACHABLE_DEST]]:
+// LLVM:   unreachable
+
 struct Ctor {
   Ctor();
 };
@@ -46,12 +104,15 @@ struct HasThings : Base {
 // CIR-NEXT:      cir.call @_Z11side_effectv() : () -> ()
 // CIR-NEXT:      cir.yield
 // CIR-NEXT:    } catch all (%[[CATCH_ARG:.*]]: !cir.eh_token {{.*}}) {
-// CIR-NEXT:      %[[CATCH_TOK:.*]], %[[EX_PTR:.*]] = cir.begin_catch 
%[[CATCH_ARG]] : !cir.eh_token -> (!cir.catch_token, !cir.ptr<!void>)
+// CIR-NEXT:      %[[CATCH_TOK2:.*]], %[[EX_PTR:.*]] = cir.begin_catch 
%[[CATCH_ARG]] : !cir.eh_token -> (!cir.catch_token, !cir.ptr<!void>)
 // CIR-NEXT:      cir.cleanup.scope {
 // CIR-NEXT:        cir.call @_Z12side_effect2v() : () -> ()
+// CIR-NEXT:        cir.throw
+// CIR-NEXT:        cir.unreachable
+// CIR-NEXT:      ^bb1:
 // CIR-NEXT:        cir.yield
 // CIR-NEXT:      } cleanup all {
-// CIR-NEXT:        cir.end_catch %[[CATCH_TOK]] : !cir.catch_token
+// CIR-NEXT:        cir.end_catch %[[CATCH_TOK2]] : !cir.catch_token
 // CIR-NEXT:        cir.yield
 // CIR-NEXT:      }
 // CIR-NEXT:      cir.yield
@@ -70,6 +131,11 @@ struct HasThings : Base {
 // LLVM:   invoke void @_Z11side_effectv()
 // LLVM:   call ptr @__cxa_begin_catch(ptr %{{.*}})
 // LLVM:   invoke void @_Z12side_effect2v()
+// LLVM:   invoke void @__cxa_rethrow()
+// LLVM:     unwind label %[[CLEANUP_LPAD2:.*]]
+// LLVM: [[CLEANUP_LPAD2]]:
+// LLVM:   landingpad { ptr, i32 }
+// LLVM:     cleanup
 // LLVMCIR:   call void @__cxa_end_catch()
 // OGCG:   invoke void @__cxa_end_catch()
 };

>From 891fa4c0b710d85463ec442923c6e247b0e7a42e Mon Sep 17 00:00:00 2001
From: erichkeane <[email protected]>
Date: Tue, 6 Oct 2026 14:51:39 -0700
Subject: [PATCH 2/2] Fixup test mistake

---
 clang/lib/CIR/CodeGen/CIRGenException.cpp | 2 +-
 clang/lib/CIR/CodeGen/CIRGenFunction.h    | 9 +++++++++
 clang/test/CIR/CodeGen/ctor-try-body.cpp  | 8 ++++----
 3 files changed, 14 insertions(+), 5 deletions(-)

diff --git a/clang/lib/CIR/CodeGen/CIRGenException.cpp 
b/clang/lib/CIR/CodeGen/CIRGenException.cpp
index 14afb80967be9f..29510dc4b9a95a 100644
--- a/clang/lib/CIR/CodeGen/CIRGenException.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenException.cpp
@@ -746,7 +746,7 @@ mlir::LogicalResult CIRGenFunction::emitCXXTryStmt(
     // return.  Note that it's illegal to put a return in a
     // constructor function-try-block's catch handler (p14), so this
     // really only applies to destructors.
-    if (doImplicitRethrow && haveInsertPoint())
+    if (doImplicitRethrow && insertionPointIsReachable())
       cgm.getCXXABI().emitRethrow(*this, /*isNoReturn=*/true);
 
     // Fall out through the catch cleanups.
diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h 
b/clang/lib/CIR/CodeGen/CIRGenFunction.h
index f715f661f8e125..c4963806c815b4 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.h
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h
@@ -669,6 +669,15 @@ class CIRGenFunction : public CIRGenTypeCache {
     return builder.getInsertionBlock() != nullptr;
   }
 
+  /// True if code emitted at the builder's insertion point can be reached.
+  /// After emitting a terminator CIRGen opens a fresh block to continue in, so
+  /// the insertion block holds unreachable code whenever it is neither its
+  /// region's entry block nor the target of a branch.
+  bool insertionPointIsReachable() const {
+    mlir::Block *block = builder.getInsertionBlock();
+    return block && (block->isEntryBlock() || !block->hasNoPredecessors());
+  }
+
   // Wrapper for function prototype sources. Wraps either a FunctionProtoType 
or
   // an ObjCMethodDecl.
   struct PrototypeWrapper {
diff --git a/clang/test/CIR/CodeGen/ctor-try-body.cpp 
b/clang/test/CIR/CodeGen/ctor-try-body.cpp
index 83659aaf9527a0..a0016fad95ee22 100644
--- a/clang/test/CIR/CodeGen/ctor-try-body.cpp
+++ b/clang/test/CIR/CodeGen/ctor-try-body.cpp
@@ -104,7 +104,7 @@ struct HasThings : Base {
 // CIR-NEXT:      cir.call @_Z11side_effectv() : () -> ()
 // CIR-NEXT:      cir.yield
 // CIR-NEXT:    } catch all (%[[CATCH_ARG:.*]]: !cir.eh_token {{.*}}) {
-// CIR-NEXT:      %[[CATCH_TOK2:.*]], %[[EX_PTR:.*]] = cir.begin_catch 
%[[CATCH_ARG]] : !cir.eh_token -> (!cir.catch_token, !cir.ptr<!void>)
+// CIR-NEXT:      %[[CATCH_TOK:.*]], %[[EX_PTR:.*]] = cir.begin_catch 
%[[CATCH_ARG]] : !cir.eh_token -> (!cir.catch_token, !cir.ptr<!void>)
 // CIR-NEXT:      cir.cleanup.scope {
 // CIR-NEXT:        cir.call @_Z12side_effect2v() : () -> ()
 // CIR-NEXT:        cir.throw
@@ -112,7 +112,7 @@ struct HasThings : Base {
 // CIR-NEXT:      ^bb1:
 // CIR-NEXT:        cir.yield
 // CIR-NEXT:      } cleanup all {
-// CIR-NEXT:        cir.end_catch %[[CATCH_TOK2]] : !cir.catch_token
+// CIR-NEXT:        cir.end_catch %[[CATCH_TOK]] : !cir.catch_token
 // CIR-NEXT:        cir.yield
 // CIR-NEXT:      }
 // CIR-NEXT:      cir.yield
@@ -132,8 +132,8 @@ struct HasThings : Base {
 // LLVM:   call ptr @__cxa_begin_catch(ptr %{{.*}})
 // LLVM:   invoke void @_Z12side_effect2v()
 // LLVM:   invoke void @__cxa_rethrow()
-// LLVM:     unwind label %[[CLEANUP_LPAD2:.*]]
-// LLVM: [[CLEANUP_LPAD2]]:
+// LLVM:     unwind label %[[CLEANUP_LPAD:.*]]
+// LLVM: [[CLEANUP_LPAD]]:
 // LLVM:   landingpad { ptr, i32 }
 // LLVM:     cleanup
 // LLVMCIR:   call void @__cxa_end_catch()

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

Reply via email to