Branch: refs/heads/davem/condref_fix
Home: https://github.com/Perl/perl5
Commit: c885aa2beb87b082941c129fd6dedf0b994320fa
https://github.com/Perl/perl5/commit/c885aa2beb87b082941c129fd6dedf0b994320fa
Author: David Mitchell <[email protected]>
Date: 2025-11-11 (Tue, 11 Nov 2025)
Changed paths:
M op.c
M t/op/ref.t
M t/run/todo.t
Log Message:
-----------
propagate correct ref context to both ?: branches
GH #18669
In something like
@{ expr } = ...
the expression is expected to return an array ref. If the expression
is something like $h{foo}, then the helem op needs to know both that:
- it is in lvalue context, so should autovivify the foo element if not
present;
- it is in array ref context, so it should autovivify the value to an
empty array ref, rather than just to undef.
The function Perl_doref() is used to propagate this ref context at
compile time, e.g. by setting the OPf_MOD and OPpDEREF_AV flags on the
OP_HELEM op.
My commit v5.31.1-87-ge9b0092a10 made this function non-recursive
(so that deep expressions wouldn't SEGV during compilation), but
introduced a bug when the expression included the ternary condition
operator, '?:'.
In particular, since '?:' is the only OP where doref() needs to recurse
down *two* branches, I made the function just iterate down the tree, and
then have special handling for OP_COND_EXPR. This involved, once having
finished iterating down the tree, to work back up the tree looking for
OP_COND_EXPR nodes, and if found, iterate back down the second branch.
This had a fatal flaw: a 'type' variable indicated what context to
apply. For example in @{$h{expr}} = ..., type would start off as
OP_RV2AV, but as the tree was walked, would change to OP_HELEM and then
to OP_RV2HV. When walking back up the tree, this value wasn't being restored.
The specific bug in the ticket boiled down to something like
@{ $cond ? $h{p} : $h{q} } = ...;
where the correct OPpDEREF_AV flag was being set on the first helem op,
but an incorrect OPpDEREF_HV on the second.
Since I can't think of anything better, the fix in this commit restores
some limited recursion to doref(). Namely, for an OP_COND_EXPR op, it
now recurses down that op's first branch, then after it returns,
iterates as normal down the second branch.
Thus extremely deeply nested ternary code like:
@{ $c1 ? $c2 ? $c3 ? .... } ...
could start to SEGV during compilation again.
Commit: 2faee6b142a7cfa20e67eae0383cd1f8b3c9ed5f
https://github.com/Perl/perl5/commit/2faee6b142a7cfa20e67eae0383cd1f8b3c9ed5f
Author: David Mitchell <[email protected]>
Date: 2025-11-11 (Tue, 11 Nov 2025)
Changed paths:
M op.c
Log Message:
-----------
Perl_doref(): eliminate duplicated code
This compile-time function propagates lvalue ref context down a chain of
ops. It does the same thing (setting OPf_MOD and OPpDEREF_XV flags) in
three places. Consolidate this code into a single place.
Should be no functional changes.
Technically the code is slightly different in that OP_[AH]ELEM now
checks for kids before following them, but since they always have kids,
this makes no difference (except being infinitesimally slower during
compilation).
Commit: 859c02d48888d2475109ed05a0858f91d64daea9
https://github.com/Perl/perl5/commit/859c02d48888d2475109ed05a0858f91d64daea9
Author: David Mitchell <[email protected]>
Date: 2025-11-11 (Tue, 11 Nov 2025)
Changed paths:
M op.c
Log Message:
-----------
Perl_doref(): improve code comments
Having just messed with this function, I understand it better, so can
comment it better.
Compare: https://github.com/Perl/perl5/compare/c885aa2beb87%5E...859c02d48888
To unsubscribe from these emails, change your notification settings at
https://github.com/Perl/perl5/settings/notifications