Skip to content

Conversation

@AmrDeveloper
Copy link
Member

Upstream the EHPersonality class for a function as a prerequisite for working with the handlers

Issue #154992

@llvmbot llvmbot added clang Clang issues not falling into any other category ClangIR Anything related to the ClangIR project labels Oct 23, 2025
@llvmbot
Copy link
Member

llvmbot commented Oct 23, 2025

@llvm/pr-subscribers-clangir

Author: Amr Hesham (AmrDeveloper)

Changes

Upstream the EHPersonality class for a function as a prerequisite for working with the handlers

Issue #154992


Full diff: https://github.com/llvm/llvm-project/pull/164883.diff

3 Files Affected:

  • (modified) clang/lib/CIR/CodeGen/CIRGenCleanup.h (+49)
  • (modified) clang/lib/CIR/CodeGen/CIRGenException.cpp (+165)
  • (modified) clang/lib/CIR/CodeGen/CIRGenFunction.h (+2)
diff --git a/clang/lib/CIR/CodeGen/CIRGenCleanup.h b/clang/lib/CIR/CodeGen/CIRGenCleanup.h
index 9acf8b1f20e79..61a09a59b05c0 100644
--- a/clang/lib/CIR/CodeGen/CIRGenCleanup.h
+++ b/clang/lib/CIR/CodeGen/CIRGenCleanup.h
@@ -15,6 +15,7 @@
 #define CLANG_LIB_CIR_CODEGEN_CIRGENCLEANUP_H
 
 #include "Address.h"
+#include "CIRGenModule.h"
 #include "EHScopeStack.h"
 #include "mlir/IR/Value.h"
 
@@ -257,5 +258,53 @@ inline void EHScopeStack::popCatch() {
   deallocate(EHCatchScope::getSizeForNumHandlers(scope.getNumHandlers()));
 }
 
+/// The exceptions personality for a function.
+struct EHPersonality {
+  const char *personalityFn = nullptr;
+
+  // If this is non-null, this personality requires a non-standard
+  // function for rethrowing an exception after a catchall cleanup.
+  // This function must have prototype void(void*).
+  const char *catchallRethrowFn = nullptr;
+
+  static const EHPersonality &get(CIRGenModule &cgm,
+                                  const clang::FunctionDecl *fd);
+  static const EHPersonality &get(CIRGenFunction &cgf);
+
+  static const EHPersonality GNU_C;
+  static const EHPersonality GNU_C_SJLJ;
+  static const EHPersonality GNU_C_SEH;
+  static const EHPersonality GNU_ObjC;
+  static const EHPersonality GNU_ObjC_SJLJ;
+  static const EHPersonality GNU_ObjC_SEH;
+  static const EHPersonality GNUstep_ObjC;
+  static const EHPersonality GNU_ObjCXX;
+  static const EHPersonality NeXT_ObjC;
+  static const EHPersonality GNU_CPlusPlus;
+  static const EHPersonality GNU_CPlusPlus_SJLJ;
+  static const EHPersonality GNU_CPlusPlus_SEH;
+  static const EHPersonality MSVC_except_handler;
+  static const EHPersonality MSVC_C_specific_handler;
+  static const EHPersonality MSVC_CxxFrameHandler3;
+  static const EHPersonality GNU_Wasm_CPlusPlus;
+  static const EHPersonality XL_CPlusPlus;
+  static const EHPersonality ZOS_CPlusPlus;
+
+  /// Does this personality use landingpads or the family of pad instructions
+  /// designed to form funclets?
+  bool usesFuncletPads() const {
+    return isMSVCPersonality() || isWasmPersonality();
+  }
+
+  bool isMSVCPersonality() const {
+    return this == &MSVC_except_handler || this == &MSVC_C_specific_handler ||
+           this == &MSVC_CxxFrameHandler3;
+  }
+
+  bool isWasmPersonality() const { return this == &GNU_Wasm_CPlusPlus; }
+
+  bool isMSVCXXPersonality() const { return this == &MSVC_CxxFrameHandler3; }
+};
+
 } // namespace clang::CIRGen
 #endif // CLANG_LIB_CIR_CODEGEN_CIRGENCLEANUP_H
