This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
sassign was used as UNOP, optimize {or,and,dor}assign
authorReini Urban <rurban@cpanel.net>
Thu, 29 Sep 2016 15:20:52 +0000 (16:20 +0100)
committerDavid Mitchell <davem@iabyn.com>
Thu, 29 Sep 2016 16:01:15 +0000 (17:01 +0100)
commit354eabfa08c1e2f5d83c116c6f072a4e1f3a62ff
tree4637a886a683b9bb28b5e702f4bac218d687cf06
parent1257c0814cb385a65f4175daa8be8b51e151e4ec
sassign was used as UNOP, optimize {or,and,dor}assign

[ DAPM:
  To clarify: OP_SASSIGN normally has two args, and is allocated as a
  BINOP. However, in something like $x ||= 1,  the optree looks like:

    4        <|> orassign(other->5) vK/1 ->7
    -           <1> ex-rv2sv sKRM/1 ->4
    3              <#> gvsv[*x] s ->4
    6           <1> sassign sK/BKWARD,1 ->7
    5              <$> const[IV 1] s ->6

  Here the sassign only has a single arg, since the other arg is already
  left on the stack after orassign has executed.

  In this case, perl was allocating the op as a UNOP, which causes
  problems with any code which assumes op_last contains a valid pointer.
  This commit changes it so that the op is always allocated as a BINOP,
  even when it only has one arg. In that case, it sets op_last to NULL
  (but see the next commit).

  Setting OPpASSIGN_BACKWARDS earlier is just a simplification of the
  code.
]

In newASSIGNOP with {or,and,dor}assign, the rhs was wrongly compiled as UNOP sassign.
It caused DEBUGGING corruption in the op finalizer for sassign (first not
pointing to last without sibling) and added random chunk to the last field.
It was never used though, as only {or,and,dor}assign used this op_other op.

{or,and,dor}assign needs the sassign with OPpASSIGN_BACKWARDS, set it
directly, not later in the LOGOP.

finalize_op needs a special case for it, as the last is empty there.
op.c
pp_hot.c