https://gcc.gnu.org/bugzilla/show_bug.cgi?id=126918

--- Comment #4 from GCC Commits <cvs-commit at gcc dot gnu.org> ---
The master branch has been updated by Jakub Jelinek <[email protected]>:

https://gcc.gnu.org/g:8aa30b41ec381846e4c08b78d437fd896d30f5da

commit r17-3400-g8aa30b41ec381846e4c08b78d437fd896d30f5da
Author: Jakub Jelinek <[email protected]>
Date:   Wed Aug 19 09:03:41 2026 +0200

    c++: Fix up constexpr catching of pointer-to-members [PR126918]

    The following patch fixes various problems with constexpr EH related to
    pointer-to-member types.
    http://eel.is/c++draft/except.handle#3.3
    and
    http://eel.is/c++draft/except.handle#3.4
    have some cases where the exception object type and handler type can be
    different.
    If handler type is a pointer type, this is implemented by __cxa_begin_catch
    returning the pointer by value rather than reference (pointer to the value
    actually), so the cast is done during returning the pointer.
    Unfortunately, for pointer-to-member types (both data and function) that is
    not the case, __cxa_begin_catch in that case returns pointer to the
    pointer-to-member type.
    At runtime libsupc++/pbase_type_info.cc (__do_catch) deals with the
    [except.handle]/(3.4) cases
          else if (typeid (*this) == typeid(__pointer_to_member_type_info))
            {
              if (__pointee->__is_function_p ())
                {
                  using pmf_type = void (__pbase_type_info::*)();
                  static const pmf_type pmf = nullptr;
                  *thr_obj = const_cast<pmf_type*>(&pmf);
                  return true;
                }
              else
                {
                  using pm_type = int __pbase_type_info::*;
                  static const pm_type pm = nullptr;
                  *thr_obj = const_cast<pm_type*>(&pm);
                  return true;
                }
            }
    and [except.handle]/(3.3) cases are done presumably by strict aliasing
    violation not visible to the compiler (runtime library returns address of
    the exception type and compiler emitted code reads it using different
    effective type).  E.g. for the foo case in the first testcase, the IL looks
    like
       <<< Unknown tree: handler

          {
            <<< Unknown tree: offset_type >>> p = *(<<< Unknown tree:
offset_type >>> &) D.2709;

            try
              {
                            register <<< Unknown tree: offset_type >>> *
D.2709;
                <<cleanup_point <<< Unknown tree: expr_stmt
                  (void) (D.2709 = (<<< Unknown tree: offset_type >>> *)
__cxa_begin_catch (__builtin_eh_pointer (0))) >>>>>;
                            <<< Unknown tree: offset_type >>> p = *(<<< Unknown
tree: offset_type >>> &) D.2709;
                return <retval> = p;
              }
            finally
              {
                __cxa_end_catch ();
              }
          } >>>
    so my attempt to use a TARGET_EXPR for the temporary didn't work,
    there is a CLEANUP_POINT_EXPR wrapping the D.2709 = __cxa_begin_catch (...)
    assignment created from cp_finish_decl that would be quite hard to avoid
(we
    already do that through ugly hacks for structured binding CWG2867 support,
    but it has consequences for e.g. coroutines etc.).
    The following patch instead creates special temporaries (as if heap
    allocated but more efficiently) that live just from the __cxa_begin_catch
    (or __cxa_get_exception_ptr) time to the corresponding __cxa_end_catch.
    They are stored in the caught_exception vector because attaching them
    as DECL_CHAIN of the exception object looks unsafe to me, the current
    exception could be queried and thrown again before the catch parameter
    goes out of scope.

    Also, I had to tweak handler_match_for_exception_type, because it only
    handled pointer-to-data-member and not all pointer-to-member types
    that [except.handle]/3 requires.

    2026-08-19  Jakub Jelinek  <[email protected]>

            PR c++/126918
            * constexpr.cc (class constexpr_global_ctx): Extend description of
            caught_exceptions vector.
            (cxx_eval_cxa_builtin_fn): When catching a pointer-to-member and
            the current exception is nullptr or pointer-to-member with
different
            type, create a temporary, initialize it from the exception value
and
            return address of it.  Make sure to free these temporaries at
            __cxa_end_catch time.
            * call.cc (handler_match_for_exception_type): Allow NULLPTR_TYPE
            exception type or different pointer-to-member type even for
            TYPE_PTRMEMFUNC_P types, not just TYPE_PTRDATAMEM_P types.

            * g++.dg/cpp26/constexpr-eh24.C: New test.
            * g++.dg/cpp26/constexpr-eh25.C: New test.

    Reviewed-by: Jason Merrill <[email protected]>

Reply via email to