https://gcc.gnu.org/g:0970bb8565616f61c6b7a7dd0edbc829b0064703

commit r16-7920-g0970bb8565616f61c6b7a7dd0edbc829b0064703
Author: Jakub Jelinek <[email protected]>
Date:   Thu Mar 5 21:43:55 2026 +0100

    c++: Avoid caching TARGET_EXPR slot value if exception is thrown from 
TARGET_EXPR_INITIAL [PR124145]
    
    The following testcase is miscompiled, we throw exception only during
    the first bar () call and not during the second and in that case reach
    the inline asm.
    The problem is that the TARGET_EXPR handling calls
                ctx->global->put_value (new_ctx.object, new_ctx.ctor);
    first for aggregate/vectors, then
            if (is_complex)
              /* In case no initialization actually happens, clear out any
                 void_node from a previous evaluation.  */
              ctx->global->put_value (slot, NULL_TREE);
    and then recurses on TARGET_EXPR_INITIAL.
    Even for is_complex it can actually store partially the result in the
    slot before throwing.
    
    When TARGET_EXPR_INITIAL doesn't throw, we do
      if (ctx->save_expr)
        ctx->save_expr->safe_push (slot);
    and that arranges for the value in slot be invalidated at the end of
    surrounding CLEANUP_POINT_EXPR.
    But in case when it does throw this isn't done.
    
    The following patch fixes it by moving that push to save_expr
    before the if (*jump_target) return NULL_TREE; check.
    
    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.

Diff:
---
 gcc/cp/constexpr.cc                         | 10 +++----
 gcc/testsuite/g++.dg/cpp26/constexpr-eh18.C | 42 +++++++++++++++++++++++++++++
 2 files changed, 47 insertions(+), 5 deletions(-)

diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc
index afd8d5731a11..aab10aa71252 100644
--- a/gcc/cp/constexpr.cc
+++ b/gcc/cp/constexpr.cc
@@ -9486,11 +9486,13 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, 
tree t,
 
        /* 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 constexpr_ctx *ctx, 
tree t,
            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)
diff --git a/gcc/testsuite/g++.dg/cpp26/constexpr-eh18.C 
b/gcc/testsuite/g++.dg/cpp26/constexpr-eh18.C
new file mode 100644
index 000000000000..a19cf4a3c589
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp26/constexpr-eh18.C
@@ -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 ());

Reply via email to