[Bug c++/126918] constexpr exceptions and nullptr vs. pointer-to-member

"jakub at gcc dot gnu.org via Gcc-bugs" <[email protected]>
Newsgroups gmane.comp.gcc.bugs
Message-ID <[email protected]/bugzilla/>
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.
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.