[clang] Objective C: use C++ exceptions on MinGW+GNUstep (PR #77255)

Frederik Carlier via cfe-commits cfe-commits at lists.llvm.org
Sun Jan 7 13:36:23 PST 2024


https://github.com/qmfrederik updated https://github.com/llvm/llvm-project/pull/77255

>From d3e6d552b2502765eff8faccd20b7566a9362491 Mon Sep 17 00:00:00 2001
From: Frederik Carlier <frederik.carlier at keysight.com>
Date: Thu, 4 Jan 2024 11:10:05 -0800
Subject: [PATCH] Objective C: use C++ exceptions on MinGW+GNUstep

The GNUstep Objective C runtime (libobjc2) is adding support for
MinGW.  This runtime uses C++ exceptions in that configuration.
---
 clang/lib/CodeGen/CGException.cpp             |  9 +++-
 clang/lib/CodeGen/CGObjCGNU.cpp               | 35 ++++++++----
 .../test/CodeGenObjC/exceptions-personality.m | 53 +++++++++++++++++++
 3 files changed, 86 insertions(+), 11 deletions(-)
 create mode 100644 clang/test/CodeGenObjC/exceptions-personality.m

diff --git a/clang/lib/CodeGen/CGException.cpp b/clang/lib/CodeGen/CGException.cpp
index 0d507da5c1ba92..cadd6f6ad75daa 100644
--- a/clang/lib/CodeGen/CGException.cpp
+++ b/clang/lib/CodeGen/CGException.cpp
@@ -156,7 +156,9 @@ static const EHPersonality &getObjCPersonality(const TargetInfo &Target,
   case ObjCRuntime::WatchOS:
     return EHPersonality::NeXT_ObjC;
   case ObjCRuntime::GNUstep:
-    if (L.ObjCRuntime.getVersion() >= VersionTuple(1, 7))
+    if (T.isOSCygMing())
+      return EHPersonality::GNU_CPlusPlus_SEH;
+    else if (L.ObjCRuntime.getVersion() >= VersionTuple(1, 7))
       return EHPersonality::GNUstep_ObjC;
     [[fallthrough]];
   case ObjCRuntime::GCC:
@@ -210,7 +212,10 @@ static const EHPersonality &getObjCXXPersonality(const TargetInfo &Target,
     return getObjCPersonality(Target, L);
 
   case ObjCRuntime::GNUstep:
-    return EHPersonality::GNU_ObjCXX;
+    if (Target.getTriple().isOSCygMing())
+      return EHPersonality::GNU_CPlusPlus_SEH;
+    else
+      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.
diff --git a/clang/lib/CodeGen/CGObjCGNU.cpp b/clang/lib/CodeGen/CGObjCGNU.cpp
index 4ca1a8cce64d89..2b3a5da87fb778 100644
--- a/clang/lib/CodeGen/CGObjCGNU.cpp
+++ b/clang/lib/CodeGen/CGObjCGNU.cpp
@@ -819,10 +819,19 @@ class CGObjCGNUstep : public CGObjCGNU {
       SlotLookupSuperFn.init(&CGM, "objc_slot_lookup_super", SlotTy,
                              PtrToObjCSuperTy, SelectorTy);
       // If we're in ObjC++ mode, then we want to make
-      if (usesSEHExceptions) {
-          llvm::Type *VoidTy = llvm::Type::getVoidTy(VMContext);
-          // void objc_exception_rethrow(void)
-          ExceptionReThrowFn.init(&CGM, "objc_exception_rethrow", VoidTy);
+      if (CGM.getTarget().getTriple().isOSCygMing() &&
+          isRuntime(ObjCRuntime::GNUstep, 2)) {
+        llvm::Type *VoidTy = llvm::Type::getVoidTy(VMContext);
+        // void *__cxa_begin_catch(void *e)
+        EnterCatchFn.init(&CGM, "__cxa_begin_catch", PtrTy, PtrTy);
+        // void __cxa_end_catch(void)
+        ExitCatchFn.init(&CGM, "__cxa_end_catch", VoidTy);
+        // void objc_exception_rethrow(void*)
+        ExceptionReThrowFn.init(&CGM, "__cxa_rethrow", PtrTy);
+      } else if (usesSEHExceptions) {
+        llvm::Type *VoidTy = llvm::Type::getVoidTy(VMContext);
+        // void objc_exception_rethrow(void)
+        ExceptionReThrowFn.init(&CGM, "objc_exception_rethrow", VoidTy);
       } else if (CGM.getLangOpts().CPlusPlus) {
         llvm::Type *VoidTy = llvm::Type::getVoidTy(VMContext);
         // void *__cxa_begin_catch(void *e)
@@ -2210,7 +2219,12 @@ CGObjCGNU::CGObjCGNU(CodeGenModule &cgm, unsigned runtimeABIVersion,
 
   // void objc_exception_throw(id);
   ExceptionThrowFn.init(&CGM, "objc_exception_throw", VoidTy, IdTy);
-  ExceptionReThrowFn.init(&CGM, "objc_exception_throw", VoidTy, IdTy);
+  if ((CGM.getTarget().getTriple().isOSCygMing() &&
+       isRuntime(ObjCRuntime::GNUstep, 2))) {
+    ExceptionReThrowFn.init(&CGM, "objc_exception_rethrow", VoidTy, IdTy);
+  } else {
+    ExceptionReThrowFn.init(&CGM, "objc_exception_throw", VoidTy, IdTy);
+  }
   // int objc_sync_enter(id);
   SyncEnterFn.init(&CGM, "objc_sync_enter", IntTy, IdTy);
   // int objc_sync_exit(id);
@@ -2387,7 +2401,9 @@ llvm::Constant *CGObjCGNUstep::GetEHType(QualType T) {
   if (usesSEHExceptions)
     return CGM.getCXXABI().getAddrOfRTTIDescriptor(T);
 
-  if (!CGM.getLangOpts().CPlusPlus)
+  if (!CGM.getLangOpts().CPlusPlus &&
+      !(CGM.getTarget().getTriple().isOSCygMing() &&
+        isRuntime(ObjCRuntime::GNUstep, 2)))
     return CGObjCGNU::GetEHType(T);
 
   // For Objective-C++, we want to provide the ability to catch both C++ and
@@ -3993,7 +4009,9 @@ void CGObjCGNU::EmitThrowStmt(CodeGenFunction &CGF,
     ExceptionAsObject = CGF.ObjCEHValueStack.back();
     isRethrow = true;
   }
-  if (isRethrow && usesSEHExceptions) {
+  if (isRethrow &&
+      (usesSEHExceptions || (CGM.getTarget().getTriple().isOSCygMing() &&
+                             isRuntime(ObjCRuntime::GNUstep, 2)))) {
     // For SEH, ExceptionAsObject may be undef, because the catch handler is
     // not passed it for catchalls and so it is not visible to the catch
     // funclet.  The real thrown object will still be live on the stack at this
@@ -4003,8 +4021,7 @@ void CGObjCGNU::EmitThrowStmt(CodeGenFunction &CGF,
     // argument.
     llvm::CallBase *Throw = CGF.EmitRuntimeCallOrInvoke(ExceptionReThrowFn);
     Throw->setDoesNotReturn();
-  }
-  else {
+  } else {
     ExceptionAsObject = CGF.Builder.CreateBitCast(ExceptionAsObject, IdTy);
     llvm::CallBase *Throw =
         CGF.EmitRuntimeCallOrInvoke(ExceptionThrowFn, ExceptionAsObject);
diff --git a/clang/test/CodeGenObjC/exceptions-personality.m b/clang/test/CodeGenObjC/exceptions-personality.m
new file mode 100644
index 00000000000000..c29f7483715d88
--- /dev/null
+++ b/clang/test/CodeGenObjC/exceptions-personality.m
@@ -0,0 +1,53 @@
+// RUN: %clang_cc1 -triple x86_64-w64-windows-gnu  -emit-llvm -fobjc-runtime=gnustep-2.0 -fexceptions -fobjc-exceptions -o %t %s
+// RUN: FileCheck --check-prefixes=CHECK-MINGW-OBJC2 < %t %s
+
+// RUN: %clang_cc1 -triple x86_64-w64-windows-gnu  -emit-llvm -fobjc-runtime=gcc -fexceptions -fobjc-exceptions -o %t %s
+// RUN: FileCheck --check-prefixes=CHECK-MINGW-GCC < %t %s
+
+// RUN: %clang_cc1 -triple x86_64-w64-windows-msvc  -emit-llvm -fobjc-runtime=gnustep-2.0 -fexceptions -fobjc-exceptions -o %t %s
+// RUN: FileCheck --check-prefixes=CHECK-MSVC-OBJC2 < %t %s
+
+// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu  -emit-llvm -fobjc-runtime=gnustep-2.0 -fexceptions -fobjc-exceptions -o %t %s
+// RUN: FileCheck --check-prefixes=CHECK-LINUX-OBJC2 < %t %s
+
+// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu  -emit-llvm -fobjc-runtime=gcc -fexceptions -fobjc-exceptions -o %t %s
+// RUN: FileCheck --check-prefixes=CHECK-LINUX-GCC < %t %s
+ at interface Foo @end
+
+void throwing(void) {
+  @try
+  {
+    // CHECK-MINGW-OBJC2: personality ptr @__gxx_personality_seh0
+    // CHECK-MINGW-OBJC2: invoke void @objc_exception_throw
+
+    // CHECK-MINGW-GCC: personality ptr @__gnu_objc_personality_v0
+    // CHECK-MINGW-GCC: invoke void @objc_exception_throw
+
+    // CHECK-MSVC-OBJC2: personality ptr @__CxxFrameHandler3
+    // CHECK-MSVC-OBJC2: invoke void @objc_exception_throw
+
+    // CHECK-LINUX-OBJC2: personality ptr @__gnustep_objc_personality_v0
+    // CHECK-LINUX-OBJC2: invoke void @objc_exception_throw
+
+    // CHECK-LINUX-GCC: personality ptr @__gnu_objc_personality_v0
+    @throw(@"error!");
+  }
+  @catch(...) 
+  {
+    // CHECK-MINGW-OBJC2: call ptr @__cxa_begin_catch
+    // CHECK-MINGW-OBJC2: invoke ptr @__cxa_rethrow
+    // CHECK-MINGW-OBJC2: invoke void @__cxa_end_catch
+    
+    // CHECK-MINGW-GCC: call void @objc_exception_throw
+
+    // CHECK-MSVC-OBJC2: call void @objc_exception_rethrow
+
+    // CHECK-LINUX-OBJC2: call ptr @objc_begin_catch
+    // CHECK-LINUX-OBJC2: invoke void @objc_exception_throw
+    // CHECK-LINUX-OBJC2: invoke void @objc_end_catch()
+
+    // CHECK-LINUX-GCC: invoke void @objc_exception_throw
+    
+    @throw;
+  }
+}
\ No newline at end of file



More information about the cfe-commits mailing list