On 3/4/26 10:38 AM, Jakub Jelinek wrote:
On Wed, Mar 04, 2026 at 09:27:01AM +0100, Jakub Jelinek wrote:
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.
If that throws, we keep it as is and return. If (!is_complex), we
can in that case keep a value cached for the TARGET_EXPR_SLOT. For
*non_constant_p I think that is a non-issue, but for *jump_target
it can still be a constant expression.
The following patch fixes it by calling put_value in that case for
the !is_complex case.
I'm leaning towards calling it regardless of the is_complex value, but
I was going to suggest that, but...
don't have a testcase right now (would need to have say some TARGET_EXPR
with VOID_TYPE TARGET_EXPR_INITIAL which calls a function to initialize
the slot and perhaps stores something into it but then throws).
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.
Jason