https://gcc.gnu.org/bugzilla/show_bug.cgi?id=126918
--- Comment #2 from Jakub Jelinek <jakub at gcc dot gnu.org> --- Hopefully fixed up testcase, http://eel.is/c++draft/except.handle#3.4 says that the nullptr -> T & case is supported just for const T & (but I don't see libsupc++ implementing this (nor the current constexpr eh). // { dg-do compile { target c++26 } } struct S { int m, n; int foo (int x) { return x + 42; } }; constexpr int S::* foo (bool x) { if (x) return nullptr; try { throw nullptr; } catch (int S::*p) { return p; } return &S::m; } constexpr int S::*const & bar (bool x) { static constexpr int S::*sm = &S::m; if (x) return sm; try { throw nullptr; } catch (int S::*const &p) { return p; } return sm; } constexpr const int S::* baz (bool x) { if (x) return nullptr; try { throw &S::m; } catch (const int S::*p) { return p; } return nullptr; } constexpr const int S::*const & qux (bool x) { static const int S::*np = nullptr; if (x) return np; try { throw &S::m; } catch (const int S::*const &p) { return p; } return np; } using F = int (S::*) (int); constexpr F corge (bool x) { if (x) return nullptr; try { throw nullptr; } catch (F p) { return p; } return &S::foo; } constexpr F const & garply (bool x) { static constexpr F f = &S::foo; if (x) return f; try { throw nullptr; } catch (F const &p) { return p; } return f; } #if __cpp_constexpr_exceptions >= 202411L static_assert (foo (false) == nullptr); static_assert (bar (false) == nullptr); static_assert (baz (false) == &S::m); static_assert (qux (false) == &S::m); static_assert (corge (false) == nullptr); static_assert (garply (false) == nullptr); #endif int main () { if (foo (false) != nullptr || bar (false) != nullptr || baz (false) != &S::m || qux (false) != &S::m || corge (false) != nullptr || garply (false) != nullptr) __builtin_abort (); } Anyway, e.g. in gimple dump, the foo case looks in the IL as D.2698 = __cxa_begin_catch (_1); p = *D.2698; while the bar case looks like D.2712 = __cxa_begin_catch (_1); p = D.2712; So, either __cxa_begin_catch in these cases creates a TARGET_EXPR and get it destroyed when the catch parm goes out of scope, or it pretends to do a new and associates it with the exception object somehow (e.g. put it somehow into DECL_EXCEPTION_REFCOUNT) and let it be deleted when the exception object is deleted.
