Hi,

This patch fixes PR106627. I ran the i386.exp tests on my x86_64-linux-gnu 
machine with a fully bootstrapped checkout. I also tested manually that no 
exception handling code is generated if none of the function versions throws an 
exception.
I don't have access to a machine to test the change to  rs6000.cc, but the code 
seems like an exact copy and I don't see a reason why it shouldn't work there 
the same way.

Regards
Simon Rainer

>From 6fcb1c742fa1d61048f7d63243225a8d1931af4a Mon Sep 17 00:00:00 2001
From: Simon Rainer <gcc....@vvalter.com>
Date: Wed, 31 Aug 2022 20:56:04 +0200
Subject: [PATCH] ipa: Fix throw in multi-versioned functions [PR106627]

Any multi-versioned function was implicitly declared as noexcept, which
leads to an abort if an exception is thrown inside the function.
The reason for this is that the function declaration is replaced by a
newly created dispatcher declaration, which has TREE_NOTHROW always set
to 1. Instead we need to set TREE_NOTHROW to the value of the original
declaration.

        PR ipa/106627

gcc/ChangeLog:

        * config/i386/i386-features.cc (ix86_get_function_versions_dispatcher): 
Set TREE_NOTHROW
                correctly for dispatcher declaration
        * config/rs6000/rs6000.cc (rs6000_get_function_versions_dispatcher): 
Likewise

gcc/testsuite/ChangeLog:

        * g++.target/i386/pr106627.C: New test.
---
 gcc/config/i386/i386-features.cc         |  1 +
 gcc/config/rs6000/rs6000.cc              |  1 +
 gcc/testsuite/g++.target/i386/pr106627.C | 30 ++++++++++++++++++++++++
 3 files changed, 32 insertions(+)
 create mode 100644 gcc/testsuite/g++.target/i386/pr106627.C

diff --git a/gcc/config/i386/i386-features.cc b/gcc/config/i386/i386-features.cc
index d6bb66cbe01..5b3b1aeff28 100644
--- a/gcc/config/i386/i386-features.cc
+++ b/gcc/config/i386/i386-features.cc
@@ -3268,6 +3268,7 @@ ix86_get_function_versions_dispatcher (void *decl)
 
       /* Right now, the dispatching is done via ifunc.  */
       dispatch_decl = make_dispatcher_decl (default_node->decl);
+      TREE_NOTHROW(dispatch_decl) = TREE_NOTHROW(fn);
 
       dispatcher_node = cgraph_node::get_create (dispatch_decl);
       gcc_assert (dispatcher_node != NULL);
diff --git a/gcc/config/rs6000/rs6000.cc b/gcc/config/rs6000/rs6000.cc
index 2f3146e56f8..9280da8a5c8 100644
--- a/gcc/config/rs6000/rs6000.cc
+++ b/gcc/config/rs6000/rs6000.cc
@@ -24861,6 +24861,7 @@ rs6000_get_function_versions_dispatcher (void *decl)
 
       /* Right now, the dispatching is done via ifunc.  */
       dispatch_decl = make_dispatcher_decl (default_node->decl);
+      TREE_NOTHROW(dispatch_decl) = TREE_NOTHROW(fn);
 
       dispatcher_node = cgraph_node::get_create (dispatch_decl);
       gcc_assert (dispatcher_node != NULL);
diff --git a/gcc/testsuite/g++.target/i386/pr106627.C 
b/gcc/testsuite/g++.target/i386/pr106627.C
new file mode 100644
index 00000000000..a67f5ae4813
--- /dev/null
+++ b/gcc/testsuite/g++.target/i386/pr106627.C
@@ -0,0 +1,30 @@
+/* PR c++/103012 Exception handling with multiversioned functions */
+/* { dg-do run } */
+/* { dg-require-ifunc "" }  */
+
+#include <assert.h>
+
+__attribute__((target("default")))
+void f() {
+    throw 1;
+}
+
+__attribute__((target("sse4.2,bmi")))
+void f() {
+    throw 2;
+}
+
+int main()
+{
+    try {
+        f();
+    }
+    catch(...)
+    {
+        return 0;
+    }
+
+    assert (false);
+    return 1;
+}
+
-- 
2.34.1

Reply via email to