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