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.
/* 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);
/* 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);
--- /dev/null
+/* PR c++/103012 Exception handling with multiversioned functions */
+/* { dg-do run } */
+/* { dg-require-ifunc "" } */
+
+extern "C" void abort (void);
+
+__attribute__((target("default")))
+void f() {
+ throw 1;
+}
+
+__attribute__((target("sse4.2,bmi")))
+void f() {
+ throw 2;
+}
+
+int main()
+{
+ try {
+ f();
+ }
+ catch(...)
+ {
+ return 0;
+ }
+
+ abort ();
+}