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
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;
Jakub