This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Ensure that op_last always points to last sibling
[perl5.git] / op.c
diff --git a/op.c b/op.c
index eea56f8..57c1537 100644 (file)
--- a/op.c
+++ b/op.c
@@ -180,7 +180,6 @@ S_new_slab(pTHX_ size_t sz)
 void *
 Perl_Slab_Alloc(pTHX_ size_t sz)
 {
-    dVAR;
     OPSLAB *slab;
     OPSLAB *slab2;
     OPSLOT *slot;
@@ -333,7 +332,6 @@ Perl_Slab_to_rw(pTHX_ OPSLAB *const slab)
 void
 Perl_Slab_Free(pTHX_ void *op)
 {
-    dVAR;
     OP * const o = (OP *)op;
     OPSLAB *slab;
 
@@ -358,7 +356,6 @@ Perl_Slab_Free(pTHX_ void *op)
 void
 Perl_opslab_free_nopad(pTHX_ OPSLAB *slab)
 {
-    dVAR;
     const bool havepad = !!PL_comppad;
     PERL_ARGS_ASSERT_OPSLAB_FREE_NOPAD;
     if (havepad) {
@@ -372,9 +369,9 @@ Perl_opslab_free_nopad(pTHX_ OPSLAB *slab)
 void
 Perl_opslab_free(pTHX_ OPSLAB *slab)
 {
-    dVAR;
     OPSLAB *slab2;
     PERL_ARGS_ASSERT_OPSLAB_FREE;
+    PERL_UNUSED_CONTEXT;
     DEBUG_S_warn((aTHX_ "freeing slab %p", (void*)slab));
     assert(slab->opslab_refcnt == 1);
     for (; slab; slab = slab2) {
@@ -582,7 +579,6 @@ S_no_bareword_allowed(pTHX_ OP *o)
 PADOFFSET
 Perl_allocmy(pTHX_ const char *const name, const STRLEN len, const U32 flags)
 {
-    dVAR;
     PADOFFSET off;
     const bool is_our = (PL_parser->in_my == KEY_our);
 
@@ -706,7 +702,9 @@ optree.
 void
 Perl_op_free(pTHX_ OP *o)
 {
+#ifdef USE_ITHREADS
     dVAR;
+#endif
     OPCODE type;
 
     /* Though ops may be freed twice, freeing the op after its slab is a
@@ -752,7 +750,7 @@ Perl_op_free(pTHX_ OP *o)
     if (o->op_flags & OPf_KIDS) {
         OP *kid, *nextkid;
        for (kid = cUNOPo->op_first; kid; kid = nextkid) {
-           nextkid = kid->op_sibling; /* Get before next freeing kid */
+           nextkid = OP_SIBLING(kid); /* Get before next freeing kid */
            op_free(kid);
        }
     }
@@ -1002,7 +1000,7 @@ S_find_and_forget_pmops(pTHX_ OP *o)
                forget_pmop((PMOP*)kid);
            }
            find_and_forget_pmops(kid);
-           kid = kid->op_sibling;
+           kid = OP_SIBLING(kid);
        }
     }
 }
@@ -1034,7 +1032,9 @@ Perl_op_null(pTHX_ OP *o)
 void
 Perl_op_refcnt_lock(pTHX)
 {
+#ifdef USE_ITHREADS
     dVAR;
+#endif
     PERL_UNUSED_CONTEXT;
     OP_REFCNT_LOCK;
 }
@@ -1042,11 +1042,177 @@ Perl_op_refcnt_lock(pTHX)
 void
 Perl_op_refcnt_unlock(pTHX)
 {
+#ifdef USE_ITHREADS
     dVAR;
+#endif
     PERL_UNUSED_CONTEXT;
     OP_REFCNT_UNLOCK;
 }
 
+
+/*
+=for apidoc op_sibling_splice
+
+A general function for editing the structure of an existing chain of
+op_sibling nodes. By analogy with the perl-level splice() function, allows
+you to delete zero or more sequential nodes, replacing them with zero or
+more different nodes.  Performs the necessary op_first/op_last
+housekeeping on the parent node and op_silbing manipulation on the
+children. The op_silbing field of the last deleted node will be set to
+NULL.
+
+Note that op_next is not manipulated, and nodes are not freed; that is the
+responsibility of the caller. It also won't create new a list op for an empty
+list etc; use higher-level functions like op_append_elem() for that.
+
+parent is the parent node of the sibling chain.
+
+start is the node preceding the first node to be spliced. Node(s)
+following it will be deleted, and ops will be inserted after it. If it is
+NULL, the first node onwards is deleted, and nodes are inserted at the
+beginning.
+
+del_count is the number of nodes to delete. If zero, no nodes are deleted.
+If -1 or greater than or equal to the number of remaining kids, all
+remaining kids are deleted.
+
+insert is the first of a chain of nodes to be inserted in place of the nodes.
+If NULL, no nodes are inserted.
+
+The head of the chain of deleted op is returned, or NULL uif no ops were
+deleted.
+
+For example:
+
+    action                    before      after         returns
+    ------                    -----       -----         -------
+
+                              P           P
+    splice(P, A, 2, X-Y)      |           |             B-C
+                              A-B-C-D     A-X-Y-D
+
+                              P           P
+    splice(P, NULL, 1, X-Y)   |           |             A
+                              A-B-C-D     X-Y-B-C-D
+
+                              P           P
+    splice(P, NULL, 1, NULL)  |           |             A
+                              A-B-C-D     B-C-D
+
+                              P           P
+    splice(P, B, 0, X-Y)      |           |             NULL
+                              A-B-C-D     A-B-X-Y-C-D
+
+=cut
+*/
+
+OP *
+Perl_op_sibling_splice(pTHX_ OP *parent, OP *start, int del_count, OP* insert)
+{
+    dVAR;
+    OP *first = start ? OP_SIBLING(start) : cLISTOPx(parent)->op_first;
+    OP *rest;
+    OP *last_del = NULL;
+    OP *last_ins = NULL;
+
+    PERL_ARGS_ASSERT_OP_SIBLING_SPLICE;
+
+    assert(del_count >= -1);
+
+    if (del_count && first) {
+        last_del = first;
+        while (--del_count && OP_HAS_SIBLING(last_del))
+            last_del = OP_SIBLING(last_del);
+        rest = OP_SIBLING(last_del);
+        OP_SIBLING_set(last_del, NULL);
+    }
+    else
+        rest = first;
+
+    if (insert) {
+        last_ins = insert;
+        while (OP_HAS_SIBLING(last_ins))
+            last_ins = OP_SIBLING(last_ins);
+        OP_SIBLING_set(last_ins, rest);
+    }
+    else
+        insert = rest;
+
+    if (start)
+        OP_SIBLING_set(start, insert);
+    else
+        cLISTOPx(parent)->op_first = insert;
+
+    if (!rest) {
+        /* update op_last */
+        U32 type = parent->op_type;
+
+        if (type == OP_NULL)
+            type = parent->op_targ;
+        type = PL_opargs[type] & OA_CLASS_MASK;
+
+        if (   type == OA_BINOP
+            || type == OA_LISTOP
+            || type == OA_PMOP
+            || type == OA_LOOP
+        )
+            cLISTOPx(parent)->op_last =
+                (last_ins ? last_ins : start ? start : NULL);
+    }
+    return last_del ? first : NULL;
+}
+
+
+/* replace the sibling following start with a new UNOP, which becomes
+ * the parent of the original sibling; e.g.
+ *
+ *  op_sibling_newUNOP(P, A, unop-args...)
+ *
+ *  P              P
+ *  |      becomes |
+ *  A-B-C          A-U-C
+ *                   |
+ *                   B
+ *
+ * where U is the new UNOP.
+ *
+ * parent and start args are the same as for op_sibling_splice();
+ * type and flags args are as newUNOP().
+ *
+ * Returns the new UNOP.
+ */
+
+OP *
+S_op_sibling_newUNOP(pTHX_ OP *parent, OP *start, I32 type, I32 flags)
+{
+    OP *kid, *newop;
+
+    kid = op_sibling_splice(parent, start, 1, NULL);
+    newop = newUNOP(type, flags, kid);
+    op_sibling_splice(parent, start, 0, newop);
+    return newop;
+}
+
+
+/* lowest-level newLOGOP-style function - just allocates and populates
+ * the struct. Higher-level stuff should be done by S_new_logop() /
+ * newLOGOP(). This function exists mainly to avoid op_first assignment
+ * being spread throughout this file.
+ */
+
+LOGOP *
+S_alloc_LOGOP(pTHX_ I32 type, OP *first, OP* other)
+{
+    LOGOP *logop;
+    NewOp(1101, logop, 1, LOGOP);
+    logop->op_type = type;
+    logop->op_first = first;
+    logop->op_other = other;
+    logop->op_flags = OPf_KIDS;
+    return logop;
+}
+
+
 /* Contextualizers */
 
 /*
@@ -1100,9 +1266,9 @@ Perl_op_linklist(pTHX_ OP *o)
        o->op_next = LINKLIST(first);
        kid = first;
        for (;;) {
-           if (kid->op_sibling) {
-               kid->op_next = LINKLIST(kid->op_sibling);
-               kid = kid->op_sibling;
+           if (OP_HAS_SIBLING(kid)) {
+               kid->op_next = LINKLIST(OP_SIBLING(kid));
+               kid = OP_SIBLING(kid);
            } else {
                kid->op_next = o;
                break;
@@ -1120,7 +1286,7 @@ S_scalarkids(pTHX_ OP *o)
 {
     if (o && o->op_flags & OPf_KIDS) {
         OP *kid;
-       for (kid = cLISTOPo->op_first; kid; kid = kid->op_sibling)
+       for (kid = cLISTOPo->op_first; kid; kid = OP_SIBLING(kid))
            scalar(kid);
     }
     return o;
@@ -1129,8 +1295,6 @@ S_scalarkids(pTHX_ OP *o)
 STATIC OP *
 S_scalarboolean(pTHX_ OP *o)
 {
-    dVAR;
-
     PERL_ARGS_ASSERT_SCALARBOOLEAN;
 
     if (o->op_type == OP_SASSIGN && cBINOPo->op_first->op_type == OP_CONST
@@ -1207,7 +1371,7 @@ S_scalar_slice_warning(pTHX_ const OP *o)
        return;
 
     kid = cLISTOPo->op_first;
-    kid = kid->op_sibling; /* get past pushmark */
+    kid = OP_SIBLING(kid); /* get past pushmark */
     /* weed out false positives: any ops that can return lists */
     switch (kid->op_type) {
     case OP_BACKTICK:
@@ -1242,8 +1406,8 @@ S_scalar_slice_warning(pTHX_ const OP *o)
     if (kid->op_type == OP_NULL && kid->op_targ == OP_LIST)
         return;
 
-    assert(kid->op_sibling);
-    name = S_op_varname(aTHX_ kid->op_sibling);
+    assert(OP_SIBLING(kid));
+    name = S_op_varname(aTHX_ OP_SIBLING(kid));
     if (!name) /* XS module fiddling with the op tree */
        return;
     S_op_pretty(aTHX_ kid, &keysv, &key);
@@ -1268,7 +1432,6 @@ S_scalar_slice_warning(pTHX_ const OP *o)
 OP *
 Perl_scalar(pTHX_ OP *o)
 {
-    dVAR;
     OP *kid;
 
     /* assumes no premature commitment */
@@ -1288,7 +1451,7 @@ Perl_scalar(pTHX_ OP *o)
     case OP_OR:
     case OP_AND:
     case OP_COND_EXPR:
-       for (kid = cUNOPo->op_first->op_sibling; kid; kid = kid->op_sibling)
+       for (kid = OP_SIBLING(cUNOPo->op_first); kid; kid = OP_SIBLING(kid))
            scalar(kid);
        break;
        /* FALLTHROUGH */
@@ -1299,7 +1462,7 @@ Perl_scalar(pTHX_ OP *o)
     case OP_NULL:
     default:
        if (o->op_flags & OPf_KIDS) {
-           for (kid = cUNOPo->op_first; kid; kid = kid->op_sibling)
+           for (kid = cUNOPo->op_first; kid; kid = OP_SIBLING(kid))
                scalar(kid);
        }
        break;
@@ -1307,10 +1470,10 @@ Perl_scalar(pTHX_ OP *o)
     case OP_LEAVETRY:
        kid = cLISTOPo->op_first;
        scalar(kid);
-       kid = kid->op_sibling;
+       kid = OP_SIBLING(kid);
     do_kids:
        while (kid) {
-           OP *sib = kid->op_sibling;
+           OP *sib = OP_SIBLING(kid);
            if (sib && kid->op_type != OP_LEAVEWHEN)
                scalarvoid(kid);
            else
@@ -1344,9 +1507,9 @@ Perl_scalar(pTHX_ OP *o)
        if (!ckWARN(WARN_SYNTAX)) break;
 
        kid = cLISTOPo->op_first;
-       kid = kid->op_sibling; /* get past pushmark */
-       assert(kid->op_sibling);
-       name = S_op_varname(aTHX_ kid->op_sibling);
+       kid = OP_SIBLING(kid); /* get past pushmark */
+       assert(OP_SIBLING(kid));
+       name = S_op_varname(aTHX_ OP_SIBLING(kid));
        if (!name) /* XS module fiddling with the op tree */
            break;
        S_op_pretty(aTHX_ kid, &keysv, &key);
@@ -1532,7 +1695,7 @@ Perl_scalarvoid(pTHX_ OP *o)
     case OP_RV2AV:
     case OP_RV2HV:
        if (!(o->op_private & (OPpLVAL_INTRO|OPpOUR_INTRO)) &&
-               (!o->op_sibling || o->op_sibling->op_type != OP_READLINE))
+               (!OP_HAS_SIBLING(o) || OP_SIBLING(o)->op_type != OP_READLINE))
            useless = "a variable";
        break;
 
@@ -1659,7 +1822,7 @@ Perl_scalarvoid(pTHX_ OP *o)
     case OP_COND_EXPR:
     case OP_ENTERGIVEN:
     case OP_ENTERWHEN:
-       for (kid = cUNOPo->op_first->op_sibling; kid; kid = kid->op_sibling)
+       for (kid = OP_SIBLING(cUNOPo->op_first); kid; kid = OP_SIBLING(kid))
            scalarvoid(kid);
        break;
 
@@ -1682,7 +1845,7 @@ Perl_scalarvoid(pTHX_ OP *o)
     case OP_LIST:
     case OP_LEAVEGIVEN:
     case OP_LEAVEWHEN:
-       for (kid = cLISTOPo->op_first; kid; kid = kid->op_sibling)
+       for (kid = cLISTOPo->op_first; kid; kid = OP_SIBLING(kid))
            scalarvoid(kid);
        break;
     case OP_ENTEREVAL:
@@ -1711,7 +1874,7 @@ S_listkids(pTHX_ OP *o)
 {
     if (o && o->op_flags & OPf_KIDS) {
         OP *kid;
-       for (kid = cLISTOPo->op_first; kid; kid = kid->op_sibling)
+       for (kid = cLISTOPo->op_first; kid; kid = OP_SIBLING(kid))
            list(kid);
     }
     return o;
@@ -1720,7 +1883,6 @@ S_listkids(pTHX_ OP *o)
 OP *
 Perl_list(pTHX_ OP *o)
 {
-    dVAR;
     OP *kid;
 
     /* assumes no premature commitment */
@@ -1747,7 +1909,7 @@ Perl_list(pTHX_ OP *o)
     case OP_OR:
     case OP_AND:
     case OP_COND_EXPR:
-       for (kid = cUNOPo->op_first->op_sibling; kid; kid = kid->op_sibling)
+       for (kid = OP_SIBLING(cUNOPo->op_first); kid; kid = OP_SIBLING(kid))
            list(kid);
        break;
     default:
@@ -1768,10 +1930,10 @@ Perl_list(pTHX_ OP *o)
     case OP_LEAVETRY:
        kid = cLISTOPo->op_first;
        list(kid);
-       kid = kid->op_sibling;
+       kid = OP_SIBLING(kid);
     do_kids:
        while (kid) {
-           OP *sib = kid->op_sibling;
+           OP *sib = OP_SIBLING(kid);
            if (sib && kid->op_type != OP_LEAVEWHEN)
                scalarvoid(kid);
            else
@@ -1791,7 +1953,6 @@ Perl_list(pTHX_ OP *o)
 static OP *
 S_scalarseq(pTHX_ OP *o)
 {
-    dVAR;
     if (o) {
        const OPCODE type = o->op_type;
 
@@ -1799,8 +1960,8 @@ S_scalarseq(pTHX_ OP *o)
            type == OP_LEAVE || type == OP_LEAVETRY)
        {
             OP *kid;
-           for (kid = cLISTOPo->op_first; kid; kid = kid->op_sibling) {
-               if (kid->op_sibling) {
+           for (kid = cLISTOPo->op_first; kid; kid = OP_SIBLING(kid)) {
+               if (OP_HAS_SIBLING(kid)) {
                    scalarvoid(kid);
                }
            }
@@ -1820,7 +1981,7 @@ S_modkids(pTHX_ OP *o, I32 type)
 {
     if (o && o->op_flags & OPf_KIDS) {
         OP *kid;
-       for (kid = cLISTOPo->op_first; kid; kid = kid->op_sibling)
+       for (kid = cLISTOPo->op_first; kid; kid = OP_SIBLING(kid))
            op_lvalue(kid, type);
     }
     return o;
@@ -1861,23 +2022,24 @@ S_finalize_op(pTHX_ OP* o)
        PL_curcop = ((COP*)o);          /* for warnings */
        break;
     case OP_EXEC:
-       if ( o->op_sibling
-           && (o->op_sibling->op_type == OP_NEXTSTATE || o->op_sibling->op_type == OP_DBSTATE)
-           && ckWARN(WARN_EXEC))
-           {
-               if (o->op_sibling->op_sibling) {
-                   const OPCODE type = o->op_sibling->op_sibling->op_type;
+       if (OP_HAS_SIBLING(o)) {
+            OP *sib = OP_SIBLING(o);
+            if ((  sib->op_type == OP_NEXTSTATE || sib->op_type == OP_DBSTATE)
+                && ckWARN(WARN_EXEC)
+                && OP_HAS_SIBLING(sib))
+            {
+                   const OPCODE type = OP_SIBLING(sib)->op_type;
                    if (type != OP_EXIT && type != OP_WARN && type != OP_DIE) {
                        const line_t oldline = CopLINE(PL_curcop);
-                       CopLINE_set(PL_curcop, CopLINE((COP*)o->op_sibling));
+                       CopLINE_set(PL_curcop, CopLINE((COP*)sib));
                        Perl_warner(aTHX_ packWARN(WARN_EXEC),
                            "Statement unlikely to be reached");
                        Perl_warner(aTHX_ packWARN(WARN_EXEC),
                            "\t(Maybe you meant system() when you said exec()?)\n");
                        CopLINE_set(PL_curcop, oldline);
                    }
-               }
            }
+        }
        break;
 
     case OP_GV:
@@ -1936,7 +2098,7 @@ S_finalize_op(pTHX_ OP* o)
         /* FALLTHROUGH */
 
     case OP_KVHSLICE:
-        kid = cLISTOPo->op_first->op_sibling;
+        kid = OP_SIBLING(cLISTOPo->op_first);
        if (/* I bet there's always a pushmark... */
            OP_TYPE_ISNT_AND_WASNT_NN(kid, OP_LIST)
            && OP_TYPE_ISNT_NN(kid, OP_CONST))
@@ -1946,7 +2108,7 @@ S_finalize_op(pTHX_ OP* o)
 
        key_op = (SVOP*)(kid->op_type == OP_CONST
                                ? kid
-                               : kLISTOP->op_first->op_sibling);
+                               : OP_SIBLING(kLISTOP->op_first));
 
        rop = (UNOP*)((LISTOP*)o)->op_last;
 
@@ -1977,7 +2139,7 @@ S_finalize_op(pTHX_ OP* o)
         && (fields = (GV**)hv_fetchs(SvSTASH(lexname), "FIELDS", FALSE))
         && isGV(*fields) && GvHV(*fields);
        for (; key_op;
-            key_op = (SVOP*)key_op->op_sibling) {
+            key_op = (SVOP*)OP_SIBLING(key_op)) {
            SV **svp, *sv;
            if (key_op->op_type != OP_CONST)
                continue;
@@ -2019,7 +2181,47 @@ S_finalize_op(pTHX_ OP* o)
 
     if (o->op_flags & OPf_KIDS) {
        OP *kid;
-       for (kid = cUNOPo->op_first; kid; kid = kid->op_sibling)
+
+#ifdef DEBUGGING
+        /* check that op_last points to the last sibling */
+        U32 type = o->op_type;
+        U32 family;
+
+        if (type == OP_NULL) {
+            type = o->op_targ;
+            /* ck_glob creates a null UNOP with ex-type GLOB
+             * (which is a list op. So pretend it wasn't a listop */
+            if (type == OP_GLOB)
+                type = OP_NULL;
+        }
+        family = PL_opargs[type] & OA_CLASS_MASK;
+
+        if (
+            /* XXX list form of 'x' is has a null op_last. This is wrong,
+             * but requires too much hacking (e.g. in Deparse) to fix for
+             * now */
+            !(type == OP_REPEAT && (o->op_private & OPpREPEAT_DOLIST))
+            && (
+                   family == OA_BINOP
+                || family == OA_LISTOP
+                || family == OA_PMOP
+                || family == OA_LOOP
+            )
+        )
+        {
+            OP *kid;
+            for (kid = cUNOPo->op_first; kid; kid = OP_SIBLING(kid)) {
+                if (!OP_HAS_SIBLING(kid)) {
+                    if (kid != cLISTOPo->op_last)
+                    {
+                        assert(kid == cLISTOPo->op_last);
+                    }
+                }
+            }
+        }
+#endif
+
+       for (kid = cUNOPo->op_first; kid; kid = OP_SIBLING(kid))
            finalize_op(kid);
     }
 }
@@ -2120,8 +2322,8 @@ Perl_op_lvalue_flags(pTHX_ OP *o, I32 type, U32 flags)
                                (long)kid->op_type, (UV)kid->op_targ);
                    kid = kLISTOP->op_first;
                }
-               while (kid->op_sibling)
-                   kid = kid->op_sibling;
+               while (OP_HAS_SIBLING(kid))
+                   kid = OP_SIBLING(kid);
                if (!(kid->op_type == OP_NULL && kid->op_targ == OP_RV2CV)) {
                    break;      /* Postpone until runtime */
                }
@@ -2189,7 +2391,7 @@ Perl_op_lvalue_flags(pTHX_ OP *o, I32 type, U32 flags)
 
     case OP_COND_EXPR:
        localize = 1;
-       for (kid = cUNOPo->op_first->op_sibling; kid; kid = kid->op_sibling)
+       for (kid = OP_SIBLING(cUNOPo->op_first); kid; kid = OP_SIBLING(kid))
            op_lvalue(kid, type);
        break;
 
@@ -2289,7 +2491,7 @@ Perl_op_lvalue_flags(pTHX_ OP *o, I32 type, U32 flags)
        if (type == OP_LEAVESUBLV)
            o->op_private |= OPpMAYBE_LVSUB;
        if (o->op_flags & OPf_KIDS)
-           op_lvalue(cBINOPo->op_first->op_sibling, type);
+           op_lvalue(OP_SIBLING(cBINOPo->op_first), type);
        break;
 
     case OP_AELEM:
@@ -2329,7 +2531,7 @@ Perl_op_lvalue_flags(pTHX_ OP *o, I32 type, U32 flags)
        /* FALLTHROUGH */
     case OP_LIST:
        localize = 0;
-       for (kid = cLISTOPo->op_first; kid; kid = kid->op_sibling)
+       for (kid = cLISTOPo->op_first; kid; kid = OP_SIBLING(kid))
            /* elements might be in void context because the list is
               in scalar context or because they are attribute sub calls */
            if ( (kid->op_flags & OPf_WANT) != OPf_WANT_VOID )
@@ -2350,8 +2552,8 @@ Perl_op_lvalue_flags(pTHX_ OP *o, I32 type, U32 flags)
         || !S_vivifies(cLOGOPo->op_first->op_type))
            op_lvalue(cLOGOPo->op_first, type);
        if (type == OP_LEAVESUBLV
-        || !S_vivifies(cLOGOPo->op_first->op_sibling->op_type))
-           op_lvalue(cLOGOPo->op_first->op_sibling, type);
+        || !S_vivifies(OP_SIBLING(cLOGOPo->op_first)->op_type))
+           op_lvalue(OP_SIBLING(cLOGOPo->op_first), type);
        goto nomod;
     }
 
@@ -2467,7 +2669,7 @@ S_refkids(pTHX_ OP *o, I32 type)
 {
     if (o && o->op_flags & OPf_KIDS) {
         OP *kid;
-       for (kid = cLISTOPo->op_first; kid; kid = kid->op_sibling)
+       for (kid = cLISTOPo->op_first; kid; kid = OP_SIBLING(kid))
            ref(kid, type);
     }
     return o;
@@ -2505,7 +2707,7 @@ Perl_doref(pTHX_ OP *o, I32 type, bool set_op_ref)
        break;
 
     case OP_COND_EXPR:
-       for (kid = cUNOPo->op_first->op_sibling; kid; kid = kid->op_sibling)
+       for (kid = OP_SIBLING(cUNOPo->op_first); kid; kid = OP_SIBLING(kid))
            doref(kid, type, set_op_ref);
        break;
     case OP_RV2SV:
@@ -2576,7 +2778,6 @@ Perl_doref(pTHX_ OP *o, I32 type, bool set_op_ref)
 STATIC OP *
 S_dup_attrlist(pTHX_ OP *o)
 {
-    dVAR;
     OP *rop;
 
     PERL_ARGS_ASSERT_DUP_ATTRLIST;
@@ -2590,7 +2791,7 @@ S_dup_attrlist(pTHX_ OP *o)
     else {
        assert((o->op_type == OP_LIST) && (o->op_flags & OPf_KIDS));
        rop = NULL;
-       for (o = cLISTOPo->op_first; o; o=o->op_sibling) {
+       for (o = cLISTOPo->op_first; o; o = OP_SIBLING(o)) {
            if (o->op_type == OP_CONST)
                rop = op_append_elem(OP_LIST, rop,
                                  newSVOP(OP_CONST, o->op_flags,
@@ -2603,7 +2804,6 @@ S_dup_attrlist(pTHX_ OP *o)
 STATIC void
 S_apply_attrs(pTHX_ HV *stash, SV *target, OP *attrs)
 {
-    dVAR;
     SV * const stashsv = stash ? newSVhek(HvNAME_HEK(stash)) : &PL_sv_no;
 
     PERL_ARGS_ASSERT_APPLY_ATTRS;
@@ -2627,7 +2827,6 @@ S_apply_attrs(pTHX_ HV *stash, SV *target, OP *attrs)
 STATIC void
 S_apply_attrs_my(pTHX_ HV *stash, OP *target, OP *attrs, OP **imopsp)
 {
-    dVAR;
     OP *pack, *imop, *arg;
     SV *meth, *stashsv, **svp;
 
@@ -2750,11 +2949,11 @@ S_move_proto_attr(pTHX_ OP **proto, OP **attrs, const GV * name)
             *attrs = NULL;
         }
     } else if (o->op_type == OP_LIST) {
-        OP * lasto = NULL;
+        OP * lasto;
         assert(o->op_flags & OPf_KIDS);
-        assert(cLISTOPo->op_first->op_type == OP_PUSHMARK);
-        /* Counting on the first op to hit the lasto = o line */
-        for (o = cLISTOPo->op_first; o; o=o->op_sibling) {
+        lasto = cLISTOPo->op_first;
+        assert(lasto->op_type == OP_PUSHMARK);
+        for (o = OP_SIBLING(lasto); o; o = OP_SIBLING(o)) {
             if (o->op_type == OP_CONST) {
                 pv = SvPV(cSVOPo_sv, pvlen);
                 if (pvlen >= 10 && memEQ(pv, "prototype(", 10)) {
@@ -2773,7 +2972,9 @@ S_move_proto_attr(pTHX_ OP **proto, OP **attrs, const GV * name)
                     else if (new_proto)
                         op_free(new_proto);
                     new_proto = o;
-                    lasto->op_sibling = o->op_sibling;
+                    /* excise new_proto from the list */
+                    op_sibling_splice(*attrs, lasto, 1, NULL);
+                    o = lasto;
                     continue;
                 }
             }
@@ -2781,7 +2982,7 @@ S_move_proto_attr(pTHX_ OP **proto, OP **attrs, const GV * name)
         }
         /* If the list is now just the PUSHMARK, scrap the whole thing; otherwise attributes.xs
            would get pulled in with no real need */
-        if (!cLISTOPx(*attrs)->op_first->op_sibling) {
+        if (!OP_HAS_SIBLING(cLISTOPx(*attrs)->op_first)) {
             op_free(*attrs);
             *attrs = NULL;
         }
@@ -2836,7 +3037,6 @@ S_cant_declare(pTHX_ OP *o)
 STATIC OP *
 S_my_kid(pTHX_ OP *o, OP *attrs, OP **imopsp)
 {
-    dVAR;
     I32 type;
     const bool stately = PL_parser && PL_parser->in_my == KEY_state;
 
@@ -2849,7 +3049,7 @@ S_my_kid(pTHX_ OP *o, OP *attrs, OP **imopsp)
 
     if (type == OP_LIST) {
         OP *kid;
-       for (kid = cLISTOPo->op_first; kid; kid = kid->op_sibling)
+       for (kid = cLISTOPo->op_first; kid; kid = OP_SIBLING(kid))
            my_kid(kid, attrs, imopsp);
        return o;
     } else if (type == OP_UNDEF || type == OP_STUB) {
@@ -2904,7 +3104,6 @@ S_my_kid(pTHX_ OP *o, OP *attrs, OP **imopsp)
 OP *
 Perl_my_attrs(pTHX_ OP *o, OP *attrs)
 {
-    dVAR;
     OP *rops;
     int maybe_scalar = 0;
 
@@ -2937,7 +3136,8 @@ Perl_my_attrs(pTHX_ OP *o, OP *attrs)
                lrops->op_first && lrops->op_first->op_type == OP_PUSHMARK)
            {
                OP * const pushmark = lrops->op_first;
-               lrops->op_first = pushmark->op_sibling;
+                /* excise pushmark */
+                op_sibling_splice(rops, NULL, 1, NULL);
                op_free(pushmark);
            }
            o = op_append_list(OP_LIST, o, rops);
@@ -3082,7 +3282,7 @@ Perl_op_scope(pTHX_ OP *o)
                op_null(kid);
 
                /* The following deals with things like 'do {1 for 1}' */
-               kid = kid->op_sibling;
+               kid = OP_SIBLING(kid);
                if (kid &&
                    (kid->op_type == OP_NEXTSTATE || kid->op_type == OP_DBSTATE))
                    op_null(kid);
@@ -3099,7 +3299,7 @@ Perl_op_unscope(pTHX_ OP *o)
 {
     if (o && o->op_type == OP_LINESEQ) {
        OP *kid = cLISTOPo->op_first;
-       for(; kid; kid = kid->op_sibling)
+       for(; kid; kid = OP_SIBLING(kid))
            if (kid->op_type == OP_NEXTSTATE || kid->op_type == OP_DBSTATE)
                op_null(kid);
     }
@@ -3109,7 +3309,6 @@ Perl_op_unscope(pTHX_ OP *o)
 int
 Perl_block_start(pTHX_ int full)
 {
-    dVAR;
     const int retval = PL_savestack_ix;
 
     pad_block_start(full);
@@ -3126,7 +3325,6 @@ Perl_block_start(pTHX_ int full)
 OP*
 Perl_block_end(pTHX_ I32 floor, OP *seq)
 {
-    dVAR;
     const int needblockscope = PL_hints & HINT_BLOCK_SCOPE;
     OP* retval = scalarseq(seq);
     OP *o;
@@ -3188,7 +3386,7 @@ Perl_block_end(pTHX_ I32 floor, OP *seq)
         */
        OP *kid = o->op_flags & OPf_KIDS ? cLISTOPo->op_first : o;
        OP * const last = o->op_flags & OPf_KIDS ? cLISTOPo->op_last : o;
-       for (;; kid = kid->op_sibling) {
+       for (;; kid = OP_SIBLING(kid)) {
            OP *newkid = newOP(OP_CLONECV, 0);
            newkid->op_targ = kid->op_targ;
            o = op_append_elem(OP_LINESEQ, o, newkid);
@@ -3224,7 +3422,6 @@ Perl_blockhook_register(pTHX_ BHK *hk)
 STATIC OP *
 S_newDEFSVOP(pTHX)
 {
-    dVAR;
     const PADOFFSET offset = pad_findmy_pvs("$_", 0);
     if (offset == NOT_IN_PAD || PAD_COMPNAME_FLAGS_isOUR(offset)) {
        return newSVREF(newGVOP(OP_GV, 0, PL_defgv));
@@ -3239,8 +3436,6 @@ S_newDEFSVOP(pTHX)
 void
 Perl_newPROG(pTHX_ OP *o)
 {
-    dVAR;
-
     PERL_ARGS_ASSERT_NEWPROG;
 
     if (PL_in_eval) {
@@ -3337,8 +3532,6 @@ Perl_newPROG(pTHX_ OP *o)
 OP *
 Perl_localize(pTHX_ OP *o, I32 lex)
 {
-    dVAR;
-
     PERL_ARGS_ASSERT_LOCALIZE;
 
     if (o->op_flags & OPf_PARENS)
@@ -3495,11 +3688,11 @@ S_fold_constants(pTHX_ OP *o)
 #endif
        break;
     case OP_PACK:
-       if (!cLISTOPo->op_first->op_sibling
-         || cLISTOPo->op_first->op_sibling->op_type != OP_CONST)
+       if (!OP_HAS_SIBLING(cLISTOPo->op_first)
+         || OP_SIBLING(cLISTOPo->op_first)->op_type != OP_CONST)
            goto nope;
        {
-           SV * const sv = cSVOPx_sv(cLISTOPo->op_first->op_sibling);
+           SV * const sv = cSVOPx_sv(OP_SIBLING(cLISTOPo->op_first));
            if (!SvPOK(sv) || SvGMAGICAL(sv)) goto nope;
            {
                const char *s = SvPVX_const(sv);
@@ -3643,16 +3836,19 @@ S_gen_constant_list(pTHX_ OP *o)
     o->op_flags &= ~OPf_REF;   /* treat \(1..2) like an ordinary list */
     o->op_flags |= OPf_PARENS; /* and flatten \(1..2,3) */
     o->op_opt = 0;             /* needs to be revisited in rpeep() */
-    curop = ((UNOP*)o)->op_first;
     av = (AV *)SvREFCNT_inc_NN(*PL_stack_sp--);
-    ((UNOP*)o)->op_first = newSVOP(OP_CONST, 0, (SV *)av);
+
+    /* replace subtree with an OP_CONST */
+    curop = ((UNOP*)o)->op_first;
+    op_sibling_splice(o, NULL, -1, newSVOP(OP_CONST, 0, (SV *)av));
+    op_free(curop);
+
     if (AvFILLp(av) != -1)
        for (svp = AvARRAY(av) + AvFILLp(av); svp >= AvARRAY(av); --svp)
        {
            SvPADTMP_on(*svp);
            SvREADONLY_on(*svp);
        }
-    op_free(curop);
     LINKLIST(o);
     return list(o);
 }
@@ -3662,15 +3858,22 @@ Perl_convert(pTHX_ I32 type, I32 flags, OP *o)
 {
     dVAR;
     if (type < 0) type = -type, flags |= OPf_SPECIAL;
-    if (!o || o->op_type != OP_LIST)
+    if (!o || o->op_type != OP_LIST) {
+        OP* last = o;
        o = newLISTOP(OP_LIST, 0, o, NULL);
+        if (last) {
+            while (OP_HAS_SIBLING(last))
+                last = OP_SIBLING(last);
+            cLISTOPo->op_last = last;
+        }
+    }
     else
        o->op_flags &= ~OPf_WANT;
 
     if (!(PL_opargs[type] & OA_MARK))
        op_null(cLISTOPo->op_first);
     else {
-       OP * const kid2 = cLISTOPo->op_first->op_sibling;
+       OP * const kid2 = OP_SIBLING(cLISTOPo->op_first);
        if (kid2 && kid2->op_type == OP_COREARGS) {
            op_null(cLISTOPo->op_first);
            kid2->op_private |= OPpCOREARGS_PUSHMARK;
@@ -3722,13 +3925,8 @@ Perl_op_append_elem(pTHX_ I32 type, OP *first, OP *last)
        return newLISTOP(type, 0, first, last);
     }
 
-    if (first->op_flags & OPf_KIDS)
-       ((LISTOP*)first)->op_last->op_sibling = last;
-    else {
-       first->op_flags |= OPf_KIDS;
-       ((LISTOP*)first)->op_first = last;
-    }
-    ((LISTOP*)first)->op_last = last;
+    op_sibling_splice(first, ((LISTOP*)first)->op_last, 0, last);
+    first->op_flags |= OPf_KIDS;
     return first;
 }
 
@@ -3760,7 +3958,7 @@ Perl_op_append_list(pTHX_ I32 type, OP *first, OP *last)
     if (last->op_type != (unsigned)type)
        return op_append_elem(type, first, last);
 
-    ((LISTOP*)first)->op_last->op_sibling = ((LISTOP*)last)->op_first;
+    OP_SIBLING_set(((LISTOP*)first)->op_last, ((LISTOP*)last)->op_first);
     ((LISTOP*)first)->op_last = ((LISTOP*)last)->op_last;
     first->op_flags |= (last->op_flags & OPf_KIDS);
 
@@ -3794,19 +3992,13 @@ Perl_op_prepend_elem(pTHX_ I32 type, OP *first, OP *last)
 
     if (last->op_type == (unsigned)type) {
        if (type == OP_LIST) {  /* already a PUSHMARK there */
-           first->op_sibling = ((LISTOP*)last)->op_first->op_sibling;
-           ((LISTOP*)last)->op_first->op_sibling = first;
+            /* insert 'first' after pushmark */
+            op_sibling_splice(last, cLISTOPx(last)->op_first, 0, first);
             if (!(first->op_flags & OPf_PARENS))
                 last->op_flags &= ~OPf_PARENS;
        }
-       else {
-           if (!(last->op_flags & OPf_KIDS)) {
-               ((LISTOP*)last)->op_last = first;
-               last->op_flags |= OPf_KIDS;
-           }
-           first->op_sibling = ((LISTOP*)last)->op_first;
-           ((LISTOP*)last)->op_first = first;
-       }
+       else
+            op_sibling_splice(last, NULL, 0, first);
        last->op_flags |= OPf_KIDS;
        return last;
     }
@@ -3837,8 +4029,15 @@ Perl_newNULLLIST(pTHX)
 static OP *
 S_force_list(pTHX_ OP *o)
 {
-    if (!o || o->op_type != OP_LIST)
+    if (!o || o->op_type != OP_LIST) {
+        OP* last = o;
        o = newLISTOP(OP_LIST, 0, o, NULL);
+        if (last) {
+            while (OP_HAS_SIBLING(last))
+                last = OP_SIBLING(last);
+            cLISTOPo->op_last = last;
+        }
+    }
     op_null(o);
     return o;
 }
@@ -3876,12 +4075,12 @@ Perl_newLISTOP(pTHX_ I32 type, I32 flags, OP *first, OP *last)
     else if (!first && last)
        first = last;
     else if (first)
-       first->op_sibling = last;
+       OP_SIBLING_set(first, last);
     listop->op_first = first;
     listop->op_last = last;
     if (type == OP_LIST) {
        OP* const pushop = newOP(OP_PUSHMARK, 0);
-       pushop->op_sibling = first;
+       OP_SIBLING_set(pushop, first);
        listop->op_first = pushop;
        listop->op_flags |= OPf_KIDS;
        if (!last)
@@ -3925,6 +4124,7 @@ Perl_newOP(pTHX_ I32 type, I32 flags)
 
     o->op_next = o;
     o->op_private = (U8)(0 | (flags >> 8));
+
     if (PL_opargs[type] & OA_RETSCALAR)
        scalar(o);
     if (PL_opargs[type] & OA_TARGET)
@@ -4021,14 +4221,14 @@ Perl_newBINOP(pTHX_ I32 type, I32 flags, OP *first, OP *last)
     }
     else {
        binop->op_private = (U8)(2 | (flags >> 8));
-       first->op_sibling = last;
+       OP_SIBLING_set(first, last);
     }
 
     binop = (BINOP*)CHECKOP(type, binop);
     if (binop->op_next || binop->op_type != (OPCODE)type)
        return (OP*)binop;
 
-    binop->op_last = binop->op_first->op_sibling;
+    binop->op_last = OP_SIBLING(binop->op_first);
 
     return fold_constants(op_integerize(op_std_init((OP *)binop)));
 }
@@ -4053,7 +4253,6 @@ static int uvcompare(const void *a, const void *b)
 static OP *
 S_pmtrans(pTHX_ OP *o, OP *expr, OP *repl)
 {
-    dVAR;
     SV * const tstr = ((SVOP*)expr)->op_sv;
     SV * const rstr =
                              ((SVOP*)repl)->op_sv;
@@ -4116,7 +4315,7 @@ S_pmtrans(pTHX_ OP *o, OP *expr, OP *repl)
            rend = r + len;
        }
 
-/* There is a  snag with this code on EBCDIC: scan_const() in toke.c has
+/* There is a snag with this code on EBCDIC: scan_const() in toke.c has
  * encoded chars in native encoding which makes ranges in the EBCDIC 0..255
  * odd.  */
 
@@ -4489,25 +4688,27 @@ Perl_pmruntime(pTHX_ OP *o, OP *expr, bool isreg, I32 floor)
        OP* kid;
        repl = cLISTOPx(expr)->op_last;
        kid = cLISTOPx(expr)->op_first;
-       while (kid->op_sibling != repl)
-           kid = kid->op_sibling;
-       kid->op_sibling = NULL;
-       cLISTOPx(expr)->op_last = kid;
+       while (OP_SIBLING(kid) != repl)
+           kid = OP_SIBLING(kid);
+        op_sibling_splice(expr, kid, 1, NULL);
     }
 
     /* for TRANS, convert LIST/PUSH/CONST into CONST, and pass to pmtrans() */
 
     if (is_trans) {
-       OP* const oe = expr;
-       assert(expr->op_type == OP_LIST);
-       assert(cLISTOPx(expr)->op_first->op_type == OP_PUSHMARK);
-       assert(cLISTOPx(expr)->op_first->op_sibling == cLISTOPx(expr)->op_last);
-       expr = cLISTOPx(oe)->op_last;
-       cLISTOPx(oe)->op_first->op_sibling = NULL;
-       cLISTOPx(oe)->op_last = NULL;
-       op_free(oe);
+        OP *first, *last;
+
+        assert(expr->op_type == OP_LIST);
+        first = cLISTOPx(expr)->op_first;
+        last  = cLISTOPx(expr)->op_last;
+        assert(first->op_type == OP_PUSHMARK);
+        assert(OP_SIBLING(first) == last);
+
+        /* cut 'last' from sibling chain, then free everything else */
+        op_sibling_splice(expr, first, 1, NULL);
+        op_free(expr);
 
-       return pmtrans(o, expr, repl);
+        return pmtrans(o, last, repl);
     }
 
     /* find whether we have any runtime or code elements;
@@ -4520,11 +4721,11 @@ Perl_pmruntime(pTHX_ OP *o, OP *expr, bool isreg, I32 floor)
     has_code = 0;
     if (expr->op_type == OP_LIST) {
        OP *o;
-       for (o = cLISTOPx(expr)->op_first; o; o = o->op_sibling) {
+       for (o = cLISTOPx(expr)->op_first; o; o = OP_SIBLING(o)) {
            if (o->op_type == OP_NULL && (o->op_flags & OPf_SPECIAL)) {
                has_code = 1;
-               assert(!o->op_next && o->op_sibling);
-               o->op_next = o->op_sibling;
+               assert(!o->op_next && OP_HAS_SIBLING(o));
+               o->op_next = OP_SIBLING(o);
            }
            else if (o->op_type != OP_CONST && o->op_type != OP_PUSHMARK)
                is_compiletime = 0;
@@ -4540,7 +4741,7 @@ Perl_pmruntime(pTHX_ OP *o, OP *expr, bool isreg, I32 floor)
 
     if (expr->op_type == OP_LIST) {
        OP *o;
-       for (o = cLISTOPx(expr)->op_first; o; o = o->op_sibling) {
+       for (o = cLISTOPx(expr)->op_first; o; o = OP_SIBLING(o)) {
 
             if (o->op_type == OP_PADAV || o->op_type == OP_RV2AV) {
                 assert( !(o->op_flags  & OPf_WANT));
@@ -4559,8 +4760,8 @@ Perl_pmruntime(pTHX_ OP *o, OP *expr, bool isreg, I32 floor)
                LISTOP *leaveop = cLISTOPx(cLISTOPo->op_first);
                /* skip ENTER */
                assert(leaveop->op_first->op_type == OP_ENTER);
-               assert(leaveop->op_first->op_sibling);
-               o->op_next = leaveop->op_first->op_sibling;
+               assert(OP_HAS_SIBLING(leaveop->op_first));
+               o->op_next = OP_SIBLING(leaveop->op_first);
                /* skip leave */
                assert(leaveop->op_flags & OPf_KIDS);
                assert(leaveop->op_last->op_next == (OP*)leaveop);
@@ -4730,15 +4931,10 @@ Perl_pmruntime(pTHX_ OP *o, OP *expr, bool isreg, I32 floor)
            expr = list(force_list(newUNOP(OP_ENTERSUB, 0, scalar(expr))));
        }
 
-       NewOp(1101, rcop, 1, LOGOP);
-       rcop->op_type = OP_REGCOMP;
+        rcop = S_alloc_LOGOP(aTHX_ OP_REGCOMP, scalar(expr), o);
        rcop->op_ppaddr = PL_ppaddr[OP_REGCOMP];
-       rcop->op_first = scalar(expr);
-       rcop->op_flags |= OPf_KIDS
-                           | ((PL_hints & HINT_RE_EVAL) ? OPf_SPECIAL : 0)
-                           | (reglist ? OPf_STACKED : 0);
-       rcop->op_private = 0;
-       rcop->op_other = o;
+       rcop->op_flags |=  ((PL_hints & HINT_RE_EVAL) ? OPf_SPECIAL : 0)
+                          | (reglist ? OPf_STACKED : 0);
        rcop->op_targ = cv_targ;
 
        /* /$x/ may cause an eval, since $x might be qr/(?{..})/  */
@@ -4764,12 +4960,14 @@ Perl_pmruntime(pTHX_ OP *o, OP *expr, bool isreg, I32 floor)
        /* If we are looking at s//.../e with a single statement, get past
           the implicit do{}. */
        if (curop->op_type == OP_NULL && curop->op_flags & OPf_KIDS
-        && cUNOPx(curop)->op_first->op_type == OP_SCOPE
-        && cUNOPx(curop)->op_first->op_flags & OPf_KIDS) {
+             && cUNOPx(curop)->op_first->op_type == OP_SCOPE
+             && cUNOPx(curop)->op_first->op_flags & OPf_KIDS)
+         {
+            OP *sib;
            OP *kid = cUNOPx(cUNOPx(curop)->op_first)->op_first;
-           if (kid->op_type == OP_NULL && kid->op_sibling
-            && !kid->op_sibling->op_sibling)
-               curop = kid->op_sibling;
+           if (kid->op_type == OP_NULL && (sib = OP_SIBLING(kid))
+                     && !OP_HAS_SIBLING(sib))
+               curop = sib;
        }
        if (curop->op_type == OP_CONST)
            konst = TRUE;
@@ -4797,13 +4995,9 @@ Perl_pmruntime(pTHX_ OP *o, OP *expr, bool isreg, I32 floor)
            op_prepend_elem(o->op_type, scalar(repl), o);
        }
        else {
-           NewOp(1101, rcop, 1, LOGOP);
-           rcop->op_type = OP_SUBSTCONT;
+            rcop = S_alloc_LOGOP(aTHX_ OP_SUBSTCONT, scalar(repl), o);
            rcop->op_ppaddr = PL_ppaddr[OP_SUBSTCONT];
-           rcop->op_first = scalar(repl);
-           rcop->op_flags |= OPf_KIDS;
            rcop->op_private = 1;
-           rcop->op_other = o;
 
            /* establish postfix order */
            rcop->op_next = LINKLIST(repl);
@@ -4917,8 +5111,6 @@ reference to it.
 OP *
 Perl_newGVOP(pTHX_ I32 type, I32 flags, GV *gv)
 {
-    dVAR;
-
     PERL_ARGS_ASSERT_NEWGVOP;
 
 #ifdef USE_ITHREADS
@@ -4971,7 +5163,6 @@ Perl_newPVOP(pTHX_ I32 type, I32 flags, char *pv)
 void
 Perl_package(pTHX_ OP *o)
 {
-    dVAR;
     SV *const sv = cSVOPo->op_sv;
 
     PERL_ARGS_ASSERT_PACKAGE;
@@ -4993,7 +5184,6 @@ Perl_package(pTHX_ OP *o)
 void
 Perl_package_version( pTHX_ OP *v )
 {
-    dVAR;
     U32 savehints = PL_hints;
     PERL_ARGS_ASSERT_PACKAGE_VERSION;
     PL_hints &= ~HINT_STRICT_VARS;
@@ -5005,7 +5195,6 @@ Perl_package_version( pTHX_ OP *v )
 void
 Perl_utilize(pTHX_ int aver, I32 floor, OP *version, OP *idop, OP *arg)
 {
-    dVAR;
     OP *pack;
     OP *imop;
     OP *veop;
@@ -5184,7 +5373,6 @@ Perl_load_module_nocontext(U32 flags, SV *name, SV *ver, ...)
 void
 Perl_vload_module(pTHX_ U32 flags, SV *name, SV *ver, va_list *args)
 {
-    dVAR;
     OP *veop, *imop;
     OP * const modname = newSVOP(OP_CONST, 0, name);
 
@@ -5239,7 +5427,6 @@ S_new_entersubop(pTHX_ GV *gv, OP *arg)
 OP *
 Perl_dofile(pTHX_ OP *term, I32 force_builtin)
 {
-    dVAR;
     OP *doop;
     GV *gv;
 
@@ -5293,8 +5480,9 @@ S_is_list_assignment(pTHX_ const OP *o)
     flags = o->op_flags;
     type = o->op_type;
     if (type == OP_COND_EXPR) {
-        const I32 t = is_list_assignment(cLOGOPo->op_first->op_sibling);
-        const I32 f = is_list_assignment(cLOGOPo->op_first->op_sibling->op_sibling);
+        OP * const sib = OP_SIBLING(cLOGOPo->op_first);
+        const I32 t = is_list_assignment(sib);
+        const I32 f = is_list_assignment(OP_SIBLING(sib));
 
        if (t && f)
            return TRUE;
@@ -5332,7 +5520,7 @@ PERL_STATIC_INLINE bool
 S_aassign_common_vars(pTHX_ OP* o)
 {
     OP *curop;
-    for (curop = cUNOPo->op_first; curop; curop=curop->op_sibling) {
+    for (curop = cUNOPo->op_first; curop; curop = OP_SIBLING(curop)) {
        if (PL_opargs[curop->op_type] & OA_DANGEROUS) {
            if (curop->op_type == OP_GV) {
                GV *gv = cGVOPx_gv(curop);
@@ -5415,7 +5603,6 @@ set as required.
 OP *
 Perl_newASSIGNOP(pTHX_ I32 flags, OP *left, I32 optype, OP *right)
 {
-    dVAR;
     OP *o;
 
     if (optype) {
@@ -5478,7 +5665,7 @@ Perl_newASSIGNOP(pTHX_ I32 flags, OP *left, I32 optype, OP *right)
                    /* Other ops in the list. */
                    maybe_common_vars = TRUE;
                }
-               lop = lop->op_sibling;
+               lop = OP_SIBLING(lop);
            }
        }
        else if ((left->op_private & OPpLVAL_INTRO)
@@ -5551,7 +5738,9 @@ Perl_newASSIGNOP(pTHX_ I32 flags, OP *left, I32 optype, OP *right)
 #endif
                        tmpop = cUNOPo->op_first;       /* to list (nulled) */
                        tmpop = ((UNOP*)tmpop)->op_first; /* to pushmark */
-                       tmpop->op_sibling = NULL;       /* don't free split */
+                        /* detach rest of siblings from o subtree,
+                         * and free subtree */
+                        op_sibling_splice(cUNOPo->op_first, tmpop, -1, NULL);
                        right->op_next = tmpop->op_next;  /* fix starting loc */
                        op_free(o);                     /* blow off assign */
                        right->op_flags &= ~OPf_WANT;
@@ -5710,8 +5899,6 @@ consumed by this function and become part of the constructed op tree.
 OP *
 Perl_newLOGOP(pTHX_ I32 type, I32 flags, OP *first, OP *other)
 {
-    dVAR;
-
     PERL_ARGS_ASSERT_NEWLOGOP;
 
     return new_logop(type, flags, &first, &other);
@@ -5742,7 +5929,7 @@ S_search_const(pTHX_ OP *o)
                    case OP_ENTER:
                    case OP_NULL:
                    case OP_NEXTSTATE:
-                       kid = kid->op_sibling;
+                       kid = OP_SIBLING(kid);
                        break;
                    default:
                        if (kid != cLISTOPo->op_last)
@@ -5869,7 +6056,7 @@ S_new_logop(pTHX_ I32 type, I32 flags, OP** firstp, OP** otherp)
            if ( ! (o2->op_type == OP_LIST
                    && (( o2 = cUNOPx(o2)->op_first))
                    && o2->op_type == OP_PUSHMARK
-                   && (( o2 = o2->op_sibling)) )
+                   && (( o2 = OP_SIBLING(o2))) )
            )
                o2 = other;
            if ((o2->op_type == OP_PADSV || o2->op_type == OP_PADAV
@@ -5892,7 +6079,7 @@ S_new_logop(pTHX_ I32 type, I32 flags, OP** firstp, OP** otherp)
        && ckWARN(WARN_MISC)) /* [#24076] Don't warn for <FH> err FOO. */
     {
        const OP * const k1 = ((UNOP*)first)->op_first;
-       const OP * const k2 = k1->op_sibling;
+       const OP * const k2 = OP_SIBLING(k1);
        OPCODE warnop = 0;
        switch (first->op_type)
        {
@@ -5937,19 +6124,16 @@ S_new_logop(pTHX_ I32 type, I32 flags, OP** firstp, OP** otherp)
     if (type == OP_ANDASSIGN || type == OP_ORASSIGN || type == OP_DORASSIGN)
        other->op_private |= OPpASSIGN_BACKWARDS;  /* other is an OP_SASSIGN */
 
-    NewOp(1101, logop, 1, LOGOP);
-
-    logop->op_type = (OPCODE)type;
+    logop = S_alloc_LOGOP(aTHX_ type, first, LINKLIST(other));
     logop->op_ppaddr = PL_ppaddr[type];
-    logop->op_first = first;
-    logop->op_flags = (U8)(flags | OPf_KIDS);
-    logop->op_other = LINKLIST(other);
+    logop->op_flags |= (U8)flags;
     logop->op_private = (U8)(1 | (flags >> 8));
 
     /* establish postfix order */
     logop->op_next = LINKLIST(first);
     first->op_next = (OP*)logop;
-    first->op_sibling = other;
+    assert(!OP_HAS_SIBLING(first));
+    op_sibling_splice((OP*)logop, first, 0, other);
 
     CHECKOP(type,logop);
 
@@ -6010,13 +6194,10 @@ Perl_newCONDOP(pTHX_ I32 flags, OP *first, OP *trueop, OP *falseop)
        live->op_folded = 1;
        return live;
     }
-    NewOp(1101, logop, 1, LOGOP);
-    logop->op_type = OP_COND_EXPR;
+    logop = S_alloc_LOGOP(aTHX_ OP_COND_EXPR, first, LINKLIST(trueop));
     logop->op_ppaddr = PL_ppaddr[OP_COND_EXPR];
-    logop->op_first = first;
-    logop->op_flags = (U8)(flags | OPf_KIDS);
+    logop->op_flags |= (U8)flags;
     logop->op_private = (U8)(1 | (flags >> 8));
-    logop->op_other = LINKLIST(trueop);
     logop->op_next = LINKLIST(falseop);
 
     CHECKOP(OP_COND_EXPR, /* that's logop->op_type */
@@ -6026,8 +6207,10 @@ Perl_newCONDOP(pTHX_ I32 flags, OP *first, OP *trueop, OP *falseop)
     start = LINKLIST(first);
     first->op_next = (OP*)logop;
 
-    first->op_sibling = trueop;
-    trueop->op_sibling = falseop;
+    /* make first, trueop, falseop silbings */
+    op_sibling_splice((OP*)logop, first,  0, trueop);
+    op_sibling_splice((OP*)logop, trueop, 0, falseop);
+
     o = newUNOP(OP_NULL, 0, (OP*)logop);
 
     trueop->op_next = falseop->op_next = o;
@@ -6062,17 +6245,14 @@ Perl_newRANGE(pTHX_ I32 flags, OP *left, OP *right)
 
     PERL_ARGS_ASSERT_NEWRANGE;
 
-    NewOp(1101, range, 1, LOGOP);
-
-    range->op_type = OP_RANGE;
+    range = S_alloc_LOGOP(aTHX_ OP_RANGE, left, LINKLIST(right));
     range->op_ppaddr = PL_ppaddr[OP_RANGE];
-    range->op_first = left;
     range->op_flags = OPf_KIDS;
     leftstart = LINKLIST(left);
-    range->op_other = LINKLIST(right);
     range->op_private = (U8)(1 | (flags >> 8));
 
-    left->op_sibling = right;
+    /* make left and right siblings */
+    op_sibling_splice((OP*)range, left, 0, right);
 
     range->op_next = (OP*)range;
     flip = newUNOP(OP_FLIP, flags, (OP*)range);
@@ -6124,7 +6304,6 @@ unused and should always be 1.
 OP *
 Perl_newLOOPOP(pTHX_ I32 flags, I32 debuggable, OP *expr, OP *block)
 {
-    dVAR;
     OP* listop;
     OP* o;
     const bool once = block && block->op_flags & OPf_SPECIAL &&
@@ -6152,7 +6331,7 @@ Perl_newLOOPOP(pTHX_ I32 flags, I32 debuggable, OP *expr, OP *block)
                newASSIGNOP(0, newDEFSVOP(), 0, expr) );
        } else if (expr->op_flags & OPf_KIDS) {
            const OP * const k1 = ((UNOP*)expr)->op_first;
-           const OP * const k2 = k1 ? k1->op_sibling : NULL;
+           const OP * const k2 = k1 ? OP_SIBLING(k1) : NULL;
            switch (expr->op_type) {
              case OP_NULL:
                if (k2 && (k2->op_type == OP_READLINE || k2->op_type == OP_READDIR)
@@ -6250,7 +6429,7 @@ Perl_newWHILEOP(pTHX_ I32 flags, I32 debuggable, LOOP *loop,
                newASSIGNOP(0, newDEFSVOP(), 0, expr) );
        } else if (expr->op_flags & OPf_KIDS) {
            const OP * const k1 = ((UNOP*)expr)->op_first;
-           const OP * const k2 = (k1) ? k1->op_sibling : NULL;
+           const OP * const k2 = (k1) ? OP_SIBLING(k1) : NULL;
            switch (expr->op_type) {
              case OP_NULL:
                if (k2 && (k2->op_type == OP_READLINE || k2->op_type == OP_READDIR)
@@ -6409,6 +6588,7 @@ Perl_newFOROP(pTHX_ I32 flags, OP *sv, OP *expr, OP *block, OP *cont)
        }
        iterpflags |= OPpITER_DEF;
     }
+
     if (expr->op_type == OP_RV2AV || expr->op_type == OP_PADAV) {
        expr = op_lvalue(force_list(scalar(ref(expr, OP_ITER))), OP_GREPSTART);
        iterflags |= OPf_STACKED;
@@ -6424,11 +6604,12 @@ Perl_newFOROP(pTHX_ I32 flags, OP *sv, OP *expr, OP *block, OP *cont)
        const UNOP* const flip = (UNOP*)((UNOP*)((BINOP*)expr)->op_first)->op_first;
        LOGOP* const range = (LOGOP*) flip->op_first;
        OP* const left  = range->op_first;
-       OP* const right = left->op_sibling;
+       OP* const right = OP_SIBLING(left);
        LISTOP* listop;
 
        range->op_flags &= ~OPf_KIDS;
-       range->op_first = NULL;
+        /* detach range's children */
+        op_sibling_splice((OP*)range, NULL, -1, NULL);
 
        listop = (LISTOP*)newLISTOP(OP_LIST, 0, left, right);
        listop->op_first->op_next = range->op_next;
@@ -6482,7 +6663,6 @@ becomes part of the constructed op tree.
 OP*
 Perl_newLOOPEX(pTHX_ I32 type, OP *label)
 {
-    dVAR;
     OP *o = NULL;
 
     PERL_ARGS_ASSERT_NEWLOOPEX;
@@ -6577,25 +6757,22 @@ S_newGIVWHENOP(pTHX_ OP *cond, OP *block,
 
     PERL_ARGS_ASSERT_NEWGIVWHENOP;
 
-    NewOp(1101, enterop, 1, LOGOP);
-    enterop->op_type = (Optype)enter_opcode;
+    enterop = S_alloc_LOGOP(aTHX_ enter_opcode, block, NULL);
     enterop->op_ppaddr = PL_ppaddr[enter_opcode];
-    enterop->op_flags =  (U8) OPf_KIDS;
     enterop->op_targ = ((entertarg == NOT_IN_PAD) ? 0 : entertarg);
     enterop->op_private = 0;
 
     o = newUNOP(leave_opcode, 0, (OP *) enterop);
 
     if (cond) {
-       enterop->op_first = scalar(cond);
-       cond->op_sibling = block;
+        /* prepend cond if we have one */
+        op_sibling_splice((OP*)enterop, NULL, 0, scalar(cond));
 
        o->op_next = LINKLIST(cond);
        cond->op_next = (OP *) enterop;
     }
     else {
        /* This is a default {} block */
-       enterop->op_first = block;
        enterop->op_flags |= OPf_SPECIAL;
        o      ->op_flags |= OPf_SPECIAL;
 
@@ -6626,8 +6803,6 @@ S_newGIVWHENOP(pTHX_ OP *cond, OP *block,
 STATIC bool
 S_looks_like_bool(pTHX_ const OP *o)
 {
-    dVAR;
-
     PERL_ARGS_ASSERT_LOOKS_LIKE_BOOL;
 
     switch(o->op_type) {
@@ -6638,7 +6813,7 @@ S_looks_like_bool(pTHX_ const OP *o)
        case OP_AND:
            return (
                looks_like_bool(cLOGOPo->op_first)
-            && looks_like_bool(cLOGOPo->op_first->op_sibling));
+            && looks_like_bool(OP_SIBLING(cLOGOPo->op_first)));
 
        case OP_NULL:
        case OP_SCALAR:
@@ -6708,7 +6883,6 @@ be affected.  If it is 0, the global $_ will be used.
 OP *
 Perl_newGIVENOP(pTHX_ OP *cond, OP *block, PADOFFSET defsv_off)
 {
-    dVAR;
     PERL_ARGS_ASSERT_NEWGIVENOP;
     return newGIVWHENOP(
        ref_array_or_hash(cond),
@@ -6828,10 +7002,9 @@ L<perlsub/"Constant Functions">.
 =cut
 */
 SV *
-Perl_cv_const_sv(pTHX_ const CV *const cv)
+Perl_cv_const_sv(const CV *const cv)
 {
     SV *sv;
-    PERL_UNUSED_CONTEXT;
     if (!cv)
        return NULL;
     if (!(SvTYPE(cv) == SVt_PVCV || SvTYPE(cv) == SVt_PVFM))
@@ -6842,9 +7015,8 @@ Perl_cv_const_sv(pTHX_ const CV *const cv)
 }
 
 SV *
-Perl_cv_const_sv_or_av(pTHX_ const CV * const cv)
+Perl_cv_const_sv_or_av(const CV * const cv)
 {
-    PERL_UNUSED_CONTEXT;
     if (!cv)
        return NULL;
     assert (SvTYPE(cv) == SVt_PVCV || SvTYPE(cv) == SVt_PVFM);
@@ -6875,14 +7047,13 @@ Perl_cv_const_sv_or_av(pTHX_ const CV * const cv)
 SV *
 Perl_op_const_sv(pTHX_ const OP *o, CV *cv)
 {
-    dVAR;
     SV *sv = NULL;
 
     if (!o)
        return NULL;
 
     if (o->op_type == OP_LINESEQ && cLISTOPo->op_first)
-       o = cLISTOPo->op_first->op_sibling;
+       o = OP_SIBLING(cLISTOPo->op_first);
 
     for (; o; o = o->op_next) {
        const OPCODE type = o->op_type;
@@ -6983,7 +7154,6 @@ S_already_defined(pTHX_ CV *const cv, OP * const block, OP * const o,
 CV *
 Perl_newMYSUB(pTHX_ I32 floor, OP *o, OP *proto, OP *attrs, OP *block)
 {
-    dVAR;
     CV **spot;
     SV **svspot;
     const char *ps;
@@ -7324,7 +7494,6 @@ CV *
 Perl_newATTRSUB_x(pTHX_ I32 floor, OP *o, OP *proto, OP *attrs,
                            OP *block, bool o_is_gv)
 {
-    dVAR;
     GV *gv;
     const char *ps;
     STRLEN ps_len = 0; /* init it to avoid false uninit warning from icc */
@@ -7755,7 +7924,6 @@ CV *
 Perl_newCONSTSUB_flags(pTHX_ HV *stash, const char *name, STRLEN len,
                              U32 flags, SV *sv)
 {
-    dVAR;
     CV* cv;
     const char *const file = CopFILE(PL_curcop);
 
@@ -7935,7 +8103,6 @@ Perl_newXS(pTHX_ const char *name, XSUBADDR_t subaddr, const char *filename)
 void
 Perl_newFORM(pTHX_ I32 floor, OP *o, OP *block)
 {
-    dVAR;
     CV *cv;
 
     GV *gv;
@@ -8086,8 +8253,7 @@ Perl_newAVREF(pTHX_ OP *o)
        return o;
     }
     else if ((o->op_type == OP_RV2AV || o->op_type == OP_PADAV)) {
-       Perl_ck_warner_d(aTHX_ packWARN(WARN_DEPRECATED),
-                      "Using an array as a reference is deprecated");
+       Perl_croak(aTHX_ "Can't use an array as a reference");
     }
     return newUNOP(OP_RV2AV, 0, scalar(o));
 }
@@ -8113,8 +8279,7 @@ Perl_newHVREF(pTHX_ OP *o)
        return o;
     }
     else if ((o->op_type == OP_RV2HV || o->op_type == OP_PADHV)) {
-       Perl_ck_warner_d(aTHX_ packWARN(WARN_DEPRECATED),
-                      "Using a hash as a reference is deprecated");
+       Perl_croak(aTHX_ "Can't use a hash as a reference");
     }
     return newUNOP(OP_RV2HV, 0, scalar(o));
 }
@@ -8208,12 +8373,15 @@ Perl_ck_backtick(pTHX_ OP *o)
 {
     GV *gv;
     OP *newop = NULL;
+    OP *sibl;
     PERL_ARGS_ASSERT_CK_BACKTICK;
     /* qx and `` have a null pushmark; CORE::readpipe has only one kid. */
-    if (o->op_flags & OPf_KIDS && cUNOPo->op_first->op_sibling
-     && (gv = gv_override("readpipe",8))) {
-       newop = S_new_entersubop(aTHX_ gv, cUNOPo->op_first->op_sibling);
-       cUNOPo->op_first->op_sibling = NULL;
+    if (o->op_flags & OPf_KIDS && (sibl = OP_SIBLING(cUNOPo->op_first))
+     && (gv = gv_override("readpipe",8)))
+    {
+        /* detach rest of silbings from o and its first child */
+        op_sibling_splice(o, cUNOPo->op_first, -1, NULL);
+       newop = S_new_entersubop(aTHX_ gv, sibl);
     }
     else if (!(o->op_flags & OPf_KIDS))
        newop = newUNOP(OP_BACKTICK, 0, newDEFSVOP());
@@ -8228,8 +8396,6 @@ Perl_ck_backtick(pTHX_ OP *o)
 OP *
 Perl_ck_bitop(pTHX_ OP *o)
 {
-    dVAR;
-
     PERL_ARGS_ASSERT_CK_BITOP;
 
     o->op_private = (U8)(PL_hints & HINT_INTEGER);
@@ -8239,7 +8405,7 @@ Perl_ck_bitop(pTHX_ OP *o)
             || o->op_type == OP_BIT_XOR))
     {
        const OP * const left = cBINOPo->op_first;
-       const OP * const right = left->op_sibling;
+       const OP * const right = OP_SIBLING(left);
        if ((OP_IS_NUMCOMPARE(left->op_type) &&
                (left->op_flags & OPf_PARENS) == 0) ||
            (OP_IS_NUMCOMPARE(right->op_type) &&
@@ -8257,6 +8423,7 @@ PERL_STATIC_INLINE bool
 is_dollar_bracket(pTHX_ const OP * const o)
 {
     const OP *kid;
+    PERL_UNUSED_CONTEXT;
     return o->op_type == OP_RV2SV && o->op_flags & OPf_KIDS
        && (kid = cUNOPx(o)->op_first)
        && kid->op_type == OP_GV
@@ -8269,14 +8436,16 @@ Perl_ck_cmp(pTHX_ OP *o)
     PERL_ARGS_ASSERT_CK_CMP;
     if (ckWARN(WARN_SYNTAX)) {
        const OP *kid = cUNOPo->op_first;
-       if (kid && (
-               (
-                  is_dollar_bracket(aTHX_ kid)
-               && kid->op_sibling && kid->op_sibling->op_type == OP_CONST
+       if (kid &&
+            (
+               (   is_dollar_bracket(aTHX_ kid)
+                 && OP_SIBLING(kid) && OP_SIBLING(kid)->op_type == OP_CONST
                )
-            || (  kid->op_type == OP_CONST
-               && (kid = kid->op_sibling) && is_dollar_bracket(aTHX_ kid))
-          ))
+            || (   kid->op_type == OP_CONST
+                && (kid = OP_SIBLING(kid)) && is_dollar_bracket(aTHX_ kid)
+                )
+          )
+        )
            Perl_warner(aTHX_ packWARN(WARN_SYNTAX),
                        "$[ used in %s (did you mean $] ?)", OP_DESC(o));
     }
@@ -8307,19 +8476,22 @@ Perl_ck_spair(pTHX_ OP *o)
     if (o->op_flags & OPf_KIDS) {
        OP* newop;
        OP* kid;
+        OP* kidkid;
        const OPCODE type = o->op_type;
        o = modkids(ck_fun(o), type);
-       kid = cUNOPo->op_first;
-       newop = kUNOP->op_first->op_sibling;
+       kid    = cUNOPo->op_first;
+       kidkid = kUNOP->op_first;
+       newop = OP_SIBLING(kidkid);
        if (newop) {
            const OPCODE type = newop->op_type;
-           if (newop->op_sibling || !(PL_opargs[type] & OA_RETSCALAR) ||
+           if (OP_HAS_SIBLING(newop) || !(PL_opargs[type] & OA_RETSCALAR) ||
                    type == OP_PADAV || type == OP_PADHV ||
                    type == OP_RV2AV || type == OP_RV2HV)
                return o;
        }
-       op_free(kUNOP->op_first);
-       kUNOP->op_first = newop;
+        /* excise first sibling */
+        op_sibling_splice(kid, NULL, 1, NULL);
+       op_free(kidkid);
     }
     /* transforms OP_REFGEN into OP_SREFGEN, OP_CHOP into OP_SCHOP,
      * and OP_CHOMP into OP_SCHOMP */
@@ -8368,8 +8540,6 @@ Perl_ck_delete(pTHX_ OP *o)
 OP *
 Perl_ck_eof(pTHX_ OP *o)
 {
-    dVAR;
-
     PERL_ARGS_ASSERT_CK_EOF;
 
     if (o->op_flags & OPf_KIDS) {
@@ -8403,13 +8573,12 @@ Perl_ck_eval(pTHX_ OP *o)
        if (kid->op_type == OP_LINESEQ || kid->op_type == OP_STUB) {
            LOGOP *enter;
 
-           cUNOPo->op_first = 0;
+            /* cut whole sibling chain free from o */
+            op_sibling_splice(o, NULL, -1, NULL);
            op_free(o);
 
-           NewOp(1101, enter, 1, LOGOP);
-           enter->op_type = OP_ENTERTRY;
+            enter = S_alloc_LOGOP(aTHX_ OP_ENTERTRY, NULL, NULL);
            enter->op_ppaddr = PL_ppaddr[OP_ENTERTRY];
-           enter->op_private = 0;
 
            /* establish postfix order */
            enter->op_next = (OP*)enter;
@@ -8437,7 +8606,9 @@ Perl_ck_eval(pTHX_ OP *o)
        /* Store a copy of %^H that pp_entereval can pick up. */
        OP *hhop = newSVOP(OP_HINTSEVAL, 0,
                           MUTABLE_SV(hv_copy_hints_hv(GvHV(PL_hintgv))));
-       cUNOPo->op_first->op_sibling = hhop;
+        /* append hhop to only child  */
+        op_sibling_splice(o, cUNOPo->op_first, 0, hhop);
+
        o->op_private |= OPpEVAL_HAS_HH;
     }
     if (!(o->op_private & OPpEVAL_BYTES)
@@ -8454,7 +8625,7 @@ Perl_ck_exec(pTHX_ OP *o)
     if (o->op_flags & OPf_STACKED) {
         OP *kid;
        o = ck_fun(o);
-       kid = cUNOPo->op_first->op_sibling;
+       kid = OP_SIBLING(cUNOPo->op_first);
        if (kid->op_type == OP_RV2GV)
            op_null(kid);
     }
@@ -8466,8 +8637,6 @@ Perl_ck_exec(pTHX_ OP *o)
 OP *
 Perl_ck_exists(pTHX_ OP *o)
 {
-    dVAR;
-
     PERL_ARGS_ASSERT_CK_EXISTS;
 
     o = ck_fun(o);
@@ -8650,7 +8819,6 @@ Perl_ck_ftst(pTHX_ OP *o)
 OP *
 Perl_ck_fun(pTHX_ OP *o)
 {
-    dVAR;
     const int type = o->op_type;
     I32 oa = PL_opargs[type] >> OASHIFT;
 
@@ -8664,17 +8832,16 @@ Perl_ck_fun(pTHX_ OP *o)
     }
 
     if (o->op_flags & OPf_KIDS) {
-        OP **tokid = &cLISTOPo->op_first;
+        OP *prev_kid = NULL;
         OP *kid = cLISTOPo->op_first;
-        OP *sibl;
         I32 numargs = 0;
        bool seen_optional = FALSE;
 
        if (kid->op_type == OP_PUSHMARK ||
            (kid->op_type == OP_NULL && kid->op_targ == OP_PUSHMARK))
        {
-           tokid = &kid->op_sibling;
-           kid = kid->op_sibling;
+           prev_kid = kid;
+           kid = OP_SIBLING(kid);
        }
        if (kid && kid->op_type == OP_COREARGS) {
            bool optional = FALSE;
@@ -8689,14 +8856,16 @@ Perl_ck_fun(pTHX_ OP *o)
 
        while (oa) {
            if (oa & OA_OPTIONAL || (oa & 7) == OA_LIST) {
-               if (!kid && !seen_optional && PL_opargs[type] & OA_DEFGV)
-                   *tokid = kid = newDEFSVOP();
+               if (!kid && !seen_optional && PL_opargs[type] & OA_DEFGV) {
+                   kid = newDEFSVOP();
+                    /* append kid to chain */
+                    op_sibling_splice(o, prev_kid, 0, kid);
+                }
                seen_optional = TRUE;
            }
            if (!kid) break;
 
            numargs++;
-           sibl = kid->op_sibling;
            switch (oa & 7) {
            case OA_SCALAR:
                /* list seen where single (scalar) arg expected? */
@@ -8717,7 +8886,7 @@ Perl_ck_fun(pTHX_ OP *o)
                break;
            case OA_AVREF:
                if ((type == OP_PUSH || type == OP_UNSHIFT)
-                   && !kid->op_sibling)
+                   && !OP_HAS_SIBLING(kid))
                    Perl_ck_warner(aTHX_ packWARN(WARN_SYNTAX),
                                   "Useless use of %s with no values",
                                   PL_op_desc[type]);
@@ -8746,12 +8915,11 @@ Perl_ck_fun(pTHX_ OP *o)
                break;
            case OA_CVREF:
                {
-                   OP * const newop = newUNOP(OP_NULL, 0, kid);
-                   kid->op_sibling = 0;
+                    /* replace kid with newop in chain */
+                   OP * const newop =
+                        S_op_sibling_newUNOP(aTHX_ o, prev_kid, OP_NULL, 0);
                    newop->op_next = newop;
                    kid = newop;
-                   kid->op_sibling = sibl;
-                   *tokid = kid;
                }
                break;
            case OA_FILEREF:
@@ -8761,9 +8929,8 @@ Perl_ck_fun(pTHX_ OP *o)
                    {
                        OP * const newop = newGVOP(OP_GV, 0,
                            gv_fetchsv(((SVOP*)kid)->op_sv, GV_ADD, SVt_PVIO));
-                       if (!(o->op_private & 1) && /* if not unop */
-                           kid == cLISTOPo->op_last)
-                           cLISTOPo->op_last = newop;
+                        /* replace kid with newop in chain */
+                        op_sibling_splice(o, prev_kid, 1, newop);
                        op_free(kid);
                        kid = newop;
                    }
@@ -8864,13 +9031,12 @@ Perl_ck_fun(pTHX_ OP *o)
                                 if ( name_utf8 ) SvUTF8_on(namesv);
                            }
                        }
-                       kid->op_sibling = 0;
-                       kid = newUNOP(OP_RV2GV, flags, scalar(kid));
-                       kid->op_targ = targ;
-                       kid->op_private |= priv;
+                        scalar(kid);
+                        kid = S_op_sibling_newUNOP(aTHX_ o, prev_kid,
+                                    OP_RV2GV, flags);
+                        kid->op_targ = targ;
+                        kid->op_private |= priv;
                    }
-                   kid->op_sibling = sibl;
-                   *tokid = kid;
                }
                scalar(kid);
                break;
@@ -8883,8 +9049,8 @@ Perl_ck_fun(pTHX_ OP *o)
                break;
            }
            oa >>= 4;
-           tokid = &kid->op_sibling;
-           kid = kid->op_sibling;
+           prev_kid = kid;
+           kid = OP_SIBLING(kid);
        }
        /* FIXME - should the numargs or-ing move after the too many
          * arguments check? */
@@ -8911,13 +9077,12 @@ Perl_ck_fun(pTHX_ OP *o)
 OP *
 Perl_ck_glob(pTHX_ OP *o)
 {
-    dVAR;
     GV *gv;
 
     PERL_ARGS_ASSERT_CK_GLOB;
 
     o = ck_fun(o);
-    if ((o->op_flags & OPf_KIDS) && !cLISTOPo->op_first->op_sibling)
+    if ((o->op_flags & OPf_KIDS) && !OP_HAS_SIBLING(cLISTOPo->op_first))
        op_append_elem(OP_GLOB, o, newDEFSVOP()); /* glob() => glob($_) */
 
     if (!(o->op_flags & OPf_SPECIAL) && (gv = gv_override("glob", 4)))
@@ -8974,12 +9139,12 @@ Perl_ck_grep(pTHX_ OP *o)
     /* don't allocate gwop here, as we may leak it if PL_parser->error_count > 0 */
 
     if (o->op_flags & OPf_STACKED) {
-        kid = cUNOPx(cLISTOPo->op_first->op_sibling)->op_first;
+        kid = cUNOPx(OP_SIBLING(cLISTOPo->op_first))->op_first;
        if (kid->op_type != OP_SCOPE && kid->op_type != OP_LEAVE)
            return no_fh_allowed(o);
        o->op_flags &= ~OPf_STACKED;
     }
-    kid = cLISTOPo->op_first->op_sibling;
+    kid = OP_SIBLING(cLISTOPo->op_first);
     if (type == OP_MAPWHILE)
        list(kid);
     else
@@ -8987,17 +9152,13 @@ Perl_ck_grep(pTHX_ OP *o)
     o = ck_fun(o);
     if (PL_parser && PL_parser->error_count)
        return o;
-    kid = cLISTOPo->op_first->op_sibling;
+    kid = OP_SIBLING(cLISTOPo->op_first);
     if (kid->op_type != OP_NULL)
        Perl_croak(aTHX_ "panic: ck_grep, type=%u", (unsigned) kid->op_type);
     kid = kUNOP->op_first;
 
-    NewOp(1101, gwop, 1, LOGOP);
-    gwop->op_type = type;
+    gwop = S_alloc_LOGOP(aTHX_ type, o, LINKLIST(kid));
     gwop->op_ppaddr = PL_ppaddr[type];
-    gwop->op_first = o;
-    gwop->op_flags |= OPf_KIDS;
-    gwop->op_other = LINKLIST(kid);
     kid->op_next = (OP*)gwop;
     offset = pad_findmy_pvs("$_", 0);
     if (offset == NOT_IN_PAD || PAD_COMPNAME_FLAGS_isOUR(offset)) {
@@ -9009,8 +9170,8 @@ Perl_ck_grep(pTHX_ OP *o)
        gwop->op_targ = o->op_targ = offset;
     }
 
-    kid = cLISTOPo->op_first->op_sibling;
-    for (kid = kid->op_sibling; kid; kid = kid->op_sibling)
+    kid = OP_SIBLING(cLISTOPo->op_first);
+    for (kid = OP_SIBLING(kid); kid; kid = OP_SIBLING(kid))
        op_lvalue(kid, OP_GREPSTART);
 
     return (OP*)gwop;
@@ -9022,9 +9183,9 @@ Perl_ck_index(pTHX_ OP *o)
     PERL_ARGS_ASSERT_CK_INDEX;
 
     if (o->op_flags & OPf_KIDS) {
-       OP *kid = cLISTOPo->op_first->op_sibling;       /* get past pushmark */
+       OP *kid = OP_SIBLING(cLISTOPo->op_first);       /* get past pushmark */
        if (kid)
-           kid = kid->op_sibling;                      /* get past "big" */
+           kid = OP_SIBLING(kid);                      /* get past "big" */
        if (kid && kid->op_type == OP_CONST) {
            const bool save_taint = TAINT_get;
            SV *sv = kSVOP->op_sv;
@@ -9064,17 +9225,13 @@ Perl_ck_defined(pTHX_ OP *o)            /* 19990527 MJD */
        case OP_RV2AV:
        case OP_PADAV:
        case OP_AASSIGN:                /* Is this a good idea? */
-           Perl_ck_warner_d(aTHX_ packWARN(WARN_DEPRECATED),
-                          "defined(@array) is deprecated");
-           Perl_ck_warner_d(aTHX_ packWARN(WARN_DEPRECATED),
-                          "\t(Maybe you should just omit the defined()?)\n");
+           Perl_croak(aTHX_ "Can't use 'defined(@array)'"
+                            " (Maybe you should just omit the defined()?)");
        break;
        case OP_RV2HV:
        case OP_PADHV:
-           Perl_ck_warner_d(aTHX_ packWARN(WARN_DEPRECATED),
-                          "defined(%%hash) is deprecated");
-           Perl_ck_warner_d(aTHX_ packWARN(WARN_DEPRECATED),
-                          "\t(Maybe you should just omit the defined()?)\n");
+           Perl_croak(aTHX_ "Can't use 'defined(%%hash)'"
+                            " (Maybe you should just omit the defined()?)");
            break;
        default:
            /* no warning */
@@ -9125,17 +9282,18 @@ Perl_ck_listiob(pTHX_ OP *o)
        kid = cLISTOPo->op_first;
     }
     if (kid->op_type == OP_PUSHMARK)
-       kid = kid->op_sibling;
+       kid = OP_SIBLING(kid);
     if (kid && o->op_flags & OPf_STACKED)
-       kid = kid->op_sibling;
-    else if (kid && !kid->op_sibling) {                /* print HANDLE; */
+       kid = OP_SIBLING(kid);
+    else if (kid && !OP_HAS_SIBLING(kid)) {            /* print HANDLE; */
        if (kid->op_type == OP_CONST && kid->op_private & OPpCONST_BARE
         && !kid->op_folded) {
            o->op_flags |= OPf_STACKED; /* make it a filehandle */
-           kid = newUNOP(OP_RV2GV, OPf_REF, scalar(kid));
-           cLISTOPo->op_first->op_sibling = kid;
-           cLISTOPo->op_last = kid;
-           kid = kid->op_sibling;
+            scalar(kid);
+            /* replace old const op with new OP_RV2GV parent */
+            kid = S_op_sibling_newUNOP(aTHX_ o, cLISTOPo->op_first,
+                                        OP_RV2GV, OPf_REF);
+           kid = OP_SIBLING(kid);
        }
     }
 
@@ -9153,12 +9311,19 @@ Perl_ck_smartmatch(pTHX_ OP *o)
     PERL_ARGS_ASSERT_CK_SMARTMATCH;
     if (0 == (o->op_flags & OPf_SPECIAL)) {
        OP *first  = cBINOPo->op_first;
-       OP *second = first->op_sibling;
+       OP *second = OP_SIBLING(first);
        
        /* Implicitly take a reference to an array or hash */
-       first->op_sibling = NULL;
-       first = cBINOPo->op_first = ref_array_or_hash(first);
-       second = first->op_sibling = ref_array_or_hash(second);
+
+        /* remove the original two siblings, then add back the
+         * (possibly different) first and second sibs.
+         */
+        op_sibling_splice(o, NULL, 1, NULL);
+        op_sibling_splice(o, NULL, 1, NULL);
+       first  = ref_array_or_hash(first);
+       second = ref_array_or_hash(second);
+        op_sibling_splice(o, NULL, 0, second);
+        op_sibling_splice(o, NULL, 0, first);
        
        /* Implicitly take a reference to a regular expression */
        if (first->op_type == OP_MATCH) {
@@ -9190,7 +9355,7 @@ Perl_ck_sassign(pTHX_ OP *o)
        && !(kid->op_private & OPpTARGET_MY)
        )
     {
-       OP * const kkid = kid->op_sibling;
+       OP * const kkid = OP_SIBLING(kid);
 
        /* Can just relocate the target. */
        if (kkid && kkid->op_type == OP_PADSV
@@ -9198,17 +9363,19 @@ Perl_ck_sassign(pTHX_ OP *o)
        {
            kid->op_targ = kkid->op_targ;
            kkid->op_targ = 0;
-           /* Now we do not need PADSV and SASSIGN. */
-           kid->op_sibling = o->op_sibling;    /* NULL */
-           cLISTOPo->op_first = NULL;
+           /* Now we do not need PADSV and SASSIGN.
+             * first replace the PADSV with OP_SIBLING(o), then
+             * detach kid and OP_SIBLING(o) from o */
+            op_sibling_splice(o, kid, 1, OP_SIBLING(o));
+            op_sibling_splice(o, NULL, -1, NULL);
            op_free(o);
            op_free(kkid);
            kid->op_private |= OPpTARGET_MY;    /* Used for context settings */
            return kid;
        }
     }
-    if (kid->op_sibling) {
-       OP *kkid = kid->op_sibling;
+    if (OP_HAS_SIBLING(kid)) {
+       OP *kkid = OP_SIBLING(kid);
        /* For state variable assignment, kkid is a list op whose op_last
           is a padsv. */
        if ((kkid->op_type == OP_PADSV ||
@@ -9217,7 +9384,7 @@ Perl_ck_sassign(pTHX_ OP *o)
             )
            )
                && (kkid->op_private & OPpLVAL_INTRO)
-               && SvPAD_STATE(*av_fetch(PL_comppad_name, kkid->op_targ, FALSE))) {
+               && SvPAD_STATE(PAD_COMPNAME_SV(kkid->op_targ))) {
            const PADOFFSET target = kkid->op_targ;
            OP *const other = newOP(OP_PADSV,
                                    kkid->op_flags
@@ -9234,9 +9401,9 @@ Perl_ck_sassign(pTHX_ OP *o)
            other->op_targ = target;
 
            /* Because we change the type of the op here, we will skip the
-              assignment binop->op_last = binop->op_first->op_sibling; at 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 = cBINOPo->op_first->op_sibling;
+           cBINOPo->op_last = OP_SIBLING(cBINOPo->op_first);
 
            return nullop;
        }
@@ -9247,8 +9414,6 @@ Perl_ck_sassign(pTHX_ OP *o)
 OP *
 Perl_ck_match(pTHX_ OP *o)
 {
-    dVAR;
-
     PERL_ARGS_ASSERT_CK_MATCH;
 
     if (o->op_type != OP_QR && PL_compcv) {
@@ -9300,8 +9465,6 @@ Perl_ck_null(pTHX_ OP *o)
 OP *
 Perl_ck_open(pTHX_ OP *o)
 {
-    dVAR;
-
     PERL_ARGS_ASSERT_CK_OPEN;
 
     S_io_hints(aTHX_ o);
@@ -9316,13 +9479,13 @@ Perl_ck_open(pTHX_ OP *o)
         if ((last->op_type == OP_CONST) &&             /* The bareword. */
             (last->op_private & OPpCONST_BARE) &&
             (last->op_private & OPpCONST_STRICT) &&
-            (oa = first->op_sibling) &&                /* The fh. */
-            (oa = oa->op_sibling) &&                   /* The mode. */
+            (oa = OP_SIBLING(first)) &&                /* The fh. */
+            (oa = OP_SIBLING(oa)) &&                   /* The mode. */
             (oa->op_type == OP_CONST) &&
             SvPOK(((SVOP*)oa)->op_sv) &&
             (mode = SvPVX_const(((SVOP*)oa)->op_sv)) &&
             mode[0] == '>' && mode[1] == '&' &&        /* A dup open. */
-            (last == oa->op_sibling))                  /* The bareword. */
+            (last == OP_SIBLING(oa)))                  /* The bareword. */
              last->op_private &= ~OPpCONST_STRICT;
     }
     return ck_fun(o);
@@ -9335,7 +9498,8 @@ Perl_ck_repeat(pTHX_ OP *o)
 
     if (cBINOPo->op_first->op_flags & OPf_PARENS) {
        o->op_private |= OPpREPEAT_DOLIST;
-       cBINOPo->op_first = force_list(cBINOPo->op_first);
+        /* promote the siblings to a list if they're not already */
+        op_sibling_splice(o, NULL, -1, force_list(cBINOPo->op_first));
     }
     else
        scalar(o);
@@ -9345,7 +9509,6 @@ Perl_ck_repeat(pTHX_ OP *o)
 OP *
 Perl_ck_require(pTHX_ OP *o)
 {
-    dVAR;
     GV* gv;
 
     PERL_ARGS_ASSERT_CK_REQUIRE;
@@ -9387,7 +9550,7 @@ Perl_ck_require(pTHX_ OP *o)
        OP *kid, *newop;
        if (o->op_flags & OPf_KIDS) {
            kid = cUNOPo->op_first;
-           cUNOPo->op_first = NULL;
+            op_sibling_splice(o, NULL, -1, NULL);
        }
        else {
            kid = newDEFSVOP();
@@ -9403,14 +9566,13 @@ Perl_ck_require(pTHX_ OP *o)
 OP *
 Perl_ck_return(pTHX_ OP *o)
 {
-    dVAR;
     OP *kid;
 
     PERL_ARGS_ASSERT_CK_RETURN;
 
-    kid = cLISTOPo->op_first->op_sibling;
+    kid = OP_SIBLING(cLISTOPo->op_first);
     if (CvLVALUE(PL_compcv)) {
-       for (; kid; kid = kid->op_sibling)
+       for (; kid; kid = OP_SIBLING(kid))
            op_lvalue(kid, OP_LEAVESUBLV);
     }
 
@@ -9426,8 +9588,8 @@ Perl_ck_select(pTHX_ OP *o)
     PERL_ARGS_ASSERT_CK_SELECT;
 
     if (o->op_flags & OPf_KIDS) {
-       kid = cLISTOPo->op_first->op_sibling;   /* get past pushmark */
-       if (kid && kid->op_sibling) {
+       kid = OP_SIBLING(cLISTOPo->op_first);   /* get past pushmark */
+       if (kid && OP_HAS_SIBLING(kid)) {
            o->op_type = OP_SSELECT;
            o->op_ppaddr = PL_ppaddr[OP_SSELECT];
            o = ck_fun(o);
@@ -9435,7 +9597,7 @@ Perl_ck_select(pTHX_ OP *o)
        }
     }
     o = ck_fun(o);
-    kid = cLISTOPo->op_first->op_sibling;    /* get past pushmark */
+    kid = OP_SIBLING(cLISTOPo->op_first);    /* get past pushmark */
     if (kid && kid->op_type == OP_RV2GV)
        kid->op_private &= ~HINT_STRICT_REFS;
     return o;
@@ -9444,7 +9606,6 @@ Perl_ck_select(pTHX_ OP *o)
 OP *
 Perl_ck_shift(pTHX_ OP *o)
 {
-    dVAR;
     const I32 type = o->op_type;
 
     PERL_ARGS_ASSERT_CK_SHIFT;
@@ -9467,7 +9628,6 @@ Perl_ck_shift(pTHX_ OP *o)
 OP *
 Perl_ck_sort(pTHX_ OP *o)
 {
-    dVAR;
     OP *firstkid;
     OP *kid;
     HV * const hinthv =
@@ -9489,7 +9649,7 @@ Perl_ck_sort(pTHX_ OP *o)
 
     if (o->op_flags & OPf_STACKED)
        simplify_sort(o);
-    firstkid = cLISTOPo->op_first->op_sibling;         /* get past pushmark */
+    firstkid = OP_SIBLING(cLISTOPo->op_first);         /* get past pushmark */
 
     if ((stacked = o->op_flags & OPf_STACKED)) {       /* may have been cleared */
        OP *kid = cUNOPx(firstkid)->op_first;           /* get past null */
@@ -9509,10 +9669,10 @@ Perl_ck_sort(pTHX_ OP *o)
            o->op_flags |= OPf_SPECIAL;
        }
 
-       firstkid = firstkid->op_sibling;
+       firstkid = OP_SIBLING(firstkid);
     }
 
-    for (kid = firstkid; kid; kid = kid->op_sibling) {
+    for (kid = firstkid; kid; kid = OP_SIBLING(kid)) {
        /* provide list context for arguments */
        list(kid);
        if (stacked)
@@ -9535,8 +9695,7 @@ Perl_ck_sort(pTHX_ OP *o)
 STATIC void
 S_simplify_sort(pTHX_ OP *o)
 {
-    dVAR;
-    OP *kid = cLISTOPo->op_first->op_sibling;  /* get past pushmark */
+    OP *kid = OP_SIBLING(cLISTOPo->op_first);  /* get past pushmark */
     OP *k;
     int descending;
     GV *gv;
@@ -9578,7 +9737,7 @@ S_simplify_sort(pTHX_ OP *o)
        kid = kBINOP->op_first;
        do {
            if (kid->op_type == OP_PADSV) {
-               SV * const name = AvARRAY(PL_comppad_name)[kid->op_targ];
+               SV * const name = PAD_COMPNAME_SV(kid->op_targ);
                if (SvCUR(name) == 2 && *SvPVX(name) == '$'
                 && (SvPVX(name)[1] == 'a' || SvPVX(name)[1] == 'b'))
                    /* diag_listed_as: "my %s" used in sort comparison */
@@ -9587,7 +9746,7 @@ S_simplify_sort(pTHX_ OP *o)
                                      SvPAD_STATE(name) ? "state" : "my",
                                      SvPVX(name));
            }
-       } while ((kid = kid->op_sibling));
+       } while ((kid = OP_SIBLING(kid)));
        return;
     }
     kid = kBINOP->op_first;                            /* get past cmp */
@@ -9626,9 +9785,10 @@ S_simplify_sort(pTHX_ OP *o)
        o->op_private |= OPpSORT_NUMERIC;
     if (k->op_type == OP_I_NCMP)
        o->op_private |= OPpSORT_NUMERIC | OPpSORT_INTEGER;
-    kid = cLISTOPo->op_first->op_sibling;
-    cLISTOPo->op_first->op_sibling = kid->op_sibling; /* bypass old block */
-    op_free(kid);                                    /* then delete it */
+    kid = OP_SIBLING(cLISTOPo->op_first);
+    /* cut out and delete old block (second sibling) */
+    op_sibling_splice(o, cLISTOPo->op_first, 1, NULL);
+    op_free(kid);
 }
 
 OP *
@@ -9645,23 +9805,18 @@ Perl_ck_split(pTHX_ OP *o)
     kid = cLISTOPo->op_first;
     if (kid->op_type != OP_NULL)
        Perl_croak(aTHX_ "panic: ck_split, type=%u", (unsigned) kid->op_type);
-    kid = kid->op_sibling;
-    op_free(cLISTOPo->op_first);
-    if (kid)
-       cLISTOPo->op_first = kid;
-    else {
-       cLISTOPo->op_first = kid = newSVOP(OP_CONST, 0, newSVpvs(" "));
-       cLISTOPo->op_last = kid; /* There was only one element previously */
-    }
+    /* delete leading NULL node, then add a CONST if no other nodes */
+    op_sibling_splice(o, NULL, 1,
+            OP_HAS_SIBLING(kid) ? NULL : newSVOP(OP_CONST, 0, newSVpvs(" ")));
+    op_free(kid);
+    kid = cLISTOPo->op_first;
 
     if (kid->op_type != OP_MATCH || kid->op_flags & OPf_STACKED) {
-       OP * const sibl = kid->op_sibling;
-       kid->op_sibling = 0;
-        kid = pmruntime( newPMOP(OP_MATCH, OPf_SPECIAL), kid, 0, 0); /* OPf_SPECIAL is used to trigger split " " behavior */
-       if (cLISTOPo->op_first == cLISTOPo->op_last)
-           cLISTOPo->op_last = kid;
-       cLISTOPo->op_first = kid;
-       kid->op_sibling = sibl;
+        /* remove kid, and replace with new optree */
+        op_sibling_splice(o, NULL, 1, NULL);
+        /* OPf_SPECIAL is used to trigger split " " behavior */
+        kid = pmruntime( newPMOP(OP_MATCH, OPf_SPECIAL), kid, 0, 0);
+        op_sibling_splice(o, NULL, 0, kid);
     }
 
     kid->op_type = OP_PUSHRE;
@@ -9672,24 +9827,24 @@ Perl_ck_split(pTHX_ OP *o)
                     "Use of /g modifier is meaningless in split");
     }
 
-    if (!kid->op_sibling)
+    if (!OP_HAS_SIBLING(kid))
        op_append_elem(OP_SPLIT, o, newDEFSVOP());
 
-    kid = kid->op_sibling;
+    kid = OP_SIBLING(kid);
     assert(kid);
     scalar(kid);
 
-    if (!kid->op_sibling)
+    if (!OP_HAS_SIBLING(kid))
     {
        op_append_elem(OP_SPLIT, o, newSVOP(OP_CONST, 0, newSViv(0)));
        o->op_private |= OPpSPLIT_IMPLIM;
     }
-    assert(kid->op_sibling);
+    assert(OP_HAS_SIBLING(kid));
 
-    kid = kid->op_sibling;
+    kid = OP_SIBLING(kid);
     scalar(kid);
 
-    if (kid->op_sibling)
+    if (OP_HAS_SIBLING(kid))
        return too_many_arguments_pv(o,OP_DESC(o), 0);
 
     return o;
@@ -9698,7 +9853,7 @@ Perl_ck_split(pTHX_ OP *o)
 OP *
 Perl_ck_join(pTHX_ OP *o)
 {
-    const OP * const kid = cLISTOPo->op_first->op_sibling;
+    const OP * const kid = OP_SIBLING(cLISTOPo->op_first);
 
     PERL_ARGS_ASSERT_CK_JOIN;
 
@@ -9849,9 +10004,9 @@ Perl_ck_entersub_args_list(pTHX_ OP *entersubop)
     OP *aop;
     PERL_ARGS_ASSERT_CK_ENTERSUB_ARGS_LIST;
     aop = cUNOPx(entersubop)->op_first;
-    if (!aop->op_sibling)
+    if (!OP_HAS_SIBLING(aop))
        aop = cUNOPx(aop)->op_first;
-    for (aop = aop->op_sibling; aop->op_sibling; aop = aop->op_sibling) {
+    for (aop = OP_SIBLING(aop); OP_HAS_SIBLING(aop); aop = OP_SIBLING(aop)) {
         list(aop);
         op_lvalue(aop, OP_ENTERSUB);
     }
@@ -9891,7 +10046,7 @@ Perl_ck_entersub_args_proto(pTHX_ OP *entersubop, GV *namegv, SV *protosv)
 {
     STRLEN proto_len;
     const char *proto, *proto_end;
-    OP *aop, *prev, *cvop;
+    OP *aop, *prev, *cvop, *parent;
     int optional = 0;
     I32 arg = 0;
     I32 contextclass = 0;
@@ -9905,12 +10060,15 @@ Perl_ck_entersub_args_proto(pTHX_ OP *entersubop, GV *namegv, SV *protosv)
     else proto = SvPV(protosv, proto_len);
     proto = S_strip_spaces(aTHX_ proto, &proto_len);
     proto_end = proto + proto_len;
+    parent = entersubop;
     aop = cUNOPx(entersubop)->op_first;
-    if (!aop->op_sibling)
+    if (!OP_HAS_SIBLING(aop)) {
+        parent = aop;
        aop = cUNOPx(aop)->op_first;
+    }
     prev = aop;
-    aop = aop->op_sibling;
-    for (cvop = aop; cvop->op_sibling; cvop = cvop->op_sibling) ;
+    aop = OP_SIBLING(aop);
+    for (cvop = aop; OP_HAS_SIBLING(cvop); cvop = OP_SIBLING(cvop)) ;
     while (aop != cvop) {
        OP* o3 = aop;
 
@@ -9959,21 +10117,22 @@ Perl_ck_entersub_args_proto(pTHX_ OP *entersubop, GV *namegv, SV *protosv)
                    if (gvop && gvop->op_type == OP_NULL) {
                        gvop = ((UNOP*)gvop)->op_first;
                        if (gvop) {
-                           for (; gvop->op_sibling; gvop = gvop->op_sibling)
+                           for (; OP_HAS_SIBLING(gvop); gvop = OP_SIBLING(gvop))
                                ;
                            if (gvop &&
                                    (gvop->op_private & OPpENTERSUB_NOPAREN) &&
                                    (gvop = ((UNOP*)gvop)->op_first) &&
                                    gvop->op_type == OP_GV)
                            {
+                                OP * newop;
                                GV * const gv = cGVOPx_gv(gvop);
-                               OP * const sibling = aop->op_sibling;
                                SV * const n = newSVpvs("");
-                               op_free(aop);
                                gv_fullname4(n, gv, "", FALSE);
-                               aop = newSVOP(OP_CONST, 0, n);
-                               prev->op_sibling = aop;
-                               aop->op_sibling = sibling;
+                                /* replace the aop subtree with a const op */
+                               newop = newSVOP(OP_CONST, 0, n);
+                                op_sibling_splice(parent, prev, 1, newop);
+                               op_free(aop);
+                                aop = newop;
                            }
                        }
                    }
@@ -10073,14 +10232,8 @@ Perl_ck_entersub_args_proto(pTHX_ OP *entersubop, GV *namegv, SV *protosv)
                            bad_type_gv(arg, "hash", namegv, 0, o3);
                        break;
                    wrapref:
-                       {
-                           OP* const kid = aop;
-                           OP* const sib = kid->op_sibling;
-                           kid->op_sibling = 0;
-                           aop = newUNOP(OP_REFGEN, 0, kid);
-                           aop->op_sibling = sib;
-                           prev->op_sibling = aop;
-                       }
+                            aop = S_op_sibling_newUNOP(aTHX_ parent, prev,
+                                                OP_REFGEN, 0);
                        if (contextclass && e) {
                            proto = e + 1;
                            contextclass = 0;
@@ -10105,13 +10258,11 @@ Perl_ck_entersub_args_proto(pTHX_ OP *entersubop, GV *namegv, SV *protosv)
 
        op_lvalue(aop, OP_ENTERSUB);
        prev = aop;
-       aop = aop->op_sibling;
+       aop = OP_SIBLING(aop);
     }
     if (aop == cvop && *proto == '_') {
        /* generate an access to $_ */
-       aop = newDEFSVOP();
-       aop->op_sibling = prev->op_sibling;
-       prev->op_sibling = aop; /* instead of cvop */
+        op_sibling_splice(parent, prev, 0, newDEFSVOP());
     }
     if (!optional && proto_end > proto &&
        (*proto != '@' && *proto != '%' && *proto != ';' && *proto != '_'))
@@ -10167,10 +10318,10 @@ Perl_ck_entersub_args_core(pTHX_ OP *entersubop, GV *namegv, SV *protosv)
 
     if (!opnum) {
        OP *cvop;
-       if (!aop->op_sibling)
+       if (!OP_HAS_SIBLING(aop))
            aop = cUNOPx(aop)->op_first;
-       aop = aop->op_sibling;
-       for (cvop = aop; cvop->op_sibling; cvop = cvop->op_sibling) ;
+       aop = OP_SIBLING(aop);
+       for (cvop = aop; OP_SIBLING(cvop); cvop = OP_SIBLING(cvop)) ;
        if (aop != cvop)
            (void)too_many_arguments_pv(entersubop, GvNAME(namegv), 0);
        
@@ -10194,22 +10345,33 @@ Perl_ck_entersub_args_core(pTHX_ OP *entersubop, GV *namegv, SV *protosv)
        NOT_REACHED;
     }
     else {
-       OP *prev, *cvop;
+       OP *prev, *cvop, *first, *parent;
        U32 flags;
-       if (!aop->op_sibling)
+
+        parent = entersubop;
+       if (!OP_HAS_SIBLING(aop)) {
+            parent = aop;
            aop = cUNOPx(aop)->op_first;
+        }
        
-       prev = aop;
-       aop = aop->op_sibling;
-       prev->op_sibling = NULL;
+       first = prev = aop;
+       aop = OP_SIBLING(aop);
+        /* find last sibling */
        for (cvop = aop;
-            cvop->op_sibling;
-            prev=cvop, cvop = cvop->op_sibling)
+            OP_HAS_SIBLING(cvop);
+            prev = cvop, cvop = OP_SIBLING(cvop))
            ;
-       prev->op_sibling = NULL;
        flags = OPf_SPECIAL * !(cvop->op_private & OPpENTERSUB_NOPAREN);
+        /* excise cvop from end of sibling chain */
+        op_sibling_splice(parent, prev, 1, NULL);
        op_free(cvop);
        if (aop == cvop) aop = NULL;
+
+        /* detach remaining silbings from the first silbing, then
+         * dispose of original optree */
+
+        if (aop)
+            op_sibling_splice(parent, first, -1, NULL);
        op_free(entersubop);
 
        if (opnum == OP_ENTEREVAL
@@ -10272,6 +10434,7 @@ Perl_cv_get_call_checker(pTHX_ CV *cv, Perl_call_checker *ckfun_p, SV **ckobj_p)
 {
     MAGIC *callmg;
     PERL_ARGS_ASSERT_CV_GET_CALL_CHECKER;
+    PERL_UNUSED_CONTEXT;
     callmg = SvMAGICAL((SV*)cv) ? mg_find((SV*)cv, PERL_MAGIC_checkcall) : NULL;
     if (callmg) {
        *ckfun_p = DPTR2FPTR(Perl_call_checker, callmg->mg_ptr);
@@ -10348,10 +10511,10 @@ Perl_ck_subr(pTHX_ OP *o)
     PERL_ARGS_ASSERT_CK_SUBR;
 
     aop = cUNOPx(o)->op_first;
-    if (!aop->op_sibling)
+    if (!OP_HAS_SIBLING(aop))
        aop = cUNOPx(aop)->op_first;
-    aop = aop->op_sibling;
-    for (cvop = aop; cvop->op_sibling; cvop = cvop->op_sibling) ;
+    aop = OP_SIBLING(aop);
+    for (cvop = aop; OP_HAS_SIBLING(cvop); cvop = OP_SIBLING(cvop)) ;
     cv = rv2cv_op_cv(cvop, RV2CVOPCV_MARK_EARLY);
     namegv = cv ? (GV*)rv2cv_op_cv(cvop, RV2CVOPCV_RETURN_NAME_GV) : NULL;
 
@@ -10367,7 +10530,7 @@ Perl_ck_subr(pTHX_ OP *o)
        if (aop->op_type == OP_CONST)
            aop->op_private &= ~OPpCONST_STRICT;
        else if (aop->op_type == OP_LIST) {
-           OP * const sib = ((UNOP*)aop)->op_first->op_sibling;
+           OP * const sib = OP_SIBLING(((UNOP*)aop)->op_first);
            if (sib && sib->op_type == OP_CONST)
                sib->op_private &= ~OPpCONST_STRICT;
        }
@@ -10433,7 +10596,7 @@ Perl_ck_trunc(pTHX_ OP *o)
        SVOP *kid = (SVOP*)cUNOPo->op_first;
 
        if (kid->op_type == OP_NULL)
-           kid = (SVOP*)kid->op_sibling;
+           kid = (SVOP*)OP_SIBLING(kid);
        if (kid && kid->op_type == OP_CONST &&
            (kid->op_private & OPpCONST_BARE) &&
            !kid->op_folded)
@@ -10455,7 +10618,7 @@ Perl_ck_substr(pTHX_ OP *o)
        OP *kid = cLISTOPo->op_first;
 
        if (kid->op_type == OP_NULL)
-           kid = kid->op_sibling;
+           kid = OP_SIBLING(kid);
        if (kid)
            kid->op_flags |= OPf_MOD;
 
@@ -10470,7 +10633,7 @@ Perl_ck_tell(pTHX_ OP *o)
     o = ck_fun(o);
     if (o->op_flags & OPf_KIDS) {
      OP *kid = cLISTOPo->op_first;
-     if (kid->op_type == OP_NULL && kid->op_sibling) kid = kid->op_sibling;
+     if (kid->op_type == OP_NULL && OP_HAS_SIBLING(kid)) kid = OP_SIBLING(kid);
      if (kid->op_type == OP_RV2GV) kid->op_private |= OPpALLOW_FAKE;
     }
     return o;
@@ -10582,39 +10745,39 @@ S_inplace_aassign(pTHX_ OP *o) {
     assert(cUNOPo->op_first->op_type == OP_NULL);
     modop_pushmark = cUNOPx(cUNOPo->op_first)->op_first;
     assert(modop_pushmark->op_type == OP_PUSHMARK);
-    modop = modop_pushmark->op_sibling;
+    modop = OP_SIBLING(modop_pushmark);
 
     if (modop->op_type != OP_SORT && modop->op_type != OP_REVERSE)
        return;
 
     /* no other operation except sort/reverse */
-    if (modop->op_sibling)
+    if (OP_HAS_SIBLING(modop))
        return;
 
     assert(cUNOPx(modop)->op_first->op_type == OP_PUSHMARK);
-    if (!(oright = cUNOPx(modop)->op_first->op_sibling)) return;
+    if (!(oright = OP_SIBLING(cUNOPx(modop)->op_first))) return;
 
     if (modop->op_flags & OPf_STACKED) {
        /* skip sort subroutine/block */
        assert(oright->op_type == OP_NULL);
-       oright = oright->op_sibling;
+       oright = OP_SIBLING(oright);
     }
 
-    assert(cUNOPo->op_first->op_sibling->op_type == OP_NULL);
-    oleft_pushmark = cUNOPx(cUNOPo->op_first->op_sibling)->op_first;
+    assert(OP_SIBLING(cUNOPo->op_first)->op_type == OP_NULL);
+    oleft_pushmark = cUNOPx(OP_SIBLING(cUNOPo->op_first))->op_first;
     assert(oleft_pushmark->op_type == OP_PUSHMARK);
-    oleft = oleft_pushmark->op_sibling;
+    oleft = OP_SIBLING(oleft_pushmark);
 
     /* Check the lhs is an array */
     if (!oleft ||
        (oleft->op_type != OP_RV2AV && oleft->op_type != OP_PADAV)
-       || oleft->op_sibling
+       || OP_HAS_SIBLING(oleft)
        || (oleft->op_private & OPpLVAL_INTRO)
     )
        return;
 
     /* Only one thing on the rhs */
-    if (oright->op_sibling)
+    if (OP_HAS_SIBLING(oright))
        return;
 
     /* check the array is the same on both sides */
@@ -10750,7 +10913,7 @@ Perl_rpeep(pTHX_ OP *o)
             OP *sibling;
             OP *other_pushmark;
             if (OP_TYPE_IS(o->op_next, OP_PUSHMARK)
-                && (sibling = o->op_sibling)
+                && (sibling = OP_SIBLING(o))
                 && sibling->op_type == OP_LIST
                 /* This KIDS check is likely superfluous since OP_LIST
                  * would otherwise be an OP_STUB. */
@@ -10789,25 +10952,25 @@ Perl_rpeep(pTHX_ OP *o)
             */
            {
                OP *next = o->op_next;
-               OP *sibling = o->op_sibling;
+               OP *sibling = OP_SIBLING(o);
                if (   OP_TYPE_IS(next, OP_PUSHMARK)
                    && OP_TYPE_IS(sibling, OP_RETURN)
                    && OP_TYPE_IS(sibling->op_next, OP_LINESEQ)
                    && OP_TYPE_IS(sibling->op_next->op_next, OP_LEAVESUB)
                    && cUNOPx(sibling)->op_first == next
-                   && next->op_sibling && next->op_sibling->op_next
+                   && OP_HAS_SIBLING(next) && OP_SIBLING(next)->op_next
                    && next->op_next
                ) {
                    /* Look through the PUSHMARK's siblings for one that
                     * points to the RETURN */
-                   OP *top = next->op_sibling;
+                   OP *top = OP_SIBLING(next);
                    while (top && top->op_next) {
                        if (top->op_next == sibling) {
                            top->op_next = sibling->op_next;
                            o->op_next = next->op_next;
                            break;
                        }
-                       top = top->op_sibling;
+                       top = OP_SIBLING(top);
                    }
                }
            }
@@ -10842,35 +11005,44 @@ Perl_rpeep(pTHX_ OP *o)
                && (!CopLABEL((COP*)o)) /* Don't mess with labels */
                && (!CopLABEL((COP*)o->op_next->op_next)) /* ... */
            ) {
-               OP *first;
-               OP *last;
-               OP *newop;
-
-               first = o->op_next;
-               last = o->op_next->op_next->op_next;
-
-               newop = newLISTOP(OP_LIST, 0, first, last);
+               OP *pad1, *ns2, *pad2, *ns3, *newop, *newpm;
+
+               pad1 =    o->op_next;
+               ns2  = pad1->op_next;
+               pad2 =  ns2->op_next;
+               ns3  = pad2->op_next;
+
+                /* we assume here that the op_next chain is the same as
+                 * the op_silbing chain */
+                assert(OP_SIBLING(o)    == pad1);
+                assert(OP_SIBLING(pad1) == ns2);
+                assert(OP_SIBLING(ns2)  == pad2);
+                assert(OP_SIBLING(pad2) == ns3);
+
+                /* create new listop, with children consisting of:
+                 * a new pushmark, pad1, pad2. */
+               OP_SIBLING_set(pad2, NULL);
+               newop = newLISTOP(OP_LIST, 0, pad1, pad2);
                newop->op_flags |= OPf_PARENS;
                newop->op_flags = (newop->op_flags & ~OPf_WANT) | OPf_WANT_VOID;
+                newpm = cUNOPx(newop)->op_first; /* pushmark */
 
                /* Kill nextstate2 between padop1/padop2 */
-               op_free(first->op_next);
-
-               first->op_next = last;                /* padop2 */
-               first->op_sibling = last;             /* ... */
-               o->op_next = cUNOPx(newop)->op_first; /* pushmark */
-               o->op_next->op_next = first;          /* padop1 */
-               o->op_next->op_sibling = first;       /* ... */
-               newop->op_next = last->op_next;       /* nextstate3 */
-               newop->op_sibling = last->op_sibling;
-               last->op_next = newop;                /* listop */
-               last->op_sibling = NULL;
-               o->op_sibling = newop;                /* ... */
+               op_free(ns2);
+
+               o    ->op_next = newpm;
+               newpm->op_next = pad1;
+               pad1 ->op_next = pad2;
+               pad2 ->op_next = newop; /* listop */
+               newop->op_next = ns3;
+
+               OP_SIBLING_set(o, newop);
+               OP_SIBLING_set(newop, ns3);
 
                newop->op_flags = (newop->op_flags & ~OPf_WANT) | OPf_WANT_VOID;
 
                /* Ensure pushmark has this flag if padops do */
-               if (first->op_flags & OPf_MOD && last->op_flags & OPf_MOD) {
+               if (pad1->op_flags & OPf_MOD && pad2->op_flags & OPf_MOD) {
                    o->op_next->op_flags |= OPf_MOD;
                }
 
@@ -11020,7 +11192,7 @@ Perl_rpeep(pTHX_ OP *o)
                     && !(rv2av->op_flags & OPf_REF)
                     && !(rv2av->op_private & (OPpLVAL_INTRO|OPpMAYBE_LVSUB))
                     && ((rv2av->op_flags & OPf_WANT) == OPf_WANT_LIST)
-                    && o->op_sibling == rv2av /* these two for Deparse */
+                    && OP_SIBLING(o) == rv2av /* these two for Deparse */
                     && cUNOPx(rv2av)->op_first == p
                 ) {
                     q = rv2av->op_next;
@@ -11035,8 +11207,8 @@ Perl_rpeep(pTHX_ OP *o)
             if (!defav) {
                 /* To allow Deparse to pessimise this, it needs to be able
                  * to restore the pushmark's original op_next, which it
-                 * will assume to be the same as op_sibling. */
-                if (o->op_next != o->op_sibling)
+                 * will assume to be the same as OP_SIBLING. */
+                if (o->op_next != OP_SIBLING(o))
                     break;
                 p = o;
             }
@@ -11296,7 +11468,7 @@ Perl_rpeep(pTHX_ OP *o)
        case OP_OR:
        case OP_DOR:
             fop = cLOGOP->op_first;
-            sop = fop->op_sibling;
+            sop = OP_SIBLING(fop);
            while (cLOGOP->op_other->op_type == OP_NULL)
                cLOGOP->op_other = cLOGOP->op_other->op_next;
            while (o->op_next && (   o->op_type == o->op_next->op_type
@@ -11410,7 +11582,7 @@ Perl_rpeep(pTHX_ OP *o)
 
            if (o->op_flags & OPf_SPECIAL) {
                 /* first arg is a code block */
-               OP * const nullop = cLISTOP->op_first->op_sibling;
+               OP * const nullop = OP_SIBLING(cLISTOP->op_first);
                 OP * kid          = cUNOPx(nullop)->op_first;
 
                 assert(nullop->op_type == OP_NULL);
@@ -11441,7 +11613,7 @@ Perl_rpeep(pTHX_ OP *o)
                break;
 
            /* reverse sort ... can be optimised.  */
-           if (!cUNOPo->op_sibling) {
+           if (!OP_HAS_SIBLING(cUNOPo)) {
                /* Nothing follows us on the list. */
                OP * const reverse = o->op_next;
 
@@ -11449,7 +11621,7 @@ Perl_rpeep(pTHX_ OP *o)
                    (reverse->op_flags & OPf_WANT) == OPf_WANT_LIST) {
                    OP * const pushmark = cUNOPx(reverse)->op_first;
                    if (pushmark && (pushmark->op_type == OP_PUSHMARK)
-                       && (cUNOPx(pushmark)->op_sibling == o)) {
+                       && (OP_SIBLING(cUNOPx(pushmark)) == o)) {
                        /* reverse -> pushmark -> sort */
                        o->op_private |= OPpSORT_REVERSE;
                        op_null(reverse);
@@ -11504,7 +11676,7 @@ Perl_rpeep(pTHX_ OP *o)
                || expushmark->op_targ != OP_PUSHMARK)
                break;
 
-           exlist = (LISTOP *) expushmark->op_sibling;
+           exlist = (LISTOP *) OP_SIBLING(expushmark);
            if (!exlist || exlist->op_type != OP_NULL
                || exlist->op_targ != OP_LIST)
                break;
@@ -11517,7 +11689,7 @@ Perl_rpeep(pTHX_ OP *o)
            if (!theirmark || theirmark->op_type != OP_PUSHMARK)
                break;
 
-           if (theirmark->op_sibling != o) {
+           if (OP_SIBLING(theirmark) != o) {
                /* There's something between the mark and the reverse, eg
                   for (1, reverse (...))
                   so no go.  */
@@ -11532,8 +11704,8 @@ Perl_rpeep(pTHX_ OP *o)
            if (!ourlast || ourlast->op_next != o)
                break;
 
-           rv2av = ourmark->op_sibling;
-           if (rv2av && rv2av->op_type == OP_RV2AV && rv2av->op_sibling == 0
+           rv2av = OP_SIBLING(ourmark);
+           if (rv2av && rv2av->op_type == OP_RV2AV && !OP_HAS_SIBLING(rv2av)
                && rv2av->op_flags == (OPf_WANT_LIST | OPf_KIDS)
                && enter->op_flags == (OPf_WANT_LIST | OPf_KIDS)) {
                /* We're just reversing a single array.  */
@@ -11598,14 +11770,15 @@ Perl_rpeep(pTHX_ OP *o)
                     *        arg2
                     *        ...
                     */
-                   OP *left = right->op_sibling;
+                   OP *left = OP_SIBLING(right);
                    if (left->op_type == OP_SUBSTR
                         && (left->op_private & 7) < 4) {
                        op_null(o);
-                       cBINOP->op_first = left;
-                       right->op_sibling =
-                           cBINOPx(left)->op_first->op_sibling;
-                       cBINOPx(left)->op_first->op_sibling = right;
+                        /* cut out right */
+                        op_sibling_splice(o, NULL, 1, NULL);
+                        /* and insert it as second child of OP_SUBSTR */
+                        op_sibling_splice(left, cBINOPx(left)->op_first, 0,
+                                    right);
                        left->op_private |= OPpSUBSTR_REPL_FIRST;
                        left->op_flags =
                            (o->op_flags & ~OPf_WANT) | OPf_WANT_VOID;
@@ -11748,6 +11921,10 @@ Perl_custom_op_get_field(pTHX_ const OP *o, const xop_flags_enum field)
                }
            }
        }
+        /* Some gcc releases emit a warning for this function:
+         * op.c: In function 'Perl_custom_op_get_field':
+         * op.c:...: warning: 'any.xop_name' may be used uninitialized in this function [-Wmaybe-uninitialized]
+         * Whether this is true, is currently unknown. */
        return any;
     }
 }
@@ -12080,7 +12257,6 @@ Perl_wrap_op_checker(pTHX_ Optype opcode,
 static void
 const_sv_xsub(pTHX_ CV* cv)
 {
-    dVAR;
     dXSARGS;
     SV *const sv = MUTABLE_SV(XSANY.any_ptr);
     PERL_UNUSED_ARG(items);
@@ -12095,7 +12271,6 @@ const_sv_xsub(pTHX_ CV* cv)
 static void
 const_av_xsub(pTHX_ CV* cv)
 {
-    dVAR;
     dXSARGS;
     AV * const av = MUTABLE_AV(XSANY.any_ptr);
     SP -= items;