diff --git a/clang/lib/CIR/CodeGen/CIRGenException.cpp b/clang/lib/CIR/CodeGen/CIRGenException.cpp
index 717a3e0032cea..67f46ffde8fda 100644
--- a/clang/lib/CIR/CodeGen/CIRGenException.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenException.cpp
@@ -18,6 +18,171 @@
 using namespace clang;
 using namespace clang::CIRGen;
 
+const EHPersonality EHPersonality::GNU_C = {"__gcc_personality_v0", nullptr};
+const EHPersonality EHPersonality::GNU_C_SJLJ = {"__gcc_personality_sj0",
+                                                 nullptr};
+const EHPersonality EHPersonality::GNU_C_SEH = {"__gcc_personality_seh0",
+                                                nullptr};
+const EHPersonality EHPersonality::NeXT_ObjC = {"__objc_personality_v0",
+                                                nullptr};
+const EHPersonality EHPersonality::GNU_CPlusPlus = {"__gxx_personality_v0",
+                                                    nullptr};
+const EHPersonality EHPersonality::GNU_CPlusPlus_SJLJ = {
+    "__gxx_personality_sj0", nullptr};
+const EHPersonality EHPersonality::GNU_CPlusPlus_SEH = {
+    "__gxx_personality_seh0", nullptr};
+const EHPersonality EHPersonality::GNU_ObjC = {"__gnu_objc_personality_v0",
+                                               "objc_exception_throw"};
+const EHPersonality EHPersonality::GNU_ObjC_SJLJ = {
+    "__gnu_objc_personality_sj0", "objc_exception_throw"};
+const EHPersonality EHPersonality::GNU_ObjC_SEH = {
+    "__gnu_objc_personality_seh0", "objc_exception_throw"};
+const EHPersonality EHPersonality::GNU_ObjCXX = {
+    "__gnustep_objcxx_personality_v0", nullptr};
+const EHPersonality EHPersonality::GNUstep_ObjC = {
+    "__gnustep_objc_personality_v0", nullptr};
+const EHPersonality EHPersonality::MSVC_except_handler = {"_except_handler3",
+                                                          nullptr};
+const EHPersonality EHPersonality::MSVC_C_specific_handler = {
+    "__C_specific_handler", nullptr};
+const EHPersonality EHPersonality::MSVC_CxxFrameHandler3 = {
+    "__CxxFrameHandler3", nullptr};
+const EHPersonality EHPersonality::GNU_Wasm_CPlusPlus = {
+    "__gxx_wasm_personality_v0", nullptr};
+const EHPersonality EHPersonality::XL_CPlusPlus = {"__xlcxx_personality_v1",
+                                                   nullptr};
+const EHPersonality EHPersonality::ZOS_CPlusPlus = {"__zos_cxx_personality_v2",
+                                                    nullptr};
+
+static const EHPersonality &getCPersonality(const TargetInfo &target,
+                                            const CodeGenOptions &cgOpts) {
+  const llvm::Triple &triple = target.getTriple();
+  if (triple.isWindowsMSVCEnvironment())
+    return EHPersonality::MSVC_CxxFrameHandler3;
+  if (cgOpts.hasSjLjExceptions())
+    return EHPersonality::GNU_C_SJLJ;
+  if (cgOpts.hasDWARFExceptions())
+    return EHPersonality::GNU_C;
+  if (cgOpts.hasSEHExceptions())
+    return EHPersonality::GNU_C_SEH;
+  return EHPersonality::GNU_C;
+}
+
+static const EHPersonality &getObjCPersonality(const TargetInfo &target,
+                                               const LangOptions &langOpts,
+                                               const CodeGenOptions &cgOpts) {
+  const llvm::Triple &triple = target.getTriple();
+  if (triple.isWindowsMSVCEnvironment())
+    return EHPersonality::MSVC_CxxFrameHandler3;
+
+  switch (langOpts.ObjCRuntime.getKind()) {
+  case ObjCRuntime::FragileMacOSX:
+    return getCPersonality(target, cgOpts);
+  case ObjCRuntime::MacOSX:
+  case ObjCRuntime::iOS:
+  case ObjCRuntime::WatchOS:
+    return EHPersonality::NeXT_ObjC;
+  case ObjCRuntime::GNUstep:
+    if (langOpts.ObjCRuntime.getVersion() >= VersionTuple(1, 7))
+      return EHPersonality::GNUstep_ObjC;
+    [[fallthrough]];
+  case ObjCRuntime::GCC:
+  case ObjCRuntime::ObjFW:
+    if (cgOpts.hasSjLjExceptions())
+      return EHPersonality::GNU_ObjC_SJLJ;
+    if (cgOpts.hasSEHExceptions())
+      return EHPersonality::GNU_ObjC_SEH;
+    return EHPersonality::GNU_ObjC;
+  }
+  llvm_unreachable("bad runtime kind");
+}
+
+static const EHPersonality &getCXXPersonality(const TargetInfo &target,
+                                              const CodeGenOptions &cgOpts) {
+  const llvm::Triple &triple = target.getTriple();
+  if (triple.isWindowsMSVCEnvironment())
+    return EHPersonality::MSVC_CxxFrameHandler3;
+  if (triple.isOSAIX())
+    return EHPersonality::XL_CPlusPlus;
+  if (cgOpts.hasSjLjExceptions())
+    return EHPersonality::GNU_CPlusPlus_SJLJ;
+  if (cgOpts.hasDWARFExceptions())
+    return EHPersonality::GNU_CPlusPlus;
+  if (cgOpts.hasSEHExceptions())
+    return EHPersonality::GNU_CPlusPlus_SEH;
+  if (cgOpts.hasWasmExceptions())
+    return EHPersonality::GNU_Wasm_CPlusPlus;
+  return EHPersonality::GNU_CPlusPlus;
+}
+
+/// Determines the personality function to use when both C++
+/// and Objective-C exceptions are being caught.
+static const EHPersonality &getObjCXXPersonality(const TargetInfo &target,
+                                                 const LangOptions &langOpts,
+                                                 const CodeGenOptions &cgOpts) {
+  if (target.getTriple().isWindowsMSVCEnvironment())
+    return EHPersonality::MSVC_CxxFrameHandler3;
+
+  switch (langOpts.ObjCRuntime.getKind()) {
+  // In the fragile ABI, just use C++ exception handling and hope
+  // they're not doing crazy exception mixing.
+  case ObjCRuntime::FragileMacOSX:
+    return getCXXPersonality(target, cgOpts);
+
+  // The ObjC personality defers to the C++ personality for non-ObjC
+  // handlers.  Unlike the C++ case, we use the same personality
+  // function on targets using (backend-driven) SJLJ EH.
+  case ObjCRuntime::MacOSX:
+  case ObjCRuntime::iOS:
+  case ObjCRuntime::WatchOS:
+    return getObjCPersonality(target, langOpts, cgOpts);
+
+  case ObjCRuntime::GNUstep:
+    return EHPersonality::GNU_ObjCXX;
+
+  // The GCC runtime's personality function inherently doesn't support
+  // mixed EH.  Use the ObjC personality just to avoid returning null.
+  case ObjCRuntime::GCC:
+  case ObjCRuntime::ObjFW:
+    return getObjCPersonality(target, langOpts, cgOpts);
+  }
+  llvm_unreachable("bad runtime kind");
+}
+
+static const EHPersonality &getSEHPersonalityMSVC(const llvm::Triple &triple) {
+  return triple.getArch() == llvm::Triple::x86
+             ? EHPersonality::MSVC_except_handler
+             : EHPersonality::MSVC_C_specific_handler;
+}
+
+const EHPersonality &EHPersonality::get(CIRGenModule &cgm,
+                                        const FunctionDecl *fd) {
+  const llvm::Triple &triple = cgm.getTarget().getTriple();
+  const LangOptions &langOpts = cgm.getLangOpts();
+  const CodeGenOptions &cgOpts = cgm.getCodeGenOpts();
+  const TargetInfo &target = cgm.getTarget();
+
+  // Functions using SEH get an SEH personality.
+  if (fd && fd->usesSEHTry())
+    return getSEHPersonalityMSVC(triple);
+
+  if (langOpts.ObjC) {
+    return langOpts.CPlusPlus ? getObjCXXPersonality(target, langOpts, cgOpts)
+                              : getObjCPersonality(target, langOpts, cgOpts);
+  }
+  return langOpts.CPlusPlus ? getCXXPersonality(target, cgOpts)
+                            : getCPersonality(target, cgOpts);
+}
+
+const EHPersonality &EHPersonality::get(CIRGenFunction &cgf) {
+  const auto *fg = cgf.curCodeDecl;
+  // For outlined finallys and filters, use the SEH personality in case they
+  // contain more SEH. This mostly only affects finallys. Filters could
+  // hypothetically use gnu statement expressions to sneak in nested SEH.
+  fg = fg ? fg : cgf.curSEHParent.getDecl();
+  return get(cgf.cgm, dyn_cast_or_null<FunctionDecl>(fg));
+}
+
 void CIRGenFunction::emitCXXThrowExpr(const CXXThrowExpr *e) {
   const llvm::Triple &triple = getTarget().getTriple();
   if (cgm.getLangOpts().OpenMPIsTargetDevice &&
diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h b/clang/lib/CIR/CodeGen/CIRGenFunction.h
index 5f9dbdc64b9e5..5249b6a8c2afd 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.h
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h
@@ -120,6 +120,8 @@ class CIRGenFunction : public CIRGenTypeCache {
   /// Tracks function scope overall cleanup handling.
   EHScopeStack ehStack;
 
+  GlobalDecl curSEHParent;
+
   llvm::DenseMap<const clang::ValueDecl *, clang::FieldDecl *>
       lambdaCaptureFields;
   clang::FieldDecl *lambdaThisCaptureField = nullptr;

@llvmbot
Copy link
Member

llvmbot commented Oct 23, 2025

@llvm/pr-subscribers-clang

Author: Amr Hesham (AmrDeveloper)

Changes

Upstream the EHPersonality class for a function as a prerequisite for working with the handlers

Issue #154992


Full diff: https://github.com/llvm/llvm-project/pull/164883.diff

3 Files Affected:

  • (modified) clang/lib/CIR/CodeGen/CIRGenCleanup.h (+49)
  • (modified) clang/lib/CIR/CodeGen/CIRGenException.cpp (+165)
  • (modified) clang/lib/CIR/CodeGen/CIRGenFunction.h (+2)
diff --git a/clang/lib/CIR/CodeGen/CIRGenCleanup.h b/clang/lib/CIR/CodeGen/CIRGenCleanup.h
index 9acf8b1f20e79..61a09a59b05c0 100644
--- a/clang/lib/CIR/CodeGen/CIRGenCleanup.h
+++ b/clang/lib/CIR/CodeGen/CIRGenCleanup.h
@@ -15,6 +15,7 @@
 #define CLANG_LIB_CIR_CODEGEN_CIRGENCLEANUP_H
 
 #include "Address.h"
+#include "CIRGenModule.h"
 #include "EHScopeStack.h"
 #include "mlir/IR/Value.h"
 
@@ -257,5 +258,53 @@ inline void EHScopeStack::popCatch() {
   deallocate(EHCatchScope::getSizeForNumHandlers(scope.getNumHandlers()));
 }
 
+/// The exceptions personality for a function.
+struct EHPersonality {
+  const char *personalityFn = nullptr;
+
+  // If this is non-null, this personality requires a non-standard
+  // function for rethrowing an exception after a catchall cleanup.
+  // This function must have prototype void(void*).
+  const char *catchallRethrowFn = nullptr;
+
+  static const EHPersonality &get(CIRGenModule &cgm,
+                                  const clang::FunctionDecl *fd);
+  static const EHPersonality &get(CIRGenFunction &cgf);
+
+  static const EHPersonality GNU_C;
+  static const EHPersonality GNU_C_SJLJ;
+  static const EHPersonality GNU_C_SEH;
+  static const EHPersonality GNU_ObjC;
+  static const EHPersonality GNU_ObjC_SJLJ;
+  static const EHPersonality GNU_ObjC_SEH;
+  static const EHPersonality GNUstep_ObjC;
+  static const EHPersonality GNU_ObjCXX;
+  static const EHPersonality NeXT_ObjC;
+  static const EHPersonality GNU_CPlusPlus;
+  static const EHPersonality GNU_CPlusPlus_SJLJ;
+  static const EHPersonality GNU_CPlusPlus_SEH;
+  static const EHPersonality MSVC_except_handler;
+  static const EHPersonality MSVC_C_specific_handler;
+  static const EHPersonality MSVC_CxxFrameHandler3;
+  static const EHPersonality GNU_Wasm_CPlusPlus;
+  static const EHPersonality XL_CPlusPlus;
+  static const EHPersonality ZOS_CPlusPlus;
+
+  /// Does this personality use landingpads or the family of pad instructions
+  /// designed to form funclets?
+  bool usesFuncletPads() const {
+    return isMSVCPersonality() || isWasmPersonality();
+  }
+
+  bool isMSVCPersonality() const {
+    return this == &MSVC_except_handler || this == &MSVC_C_specific_handler ||
+           this == &MSVC_CxxFrameHandler3;
+  }
+
+  bool isWasmPersonality() const { return this == &GNU_Wasm_CPlusPlus; }
+
+  bool isMSVCXXPersonality() const { return this == &MSVC_CxxFrameHandler3; }
+};
+
 } // namespace clang::CIRGen
 #endif // CLANG_LIB_CIR_CODEGEN_CIRGENCLEANUP_H
diff --git a/clang/lib/CIR/CodeGen/CIRGenException.cpp b/clang/lib/CIR/CodeGen/CIRGenException.cpp
index 717a3e0032cea..67f46ffde8fda 100644
--- a/clang/lib/CIR/CodeGen/CIRGenException.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenException.cpp
@@ -18,6 +18,171 @@
 using namespace clang;
 using namespace clang::CIRGen;
 
+const EHPersonality EHPersonality::GNU_C = {"__gcc_personality_v0", nullptr};
+const EHPersonality EHPersonality::GNU_C_SJLJ = {"__gcc_personality_sj0",
+                                                 nullptr};
+const EHPersonality EHPersonality::GNU_C_SEH = {"__gcc_personality_seh0",
+                                                nullptr};
+const EHPersonality EHPersonality::NeXT_ObjC = {"__objc_personality_v0",
+                                                nullptr};
+const EHPersonality EHPersonality::GNU_CPlusPlus = {"__gxx_personality_v0",
+                                                    nullptr};
+const EHPersonality EHPersonality::GNU_CPlusPlus_SJLJ = {
+    "__gxx_personality_sj0", nullptr};
+const EHPersonality EHPersonality::GNU_CPlusPlus_SEH = {
+    "__gxx_personality_seh0", nullptr};
+const EHPersonality EHPersonality::GNU_ObjC = {"__gnu_objc_personality_v0",
+                                               "objc_exception_throw"};
+const EHPersonality EHPersonality::GNU_ObjC_SJLJ = {
+    "__gnu_objc_personality_sj0", "objc_exception_throw"};
+const EHPersonality EHPersonality::GNU_ObjC_SEH = {
+    "__gnu_objc_personality_seh0", "objc_exception_throw"};
+const EHPersonality EHPersonality::GNU_ObjCXX = {
+    "__gnustep_objcxx_personality_v0", nullptr};
+const EHPersonality EHPersonality::GNUstep_ObjC = {
+    "__gnustep_objc_personality_v0", nullptr};
+const EHPersonality EHPersonality::MSVC_except_handler = {"_except_handler3",
+                                                          nullptr};
+const EHPersonality EHPersonality::MSVC_C_specific_handler = {
+    "__C_specific_handler", nullptr};
+const EHPersonality EHPersonality::MSVC_CxxFrameHandler3 = {
+    "__CxxFrameHandler3", nullptr};
+const EHPersonality EHPersonality::GNU_Wasm_CPlusPlus = {
+    "__gxx_wasm_personality_v0", nullptr};
+const EHPersonality EHPersonality::XL_CPlusPlus = {"__xlcxx_personality_v1",
+                                                   nullptr};
+const EHPersonality EHPersonality::ZOS_CPlusPlus = {"__zos_cxx_personality_v2",
+                                                    nullptr};
+
+static const EHPersonality &getCPersonality(const TargetInfo &target,
+                                            const CodeGenOptions &cgOpts) {
+  const llvm::Triple &triple = target.getTriple();
+  if (triple.isWindowsMSVCEnvironment())
+    return EHPersonality::MSVC_CxxFrameHandler3;
+  if (cgOpts.hasSjLjExceptions())
+    return EHPersonality::GNU_C_SJLJ;
+  if (cgOpts.hasDWARFExceptions())
+    return EHPersonality::GNU_C;
+  if (cgOpts.hasSEHExceptions())
+    return EHPersonality::GNU_C_SEH;
+  return EHPersonality::GNU_C;
+}
+
+static const EHPersonality &getObjCPersonality(const TargetInfo &target,
+                                               const LangOptions &langOpts,
+                                               const CodeGenOptions &cgOpts) {
+  const llvm::Triple &triple = target.getTriple();
+  if (triple.isWindowsMSVCEnvironment())
+    return EHPersonality::MSVC_CxxFrameHandler3;
+
+  switch (langOpts.ObjCRuntime.getKind()) {
+  case ObjCRuntime::FragileMacOSX:
+    return getCPersonality(target, cgOpts);
+  case ObjCRuntime::MacOSX:
+  case ObjCRuntime::iOS:
+  case ObjCRuntime::WatchOS:
+    return EHPersonality::NeXT_ObjC;
+  case ObjCRuntime::GNUstep:
+    if (langOpts.ObjCRuntime.getVersion() >= VersionTuple(1, 7))
+      return EHPersonality::GNUstep_ObjC;
+    [[fallthrough]];
+  case ObjCRuntime::GCC:
+  case ObjCRuntime::ObjFW:
+    if (cgOpts.hasSjLjExceptions())
+      return EHPersonality::GNU_ObjC_SJLJ;
+    if (cgOpts.hasSEHExceptions())
+      return EHPersonality::GNU_ObjC_SEH;
+    return EHPersonality::GNU_ObjC;
+  }
+  llvm_unreachable("bad runtime kind");
+}
+
+static const EHPersonality &getCXXPersonality(const TargetInfo &target,
+                                              const CodeGenOptions &cgOpts) {
+  const llvm::Triple &triple = target.getTriple();
+  if (triple.isWindowsMSVCEnvironment())
+    return EHPersonality::MSVC_CxxFrameHandler3;
+  if (triple.isOSAIX())
+    return EHPersonality::XL_CPlusPlus;
+  if (cgOpts.hasSjLjExceptions())
+    return EHPersonality::GNU_CPlusPlus_SJLJ;
+  if (cgOpts.hasDWARFExceptions())
+    return EHPersonality::GNU_CPlusPlus;
+  if (cgOpts.hasSEHExceptions())
+    return EHPersonality::GNU_CPlusPlus_SEH;
+  if (cgOpts.hasWasmExceptions())
+    return EHPersonality::GNU_Wasm_CPlusPlus;
+  return EHPersonality::GNU_CPlusPlus;
+}
+
+/// Determines the personality function to use when both C++
+/// and Objective-C exceptions are being caught.
+static const EHPersonality &getObjCXXPersonality(const TargetInfo &target,
+                                                 const LangOptions &langOpts,
+                                                 const CodeGenOptions &cgOpts) {
+  if (target.getTriple().isWindowsMSVCEnvironment())
+    return EHPersonality::MSVC_CxxFrameHandler3;
+
+  switch (langOpts.ObjCRuntime.getKind()) {
+  // In the fragile ABI, just use C++ exception handling and hope
+  // they're not doing crazy exception mixing.
+  case ObjCRuntime::FragileMacOSX:
+    return getCXXPersonality(target, cgOpts);
+
+  // The ObjC personality defers to the C++ personality for non-ObjC
+  // handlers.  Unlike the C++ case, we use the same personality
+  // function on targets using (backend-driven) SJLJ EH.
+  case ObjCRuntime::MacOSX:
+  case ObjCRuntime::iOS:
+  case ObjCRuntime::WatchOS:
+    return getObjCPersonality(target, langOpts, cgOpts);
+
+  case ObjCRuntime::GNUstep:
+    return EHPersonality::GNU_ObjCXX;
+
+  // The GCC runtime's personality function inherently doesn't support
+  // mixed EH.  Use the ObjC personality just to avoid returning null.
+  case ObjCRuntime::GCC:
+  case ObjCRuntime::ObjFW:
+    return getObjCPersonality(target, langOpts, cgOpts);
+  }
+  llvm_unreachable("bad runtime kind");
+}
+
+static const EHPersonality &getSEHPersonalityMSVC(const llvm::Triple &triple) {
+  return triple.getArch() == llvm::Triple::x86
+             ? EHPersonality::MSVC_except_handler
+             : EHPersonality::MSVC_C_specific_handler;
+}
+
+const EHPersonality &EHPersonality::get(CIRGenModule &cgm,
+                                        const FunctionDecl *fd) {
+  const llvm::Triple &triple = cgm.getTarget().getTriple();
+  const LangOptions &langOpts = cgm.getLangOpts();
+  const CodeGenOptions &cgOpts = cgm.getCodeGenOpts();
+  const TargetInfo &target = cgm.getTarget();
+
+  // Functions using SEH get an SEH personality.
+  if (fd && fd->usesSEHTry())
+    return getSEHPersonalityMSVC(triple);
+
+  if (langOpts.ObjC) {
+    return langOpts.CPlusPlus ? getObjCXXPersonality(target, langOpts, cgOpts)
+                              : getObjCPersonality(target, langOpts, cgOpts);
+  }
+  return langOpts.CPlusPlus ? getCXXPersonality(target, cgOpts)
+                            : getCPersonality(target, cgOpts);
+}
+
+const EHPersonality &EHPersonality::get(CIRGenFunction &cgf) {
+  const auto *fg = cgf.curCodeDecl;
+  // For outlined finallys and filters, use the SEH personality in case they
+  // contain more SEH. This mostly only affects finallys. Filters could
+  // hypothetically use gnu statement expressions to sneak in nested SEH.
+  fg = fg ? fg : cgf.curSEHParent.getDecl();
+  return get(cgf.cgm, dyn_cast_or_null<FunctionDecl>(fg));
+}
+
 void CIRGenFunction::emitCXXThrowExpr(const CXXThrowExpr *e) {
   const llvm::Triple &triple = getTarget().getTriple();
   if (cgm.getLangOpts().OpenMPIsTargetDevice &&
diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h b/clang/lib/CIR/CodeGen/CIRGenFunction.h
index 5f9dbdc64b9e5..5249b6a8c2afd 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.h
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h
@@ -120,6 +120,8 @@ class CIRGenFunction : public CIRGenTypeCache {
   /// Tracks function scope overall cleanup handling.
   EHScopeStack ehStack;
 
+  GlobalDecl curSEHParent;
+
   llvm::DenseMap<const clang::ValueDecl *, clang::FieldDecl *>
       lambdaCaptureFields;
   clang::FieldDecl *lambdaThisCaptureField = nullptr;

Copy link
Member

@bcardosolopes bcardosolopes left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Content LGTM, but I have a pending question.

}

/// The exceptions personality for a function.
struct EHPersonality {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is is possible to abstract most of this (or if you tried) into a base class that could be shared between it and classic CG? Seems like 95% is the same but ::get methods. It can come as follow up PR, but I think we should handle this sooner than later. (cc @andykaylor)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I think it's possible and can also be done by one class with CodeGenModule and CodeGenFunction as a template parameters, and we can specialize the ::get method twice for both codegens 🤔.

I think that this case is also a good example for adding a shared codegen component.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you have the time it would be great to follow up on some of these refactoring (so it can open the road for easily incorporating later ones) before the GSoC term ends! Thanks again for working on this

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, I will do that 🫡

@AmrDeveloper AmrDeveloper merged commit b0658b1 into llvm:main Oct 25, 2025
13 checks passed
dvbuka pushed a commit to dvbuka/llvm-project that referenced this pull request Oct 27, 2025
Upstream the EHPersonality class for a function as a prerequisite for
working with the handlers

Issue llvm#154992
Lukacma pushed a commit to Lukacma/llvm-project that referenced this pull request Oct 29, 2025
Upstream the EHPersonality class for a function as a prerequisite for
working with the handlers

Issue llvm#154992
aokblast pushed a commit to aokblast/llvm-project that referenced this pull request Oct 30, 2025
Upstream the EHPersonality class for a function as a prerequisite for
working with the handlers

Issue llvm#154992
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

clang Clang issues not falling into any other category ClangIR Anything related to the ClangIR project

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants