Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Objective C: use C++ exceptions on MinGW+GNUstep #77255

Merged
merged 1 commit into from
Jan 10, 2024

Conversation

qmfrederik
Copy link
Contributor

@qmfrederik qmfrederik commented Jan 7, 2024

The GNUstep Objective C runtime (libobjc2) is adding support for the GNU ABI on Windows (more specifically, MinGW). The libobjc2 runtime uses C++ exceptions in that configuration; this PR updates clang to act accordingly.

The corresponding change to libobjc2 is here: gnustep/libobjc2#267

Copy link

github-actions bot commented Jan 7, 2024

Thank you for submitting a Pull Request (PR) to the LLVM Project!

This PR will be automatically labeled and the relevant teams will be
notified.

If you wish to, you can add reviewers by using the "Reviewers" section on this page.

If this is not working for you, it is probably because you do not have write
permissions for the repository. In which case you can instead tag reviewers by
name in a comment by using @ followed by their GitHub username.

If you have received no comments on your PR for a week, you can request a review
by "ping"ing the PR by adding a comment “Ping”. The common courtesy "ping" rate
is once a week. Please remember that you are asking for valuable time from other developers.

If you have further questions, they may be answered by the LLVM GitHub User Guide.

You can also ask questions in a comment on this PR, on the LLVM Discord or on the forums.

@llvmbot
Copy link
Member

llvmbot commented Jan 7, 2024

@llvm/pr-subscribers-clang

@llvm/pr-subscribers-clang-codegen

Author: Frederik Carlier (qmfrederik)

Changes

The GNUstep Objective C runtime (libobjc2) is adding support for MinGW. This runtime uses C++ exceptions in that configuration.


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

3 Files Affected:

  • (modified) clang/lib/CodeGen/CGException.cpp (+11-7)
  • (modified) clang/lib/CodeGen/CGObjCGNU.cpp (+16-4)
  • (added) clang/test/CodeGenObjC/exceptions-personality.m (+53)
