On Wed, Mar 04, 2026 at 12:56:38PM -0500, Jason Merrill wrote:
> > I've been worrying also about something like:
> > struct S { int s; };
> > 
> > constexpr S
> > foo (int x)
> > {
> >    return S { x };
> > }
> > 
> > constexpr int
> > bar (int x)
> > {
> >    return foo (x).s;
> > }
> > 
> > constexpr bool
> > baz ()
> > {
> >    if (bar (42) != 42)
> >      throw 1;
> > 
> >    if (bar (43) != 43)
> >      throw 2;
> >    return true;
> > }
> > 
> > static_assert (baz ());
> > but that works fine - if TARGET_EXPR_INITIAL doesn't throw (and isn't
> > non-constant), and it is wrapped into a CLEANUP_POINT_EXPR, that
> > CLEANUP_POINT_EXPR sets ctx->save_expr and TARGET_EXPR handling will
> > if (ctx->save_expr)
> >    ctx->save_exprs->safe_push (slot);
> > and then CLEANUP_POINT_EXPR handling will
> >          /* Forget SAVE_EXPRs and TARGET_EXPRs created by this
> >             full-expression.  */
> >          for (tree save_expr : save_exprs)
> >            destroy_value_checked (ctx, save_expr, non_constant_p);
> > Anyway, that means another way to fix this would be to move
> >          if (ctx->save_exprs)
> >            ctx->save_exprs->safe_push (slot);
> > before
> >          if (*jump_target)
> >            return NULL_TREE;
> 
> ...this sounds better.

Bootstrapped/regtested on x86_64-linux and i686-linux now, ok for trunk?

2026-03-05  Jakub Jelinek  <[email protected]>

        PR c++/124145
        * constexpr.cc (cxx_eval_constant_expression) <case TARGET_EXPR>: Move
        ctx->save_expr->safe_push (slot) call before if (*jump_target) test.
        Use TARGET_EXPR_INITIAL instead of TREE_OPERAND.

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

--- gcc/cp/constexpr.cc.jj      2026-03-03 15:43:28.514891948 +0100
+++ gcc/cp/constexpr.cc 2026-03-04 19:42:38.212514610 +0100
@@ -9486,11 +9486,13 @@ cxx_eval_constant_expression (const cons
 
        /* Pass vc_prvalue because this indicates
           initialization of a temporary.  */
-       r = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 1), vc_prvalue,
-                                         non_constant_p, overflow_p,
-                                         jump_target);
+       r = cxx_eval_constant_expression (ctx, TARGET_EXPR_INITIAL (t),
+                                         vc_prvalue, non_constant_p,
+                                         overflow_p, jump_target);
        if (*non_constant_p)
          break;
+       if (ctx->save_exprs)
+         ctx->save_exprs->safe_push (slot);
        if (*jump_target)
          return NULL_TREE;
        if (!is_complex)
@@ -9509,8 +9511,6 @@ cxx_eval_constant_expression (const cons
            if (CLEANUP_EH_ONLY (t))
              ctx->global->cleanups->safe_push (NULL_TREE);
          }
-       if (ctx->save_exprs)
-         ctx->save_exprs->safe_push (slot);
        if (lval)
          return slot;
        if (is_complex)
--- gcc/testsuite/g++.dg/cpp26/constexpr-eh18.C.jj      2026-03-03 
13:44:19.501639167 +0100
+++ gcc/testsuite/g++.dg/cpp26/constexpr-eh18.C 2026-03-03 13:43:51.868100042 
+0100
@@ -0,0 +1,42 @@
+// PR c++/124145
+// { dg-do compile { target c++26 } }
+
+struct S {};
+
+constexpr S
+foo (S x)
+{
+  throw 123;
+  return x;
+}
+
+constexpr void
+bar ()
+{
+  foo (S {});
+}
+
+constexpr bool
+baz ()
+{
+  try
+    {
+      bar ();
+      asm  ("");
+    }
+  catch (int)
+    {
+    }
+
+  try
+    {
+      bar ();
+      asm ("");
+    }
+  catch (int)
+    {
+    }
+  return true;
+}
+
+static_assert (baz ());


        Jakub

Reply via email to