op.c: In newBINOP, set up op_last before CHECKOP
authorFather Chrysostomos <sprout@cpan.org>
Sun, 21 Sep 2014 06:33:26 +0000 (23:33 -0700)
committerFather Chrysostomos <sprout@cpan.org>
Sat, 11 Oct 2014 04:54:05 +0000 (21:54 -0700)
Set up op_last pointers in newBINOP before calling the op-specific
ck_* routine.

That way, since this op sub-tree is well-formed from the outset, we
don’t need as much fix-up code elsewhere to account for the case where
the binop has been embedded inside a larger op tree (state var ini-
tialisation).

The repetition operator is an odd bird.  If the lhs is a list of one
item, it is effectively an unop, though still of class binop.  Though
op_last would usually point to the last immediate child, it ended
up null instead.  B::Deparse was written to expect that, so let’s
keep it that way by setting it to null in ck_repeat, now that the
last = first->sibling assignment in newBINOP (which used to do it)
happens earlier.

op.c

diff --git a/op.c b/op.c
index 2b17d3e..fc93244 100644 (file)
--- a/op.c
+++ b/op.c
@@ -4410,16 +4410,16 @@ Perl_newBINOP(pTHX_ I32 type, I32 flags, OP *first, OP *last)
         last->op_sibling = (OP*)binop;
 #endif
 
-    binop = (BINOP*)CHECKOP(type, binop);
-    if (binop->op_next || binop->op_type != (OPCODE)type)
-       return (OP*)binop;
-
     binop->op_last = OP_SIBLING(binop->op_first);
 #ifdef PERL_OP_PARENT
     if (binop->op_last)
         binop->op_last->op_sibling = (OP*)binop;
 #endif
 
+    binop = (BINOP*)CHECKOP(type, binop);
+    if (binop->op_next || binop->op_type != (OPCODE)type)
+       return (OP*)binop;
+
     return fold_constants(op_integerize(op_std_init((OP *)binop)));
 }
 
@@ -9765,15 +9765,6 @@ Perl_ck_sassign(pTHX_ OP *o)
            condop->op_targ = target;
            other->op_targ = target;
 
-           /* Because we change the type of the op here, we will skip the
-              assignment binop->op_last = OP_SIBLING(binop->op_first); at the
-              end of Perl_newBINOP(). So need to do it here. */
-           cBINOPo->op_last = OP_SIBLING(cBINOPo->op_first);
-            cBINOPo->op_first->op_lastsib = 0;
-            cBINOPo->op_last ->op_lastsib = 1;
-#ifdef PERL_OP_PARENT
-            cBINOPo->op_last->op_sibling = o;
-#endif
            return nullop;
        }
     }
@@ -9872,6 +9863,7 @@ Perl_ck_repeat(pTHX_ OP *o)
         kids = op_sibling_splice(o, NULL, -1, NULL); /* detach all kids */
         kids = force_list(kids, 1); /* promote them to a list */
         op_sibling_splice(o, NULL, 0, kids); /* and add back */
+        if (cBINOPo->op_last == kids) cBINOPo->op_last = NULL;
     }
     else
        scalar(o);