diff --git a/clang/lib/CodeGen/CGException.cpp b/clang/lib/CodeGen/CGException.cpp
index 0d507da5c1ba92..939f7962dcc635 100644
--- a/clang/lib/CodeGen/CGException.cpp
+++ b/clang/lib/CodeGen/CGException.cpp
@@ -145,8 +145,6 @@ static const EHPersonality &getCPersonality(const TargetInfo &Target,
 static const EHPersonality &getObjCPersonality(const TargetInfo &Target,
                                                const LangOptions &L) {
   const llvm::Triple &T = Target.getTriple();
-  if (T.isWindowsMSVCEnvironment())
-    return EHPersonality::MSVC_CxxFrameHandler3;
 
   switch (L.ObjCRuntime.getKind()) {
   case ObjCRuntime::FragileMacOSX:
@@ -156,7 +154,11 @@ 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 (T.isWindowsMSVCEnvironment())
+      return EHPersonality::MSVC_CxxFrameHandler3;
+    else if (L.ObjCRuntime.getVersion() >= VersionTuple(1, 7))
       return EHPersonality::GNUstep_ObjC;
     [[fallthrough]];
   case ObjCRuntime::GCC:
@@ -192,9 +194,6 @@ static const EHPersonality &getCXXPersonality(const TargetInfo &Target,
 /// and Objective-C exceptions are being caught.
 static const EHPersonality &getObjCXXPersonality(const TargetInfo &Target,
                                                  const LangOptions &L) {
-  if (Target.getTriple().isWindowsMSVCEnvironment())
-    return EHPersonality::MSVC_CxxFrameHandler3;
-
   switch (L.ObjCRuntime.getKind()) {
   // In the fragile ABI, just use C++ exception handling and hope
   // they're not doing crazy exception mixing.
@@ -210,7 +209,12 @@ static const EHPersonality &getObjCXXPersonality(const TargetInfo &Target,
     return getObjCPersonality(Target, L);
 
   case ObjCRuntime::GNUstep:
-    return EHPersonality::GNU_ObjCXX;
+    if (Target.getTriple().isWindowsMSVCEnvironment())
+      return EHPersonality::MSVC_CxxFrameHandler3;
+    else 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..5ace469c927045 100644
--- a/clang/lib/CodeGen/CGObjCGNU.cpp
+++ b/clang/lib/CodeGen/CGObjCGNU.cpp
@@ -819,7 +819,15 @@ 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) {
+      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);
@@ -2210,7 +2218,11 @@ 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 +2399,7 @@ 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 +4005,7 @@ 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
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
+@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

Copy link

github-actions bot commented Jan 7, 2024

✅ With the latest revision this PR passed the C/C++ code formatter.

@qmfrederik qmfrederik force-pushed the mingw-exceptions branch 2 times, most recently from 62d7da8 to d04a411 Compare January 7, 2024 21:11
@qmfrederik
Copy link
Contributor Author

/cc @davidchisnall

@qmfrederik qmfrederik force-pushed the mingw-exceptions branch 3 times, most recently from 4212c79 to d5dec27 Compare January 7, 2024 21:38
@davidchisnall davidchisnall self-assigned this Jan 8, 2024
@davidchisnall
Copy link
Contributor

The failing format CI isn’t in this PR, rebasing to (hopefully) fix it

if (Target.getTriple().isOSCygMing())
return EHPersonality::GNU_CPlusPlus_SEH;
else
return EHPersonality::GNU_ObjCXX;
Copy link
Member

Choose a reason for hiding this comment

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

This might be nicer as a ternary return.

// void objc_exception_rethrow(void*)
ExceptionReThrowFn.init(&CGM, "__cxa_rethrow", PtrTy);
} else if (usesSEHExceptions) {
llvm::Type *VoidTy = llvm::Type::getVoidTy(VMContext);
Copy link
Member

Choose a reason for hiding this comment

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

Why not hoist this? It is used across multiple branches.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good remark, thanks. Fixed this.

if (isRethrow && usesSEHExceptions) {
if (isRethrow &&
(usesSEHExceptions || (CGM.getTarget().getTriple().isOSCygMing() &&
isRuntime(ObjCRuntime::GNUstep, 2)))) {
Copy link
Member

Choose a reason for hiding this comment

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

Does it make sense to introduce a usesCxxExceptions variable?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, that makes the intent clearer. I changed this.

@qmfrederik
Copy link
Contributor Author

@compnerd Thanks for you feedback, I addressed your comments.

@qmfrederik qmfrederik force-pushed the mingw-exceptions branch 2 times, most recently from 2a97fae to a961488 Compare January 9, 2024 12:12
@qmfrederik
Copy link
Contributor Author

@compnerd @davidchisnall I've addressed the feedback and CI is (mostly) green. The build failure on Windows seems unrelated:

# Removing c:/ws\src
# Creating "c:/ws\src"
> git clone -v -- https://github.com/llvm-premerge-tests/llvm-project.git .
Cloning into '.'...
remote: Internal Server Error
fatal: unable to access 'https://github.com/llvm-premerge-tests/llvm-project.git/': The requested URL returned error: 500

@davidchisnall
Copy link
Contributor

I'd like CI to be green. Hopefully the failure is transient, but I don't seem to be able to kick off a rerun. Maybe once others start passing, you can squash the two commits and force push to restart it?

@qmfrederik
Copy link
Contributor Author

Looks like there was an intermittent issue with GitHub, which should be resolved now. I've squashed and pushed. Fingers crossed!

@qmfrederik
Copy link
Contributor Author

CI looks green, let me know if there's anything else you need from me on this PR!

@@ -2210,7 +2219,11 @@ 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 (usesCxxExceptions) {
ExceptionReThrowFn.init(&CGM, "objc_exception_rethrow", VoidTy, IdTy);
Copy link
Member

Choose a reason for hiding this comment

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

I would say that a ternary to select between the exception model and identify the name would be better as you are just selecting the label.

@davidchisnall
Copy link
Contributor

It looks as if three tests are failing in CI:

Clang :: CodeGenObjC/2007-04-03-ObjcEH.m
Clang :: CodeGenObjC/exceptions-personality.m
Clang :: Coverage/codegen-gnu.m

The GNUstep Objective C runtime (libobjc2) is adding support for
MinGW.  This runtime uses C++ exceptions in that configuration.
@qmfrederik
Copy link
Contributor Author

@davidchisnall Apologies, that was a fat-finger mistake while addressing the latest feedback. CI is green now.

@davidchisnall davidchisnall merged commit 1d5106d into llvm:main Jan 10, 2024
4 checks passed
@qmfrederik qmfrederik deleted the mingw-exceptions branch January 10, 2024 16:54
justinfargnoli pushed a commit to justinfargnoli/llvm-project that referenced this pull request Jan 28, 2024
The GNUstep Objective C runtime (libobjc2) is adding support for the GNU
ABI on Windows (more specifically, MinGW). The libobjc2 runtime uses C++
exceptions in that configuration; this PR updates clang to act
accordingly.

The corresponding change to libobjc2 is here:
gnustep/libobjc2#267
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang:codegen clang Clang issues not falling into any other category objective-c objective-c++
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants