This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
op.c: Skip priv flags assert if ppaddr changes
[perl5.git] / op.c
diff --git a/op.c b/op.c
index fec74ca..268f2ee 100644 (file)
--- a/op.c
+++ b/op.c
@@ -535,7 +535,7 @@ S_bad_type_pv(pTHX_ I32 n, const char *t, const char *name, U32 flags, const OP
 STATIC void
 S_bad_type_gv(pTHX_ I32 n, const char *t, GV *gv, U32 flags, const OP *kid)
 {
-    SV * const namesv = cv_name((CV *)gv, NULL);
+    SV * const namesv = cv_name((CV *)gv, NULL, 0);
     PERL_ARGS_ASSERT_BAD_TYPE_GV;
  
     yyerror_pv(Perl_form(aTHX_ "Type of arg %d to %"SVf" must be %s (not %s)",
@@ -567,10 +567,6 @@ Perl_allocmy(pTHX_ const char *const name, const STRLEN len, const U32 flags)
        Perl_croak(aTHX_ "panic: allocmy illegal flag bits 0x%" UVxf,
                   (UV)flags);
 
-    /* Until we're using the length for real, cross check that we're being
-       told the truth.  */
-    assert(strlen(name) == len);
-
     /* complain about "my $<special_var>" etc etc */
     if (len &&
        !(is_our ||
@@ -578,7 +574,6 @@ Perl_allocmy(pTHX_ const char *const name, const STRLEN len, const U32 flags)
          ((flags & SVf_UTF8) && isIDFIRST_utf8((U8 *)name+1)) ||
          (name[1] == '_' && (*name == '$' || len > 2))))
     {
-       /* name[2] is true if strlen(name) > 2  */
        if (!(flags & SVf_UTF8 && UTF8_IS_START(name[1]))
         && (!isPRINT(name[1]) || strchr("\t\n\r\f", name[1]))) {
            yyerror(Perl_form(aTHX_ "Can't use global %c^%c%.*s in \"%s\"",
@@ -606,7 +601,9 @@ Perl_allocmy(pTHX_ const char *const name, const STRLEN len, const U32 flags)
                    PL_parser->in_my_stash,
                    (is_our
                        /* $_ is always in main::, even with our */
-                       ? (PL_curstash && !strEQ(name,"$_") ? PL_curstash : PL_defstash)
+                       ? (PL_curstash && !memEQs(name,len,"$_")
+                           ? PL_curstash
+                           : PL_defstash)
                        : NULL
                    )
     );
@@ -698,7 +695,9 @@ Perl_op_free(pTHX_ OP *o)
 
     /* an op should only ever acquire op_private flags that we know about.
      * If this fails, you may need to fix something in regen/op_private */
-    assert(!(o->op_private & ~PL_op_private_valid[type]));
+    if (o->op_ppaddr == PL_ppaddr[o->op_type]) {
+       assert(!(o->op_private & ~PL_op_private_valid[type]));
+    }
 
     if (o->op_private & OPpREFCOUNTED) {
        switch (type) {
@@ -807,8 +806,6 @@ Perl_op_clear(pTHX_ OP *o)
                SvREFCNT_inc_simple_void(gv);
 #ifdef USE_ITHREADS
            if (cPADOPo->op_padix > 0) {
-               /* No GvIN_PAD_off(cGVOPo_gv) here, because other references
-                * may still exist on the pad */
                pad_swipe(cPADOPo->op_padix, TRUE);
                cPADOPo->op_padix = 0;
            }
@@ -825,6 +822,15 @@ Perl_op_clear(pTHX_ OP *o)
        }
        break;
     case OP_METHOD_NAMED:
+        SvREFCNT_dec(cMETHOPx(o)->op_u.op_meth_sv);
+        cMETHOPx(o)->op_u.op_meth_sv = NULL;
+#ifdef USE_ITHREADS
+        if (o->op_targ) {
+            pad_swipe(o->op_targ, 1);
+            o->op_targ = 0;
+        }
+#endif
+        break;
     case OP_CONST:
     case OP_HINTSEVAL:
        SvREFCNT_dec(cSVOPo->op_sv);
@@ -875,8 +881,6 @@ Perl_op_clear(pTHX_ OP *o)
     case OP_PUSHRE:
 #ifdef USE_ITHREADS
         if (cPMOPo->op_pmreplrootu.op_pmtargetoff) {
-           /* No GvIN_PAD_off here, because other references may still
-            * exist on the pad */
            pad_swipe(cPMOPo->op_pmreplrootu.op_pmtargetoff, TRUE);
        }
 #else
@@ -1038,25 +1042,25 @@ Perl_op_refcnt_unlock(pTHX)
 =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
+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_sibling manipulation on the
-children. The last deleted node will be marked as as the last node by
+children.  The last deleted node will be marked as as the last node by
 updating the op_sibling or op_lastsib field as appropriate.
 
 Note that op_next is not manipulated, and nodes are not freed; that is the
-responsibility of the caller. It also won't create a new list op for an
+responsibility of the caller.  It also won't create a new 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
+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.
+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.
 
@@ -1160,7 +1164,7 @@ Perl_op_sibling_splice(OP *parent, OP *start, int del_count, OP* insert)
 /*
 =for apidoc op_parent
 
-returns the parent OP of o, if it has a parent. Returns NULL otherwise.
+returns the parent OP of o, if it has a parent.  Returns NULL otherwise.
 (Currently perl must be built with C<-DPERL_OP_PARENT> for this feature to
 work.
 
@@ -1693,6 +1697,8 @@ Perl_scalarvoid(pTHX_ OP *o)
     case OP_SPLIT:
        kid = cLISTOPo->op_first;
        if (kid && kid->op_type == OP_PUSHRE
+               && !kid->op_targ
+               && !(o->op_flags & OPf_STACKED)
 #ifdef USE_ITHREADS
                && !((PMOP*)kid)->op_pmreplrootu.op_pmtargetoff)
 #else
@@ -1734,6 +1740,7 @@ Perl_scalarvoid(pTHX_ OP *o)
            no_bareword_allowed(o);
        else {
            if (ckWARN(WARN_VOID)) {
+               NV nv;
                /* don't warn on optimised away booleans, eg 
                 * use constant Foo, 5; Foo || print; */
                if (cSVOPo->op_private & OPpCONST_SHORTCIRCUIT)
@@ -1741,7 +1748,7 @@ Perl_scalarvoid(pTHX_ OP *o)
                /* the constants 0 and 1 are permitted as they are
                   conventionally used as dummies in constructs like
                        1 while some_condition_with_side_effects;  */
-               else if (SvNIOK(sv) && (SvNV(sv) == 0.0 || SvNV(sv) == 1.0))
+               else if (SvNIOK(sv) && ((nv = SvNV(sv)) == 0.0 || nv == 1.0))
                    useless = NULL;
                else if (SvPOK(sv)) {
                     SV * const dsv = newSVpvs("");
@@ -1799,7 +1806,8 @@ Perl_scalarvoid(pTHX_ OP *o)
 
        refgen = (UNOP *)((BINOP *)o)->op_first;
 
-       if (!refgen || refgen->op_type != OP_REFGEN)
+       if (!refgen || (refgen->op_type != OP_REFGEN
+                       && refgen->op_type != OP_SREFGEN))
            break;
 
        exlist = (LISTOP *)refgen->op_first;
@@ -1807,7 +1815,8 @@ Perl_scalarvoid(pTHX_ OP *o)
            || exlist->op_targ != OP_LIST)
            break;
 
-       if (exlist->op_first->op_type != OP_PUSHMARK)
+       if (exlist->op_first->op_type != OP_PUSHMARK
+        && exlist->op_first != exlist->op_last)
            break;
 
        rv2cv = (UNOP*)exlist->op_last;
@@ -2039,6 +2048,27 @@ Perl_finalize_optree(pTHX_ OP* o)
     LEAVE;
 }
 
+#ifdef USE_ITHREADS
+/* Relocate sv to the pad for thread safety.
+ * Despite being a "constant", the SV is written to,
+ * for reference counts, sv_upgrade() etc. */
+PERL_STATIC_INLINE void
+S_op_relocate_sv(pTHX_ SV** svp, PADOFFSET* targp)
+{
+    PADOFFSET ix;
+    PERL_ARGS_ASSERT_OP_RELOCATE_SV;
+    if (!*svp) return;
+    ix = pad_alloc(OP_CONST, SVf_READONLY);
+    SvREFCNT_dec(PAD_SVl(ix));
+    PAD_SETSV(ix, *svp);
+    /* XXX I don't know how this isn't readonly already. */
+    if (!SvIsCOW(PAD_SVl(ix))) SvREADONLY_on(PAD_SVl(ix));
+    *svp = NULL;
+    *targp = ix;
+}
+#endif
+
+
 STATIC void
 S_finalize_op(pTHX_ OP* o)
 {
@@ -2091,21 +2121,16 @@ S_finalize_op(pTHX_ OP* o)
        /* FALLTHROUGH */
 #ifdef USE_ITHREADS
     case OP_HINTSEVAL:
+        op_relocate_sv(&cSVOPo->op_sv, &o->op_targ);
+#endif
+        break;
+
+#ifdef USE_ITHREADS
+    /* Relocate all the METHOP's SVs to the pad for thread safety. */
     case OP_METHOD_NAMED:
-       /* Relocate sv to the pad for thread safety.
-        * Despite being a "constant", the SV is written to,
-        * for reference counts, sv_upgrade() etc. */
-       if (cSVOPo->op_sv) {
-           const PADOFFSET ix = pad_alloc(OP_CONST, SVf_READONLY);
-           SvREFCNT_dec(PAD_SVl(ix));
-           PAD_SETSV(ix, cSVOPo->op_sv);
-           /* XXX I don't know how this isn't readonly already. */
-           if (!SvIsCOW(PAD_SVl(ix))) SvREADONLY_on(PAD_SVl(ix));
-           cSVOPo->op_sv = NULL;
-           o->op_targ = ix;
-       }
+        op_relocate_sv(&cMETHOPx(o)->op_u.op_meth_sv, &o->op_targ);
+        break;
 #endif
-       break;
 
     case OP_HELEM: {
        UNOP *rop;
@@ -2241,6 +2266,7 @@ S_finalize_op(pTHX_ OP* o)
               || family == OA_BASEOP_OR_UNOP
               || family == OA_FILESTATOP
               || family == OA_LOOPEXOP
+              || family == OA_METHOP
               /* I don't know why SASSIGN is tagged as OA_BASEOP - DAPM */
               || type == OP_SASSIGN
               || type == OP_CUSTOM
@@ -2313,6 +2339,130 @@ S_vivifies(const OPCODE type)
     return 0;
 }
 
+static void
+S_lvref(pTHX_ OP *o, I32 type)
+{
+    OP *kid;
+    switch (o->op_type) {
+    case OP_COND_EXPR:
+       for (kid = OP_SIBLING(cUNOPo->op_first); kid;
+            kid = OP_SIBLING(kid))
+           S_lvref(aTHX_ kid, type);
+       /* FALLTHROUGH */
+    case OP_PUSHMARK:
+       return;
+    case OP_RV2AV:
+       if (cUNOPo->op_first->op_type != OP_GV) goto badref;
+       o->op_flags |= OPf_STACKED;
+       if (o->op_flags & OPf_PARENS) {
+           if (o->op_private & OPpLVAL_INTRO) {
+                /* diag_listed_as: Can't modify %s in %s */
+                yyerror(Perl_form(aTHX_ "Can't modify reference to "
+                     "localized parenthesized array in list assignment"));
+               return;
+           }
+         slurpy:
+           o->op_type = OP_LVAVREF;
+           o->op_ppaddr = PL_ppaddr[OP_LVAVREF];
+           o->op_private &= OPpLVAL_INTRO|OPpPAD_STATE;
+           o->op_flags |= OPf_MOD|OPf_REF;
+           return;
+       }
+       o->op_private |= OPpLVREF_AV;
+       goto checkgv;
+    case OP_RV2CV:
+       kid = cUNOPo->op_first;
+       if (kid->op_type == OP_NULL)
+           kid = cUNOPx(kUNOP->op_first->op_sibling)
+               ->op_first;
+       o->op_private = OPpLVREF_CV;
+       if (kid->op_type == OP_GV)
+           o->op_flags |= OPf_STACKED;
+       else if (kid->op_type == OP_PADCV) {
+           o->op_targ = kid->op_targ;
+           kid->op_targ = 0;
+           op_free(cUNOPo->op_first);
+           cUNOPo->op_first = NULL;
+           o->op_flags &=~ OPf_KIDS;
+       }
+       else goto badref;
+       break;
+    case OP_RV2HV:
+       if (o->op_flags & OPf_PARENS) {
+         parenhash:
+           /* diag_listed_as: Can't modify %s in %s */
+           yyerror(Perl_form(aTHX_ "Can't modify reference to "
+                                "parenthesized hash in list assignment"));
+               return;
+       }
+       o->op_private |= OPpLVREF_HV;
+       /* FALLTHROUGH */
+    case OP_RV2SV:
+      checkgv:
+       if (cUNOPo->op_first->op_type != OP_GV) goto badref;
+       o->op_flags |= OPf_STACKED;
+       break;
+    case OP_PADHV:
+       if (o->op_flags & OPf_PARENS) goto parenhash;
+       o->op_private |= OPpLVREF_HV;
+       /* FALLTHROUGH */
+    case OP_PADSV:
+       PAD_COMPNAME_GEN_set(o->op_targ, PERL_INT_MAX);
+       break;
+    case OP_PADAV:
+       PAD_COMPNAME_GEN_set(o->op_targ, PERL_INT_MAX);
+       if (o->op_flags & OPf_PARENS) goto slurpy;
+       o->op_private |= OPpLVREF_AV;
+       break;
+    case OP_AELEM:
+    case OP_HELEM:
+       o->op_private |= OPpLVREF_ELEM;
+       o->op_flags   |= OPf_STACKED;
+       break;
+    case OP_ASLICE:
+    case OP_HSLICE:
+       o->op_type = OP_LVREFSLICE;
+       o->op_ppaddr = PL_ppaddr[OP_LVREFSLICE];
+       o->op_private &= OPpLVAL_INTRO|OPpLVREF_ELEM;
+       return;
+    case OP_NULL:
+       if (o->op_flags & OPf_SPECIAL)          /* do BLOCK */
+           goto badref;
+       else if (!(o->op_flags & OPf_KIDS))
+           return;
+       if (o->op_targ != OP_LIST) {
+           S_lvref(aTHX_ cBINOPo->op_first, type);
+           return;
+       }
+       /* FALLTHROUGH */
+    case OP_LIST:
+       for (kid = cLISTOPo->op_first; kid; kid = OP_SIBLING(kid)) {
+           assert((kid->op_flags & OPf_WANT) != OPf_WANT_VOID);
+           S_lvref(aTHX_ kid, type);
+       }
+       return;
+    case OP_STUB:
+       if (o->op_flags & OPf_PARENS)
+           return;
+       /* FALLTHROUGH */
+    default:
+      badref:
+       /* diag_listed_as: Can't modify %s in %s */
+       yyerror(Perl_form(aTHX_ "Can't modify reference to %s in %s",
+                    o->op_type == OP_NULL && o->op_flags & OPf_SPECIAL
+                     ? "do block"
+                     : OP_DESC(o),
+                    PL_op_desc[type]));
+       return;
+    }
+    o->op_type = OP_LVREF;
+    o->op_ppaddr = PL_ppaddr[OP_LVREF];
+    o->op_private &=
+       OPpLVAL_INTRO|OPpLVREF_ELEM|OPpLVREF_TYPE|OPpPAD_STATE;
+    if (type == OP_ENTERLOOP)
+       o->op_private |= OPpLVREF_ITER;
+}
+
 OP *
 Perl_op_lvalue_flags(pTHX_ OP *o, I32 type, U32 flags)
 {
@@ -2352,10 +2502,10 @@ Perl_op_lvalue_flags(pTHX_ OP *o, I32 type, U32 flags)
            break;
        }
        else {                          /* lvalue subroutine call */
-           o->op_private |= OPpLVAL_INTRO
-                          |(OPpENTERSUB_INARGS * (type == OP_LEAVESUBLV));
+           o->op_private |= OPpLVAL_INTRO;
            PL_modcount = RETURN_UNLIMITED_NUMBER;
-           if (type == OP_GREPSTART || type == OP_ENTERSUB || type == OP_REFGEN) {
+           if (type == OP_GREPSTART || type == OP_ENTERSUB
+            || type == OP_REFGEN    || type == OP_LEAVESUBLV) {
                /* Potential lvalue context: */
                o->op_private |= OPpENTERSUB_INARGS;
                break;
@@ -2594,11 +2744,6 @@ Perl_op_lvalue_flags(pTHX_ OP *o, I32 type, U32 flags)
                op_lvalue(kid, type);
        break;
 
-    case OP_RETURN:
-       if (type != OP_LEAVESUBLV)
-           goto nomod;
-       break; /* op_lvalue()ing was handled by ck_return() */
-
     case OP_COREARGS:
        return o;
 
@@ -2611,6 +2756,35 @@ Perl_op_lvalue_flags(pTHX_ OP *o, I32 type, U32 flags)
         || !S_vivifies(OP_SIBLING(cLOGOPo->op_first)->op_type))
            op_lvalue(OP_SIBLING(cLOGOPo->op_first), type);
        goto nomod;
+
+    case OP_SREFGEN:
+       if (type != OP_AASSIGN && type != OP_SASSIGN
+        && type != OP_ENTERLOOP)
+           goto nomod;
+       /* Don’t bother applying lvalue context to the ex-list.  */
+       kid = cUNOPx(cUNOPo->op_first)->op_first;
+       assert (!OP_HAS_SIBLING(kid));
+       goto kid_2lvref;
+    case OP_REFGEN:
+       if (type != OP_AASSIGN) goto nomod;
+       kid = cUNOPo->op_first;
+      kid_2lvref:
+       {
+           const U8 ec = PL_parser ? PL_parser->error_count : 0;
+           S_lvref(aTHX_ kid, type);
+           if (!PL_parser || PL_parser->error_count == ec) {
+               if (!FEATURE_LVREF_IS_ENABLED)
+                   Perl_croak(aTHX_
+                            "Experimental lvalue references not enabled");
+               Perl_ck_warner_d(aTHX_
+                                packWARN(WARN_EXPERIMENTAL__LVALUE_REFS),
+                             "Lvalue references are experimental");
+           }
+       }
+       if (o->op_type == OP_REFGEN)
+           op_null(cUNOPx(cUNOPo->op_first)->op_first); /* pushmark */
+       op_null(o);
+       return o;
     }
 
     /* [20011101.069] File test operators interpret OPf_REF to mean that
@@ -2923,7 +3097,7 @@ S_apply_attrs_my(pTHX_ HV *stash, OP *target, OP *attrs, OP **imopsp)
     imop = convert(OP_ENTERSUB, OPf_STACKED|OPf_SPECIAL|OPf_WANT_VOID,
                   op_append_elem(OP_LIST,
                               op_prepend_elem(OP_LIST, pack, list(arg)),
-                              newSVOP(OP_METHOD_NAMED, 0, meth)));
+                              newMETHOP_named(OP_METHOD_NAMED, 0, meth)));
 
     /* Combine the ops. */
     *imopsp = op_append_elem(OP_LIST, *imopsp, imop);
@@ -3700,6 +3874,7 @@ S_fold_constants(pTHX_ OP *o)
     OP * VOL curop;
     OP *newop;
     VOL I32 type = o->op_type;
+    bool folded;
     SV * VOL sv = NULL;
     int ret = 0;
     I32 oldscope;
@@ -3846,6 +4021,7 @@ S_fold_constants(pTHX_ OP *o)
     if (ret)
        goto nope;
 
+    folded = cBOOL(o->op_folded);
     op_free(o);
     assert(sv);
     if (type == OP_STRINGIFY) SvPADTMP_off(sv);
@@ -3858,7 +4034,11 @@ S_fold_constants(pTHX_ OP *o)
     else
     {
        newop = newSVOP(OP_CONST, 0, MUTABLE_SV(sv));
-       if (type != OP_STRINGIFY) newop->op_folded = 1;
+       /* OP_STRINGIFY and constant folding are used to implement qq.
+          Here the constant folding is an implementation detail that we
+          want to hide.  If the stringify op is itself already marked
+          folded, however, then it is actually a folded join.  */
+       if (type != OP_STRINGIFY || folded) newop->op_folded = 1;
     }
     return newop;
 
@@ -4278,6 +4458,77 @@ Perl_newUNOP(pTHX_ I32 type, I32 flags, OP *first)
 }
 
 /*
+=for apidoc Am|OP *|newMETHOP|I32 type|I32 flags|OP *first
+
+Constructs, checks, and returns an op of method type with a method name
+evaluated at runtime. I<type> is the opcode. I<flags> gives the eight
+bits of C<op_flags>, except that C<OPf_KIDS> will be set automatically,
+and, shifted up eight bits, the eight bits of C<op_private>, except that
+the bit with value 1 is automatically set. I<dynamic_meth> supplies an
+op which evaluates method name; it is consumed by this function and
+become part of the constructed op tree.
+Supported optypes: OP_METHOD.
+
+=cut
+*/
+
+static OP*
+S_newMETHOP_internal(pTHX_ I32 type, I32 flags, OP* dynamic_meth, SV* const_meth) {
+    dVAR;
+    METHOP *methop;
+
+    assert((PL_opargs[type] & OA_CLASS_MASK) == OA_METHOP);
+
+    NewOp(1101, methop, 1, METHOP);
+    if (dynamic_meth) {
+        if (PL_opargs[type] & OA_MARK) dynamic_meth = force_list(dynamic_meth, 1);
+        methop->op_flags = (U8)(flags | OPf_KIDS);
+        methop->op_u.op_first = dynamic_meth;
+        methop->op_private = (U8)(1 | (flags >> 8));
+    }
+    else {
+        assert(const_meth);
+        methop->op_flags = (U8)(flags & ~OPf_KIDS);
+        methop->op_u.op_meth_sv = const_meth;
+        methop->op_private = (U8)(0 | (flags >> 8));
+        methop->op_next = (OP*)methop;
+    }
+
+    methop->op_type = (OPCODE)type;
+    methop->op_ppaddr = PL_ppaddr[type];
+    methop = (METHOP*) CHECKOP(type, methop);
+
+    if (methop->op_next) return (OP*)methop;
+
+    return fold_constants(op_integerize(op_std_init((OP *) methop)));
+}
+
+OP *
+Perl_newMETHOP (pTHX_ I32 type, I32 flags, OP* dynamic_meth) {
+    PERL_ARGS_ASSERT_NEWMETHOP;
+    return newMETHOP_internal(type, flags, dynamic_meth, NULL);
+}
+
+/*
+=for apidoc Am|OP *|newMETHOP_named|I32 type|I32 flags|SV *const_meth
+
+Constructs, checks, and returns an op of method type with a constant
+method name. I<type> is the opcode. I<flags> gives the eight bits of
+C<op_flags>, and, shifted up eight bits, the eight bits of
+C<op_private>. I<const_meth> supplies a constant method name;
+it must be a shared COW string.
+Supported optypes: OP_METHOD_NAMED.
+
+=cut
+*/
+
+OP *
+Perl_newMETHOP_named (pTHX_ I32 type, I32 flags, SV* const_meth) {
+    PERL_ARGS_ASSERT_NEWMETHOP_NAMED;
+    return newMETHOP_internal(type, flags, NULL, const_meth);
+}
+
+/*
 =for apidoc Am|OP *|newBINOP|I32 type|I32 flags|OP *first|OP *last
 
 Constructs, checks, and returns an op of any binary type.  I<type>
@@ -4324,16 +4575,16 @@ Perl_newBINOP(pTHX_ I32 type, I32 flags, OP *first, OP *last)
         last->op_sibling = (OP*)binop;
 #endif
 
-    binop = (BINOP*)CHECKOP(type, binop);
-    if (binop->op_next || binop->op_type != (OPCODE)type)
-       return (OP*)binop;
-
     binop->op_last = OP_SIBLING(binop->op_first);
 #ifdef PERL_OP_PARENT
     if (binop->op_last)
         binop->op_last->op_sibling = (OP*)binop;
 #endif
 
+    binop = (BINOP*)CHECKOP(type, binop);
+    if (binop->op_next || binop->op_type != (OPCODE)type)
+       return (OP*)binop;
+
     return fold_constants(op_integerize(op_std_init((OP *)binop)));
 }
 
@@ -4828,7 +5079,15 @@ Perl_pmruntime(pTHX_ OP *o, OP *expr, bool isreg, I32 floor)
        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 && OP_HAS_SIBLING(o));
+               assert(!o->op_next);
+               if (UNLIKELY(!OP_HAS_SIBLING(o))) {
+                   assert(PL_parser && PL_parser->error_count);
+                   /* This can happen with qr/ (?{(^{})/.  Just fake up
+                      the op we were expecting to see, to avoid crashing
+                      elsewhere.  */
+                   op_sibling_splice(expr, o, 0,
+                                     newSVOP(OP_CONST, 0, &PL_sv_no));
+               }
                o->op_next = OP_SIBLING(o);
            }
            else if (o->op_type != OP_CONST && o->op_type != OP_PUSHMARK)
@@ -5186,7 +5445,7 @@ Perl_newPADOP(pTHX_ I32 type, I32 flags, SV *sv)
     padop->op_type = (OPCODE)type;
     padop->op_ppaddr = PL_ppaddr[type];
     padop->op_padix =
-       pad_alloc(type, IS_PADGV(sv) ? SVf_READONLY : SVs_PADTMP);
+       pad_alloc(type, isGV(sv) ? SVf_READONLY : SVs_PADTMP);
     SvREFCNT_dec(PAD_SVl(padop->op_padix));
     PAD_SETSV(padop->op_padix, sv);
     assert(sv);
@@ -5219,7 +5478,6 @@ Perl_newGVOP(pTHX_ I32 type, I32 flags, GV *gv)
     PERL_ARGS_ASSERT_NEWGVOP;
 
 #ifdef USE_ITHREADS
-    GvIN_PAD_on(gv);
     return newPADOP(type, flags, SvREFCNT_inc_simple_NN(gv));
 #else
     return newSVOP(type, flags, SvREFCNT_inc_simple_NN(gv));
@@ -5332,7 +5590,7 @@ Perl_utilize(pTHX_ int aver, I32 floor, OP *version, OP *idop, OP *arg)
            veop = convert(OP_ENTERSUB, OPf_STACKED|OPf_SPECIAL,
                            op_append_elem(OP_LIST,
                                        op_prepend_elem(OP_LIST, pack, list(version)),
-                                       newSVOP(OP_METHOD_NAMED, 0, meth)));
+                                       newMETHOP_named(OP_METHOD_NAMED, 0, meth)));
        }
     }
 
@@ -5359,7 +5617,7 @@ Perl_utilize(pTHX_ int aver, I32 floor, OP *version, OP *idop, OP *arg)
        imop = convert(OP_ENTERSUB, OPf_STACKED|OPf_SPECIAL,
                       op_append_elem(OP_LIST,
                                   op_prepend_elem(OP_LIST, pack, list(arg)),
-                                  newSVOP(OP_METHOD_NAMED, 0, meth)));
+                                  newMETHOP_named(OP_METHOD_NAMED, 0, meth)));
     }
 
     /* Fake up the BEGIN {}, which does its thing immediately. */
@@ -5568,11 +5826,15 @@ Perl_newSLICEOP(pTHX_ I32 flags, OP *subscript, OP *listval)
            list(force_list(listval,   1)) );
 }
 
+#define ASSIGN_LIST   1
+#define ASSIGN_REF    2
+
 STATIC I32
-S_is_list_assignment(pTHX_ const OP *o)
+S_assignment_type(pTHX_ const OP *o)
 {
     unsigned type;
     U8 flags;
+    U8 ret;
 
     if (!o)
        return TRUE;
@@ -5584,40 +5846,72 @@ S_is_list_assignment(pTHX_ const OP *o)
     type = o->op_type;
     if (type == OP_COND_EXPR) {
         OP * const sib = OP_SIBLING(cLOGOPo->op_first);
-        const I32 t = is_list_assignment(sib);
-        const I32 f = is_list_assignment(OP_SIBLING(sib));
+        const I32 t = assignment_type(sib);
+        const I32 f = assignment_type(OP_SIBLING(sib));
 
-       if (t && f)
-           return TRUE;
-       if (t || f)
+       if (t == ASSIGN_LIST && f == ASSIGN_LIST)
+           return ASSIGN_LIST;
+       if ((t == ASSIGN_LIST) ^ (f == ASSIGN_LIST))
            yyerror("Assignment to both a list and a scalar");
        return FALSE;
     }
 
+    if (type == OP_SREFGEN)
+    {
+       OP * const kid = cUNOPx(cUNOPo->op_first)->op_first;
+       type = kid->op_type;
+       flags |= kid->op_flags;
+       if (!(flags & OPf_PARENS)
+         && (kid->op_type == OP_RV2AV || kid->op_type == OP_PADAV ||
+             kid->op_type == OP_RV2HV || kid->op_type == OP_PADHV ))
+           return ASSIGN_REF;
+       ret = ASSIGN_REF;
+    }
+    else ret = 0;
+
     if (type == OP_LIST &&
        (flags & OPf_WANT) == OPf_WANT_SCALAR &&
        o->op_private & OPpLVAL_INTRO)
-       return FALSE;
+       return ret;
 
     if (type == OP_LIST || flags & OPf_PARENS ||
        type == OP_RV2AV || type == OP_RV2HV ||
        type == OP_ASLICE || type == OP_HSLICE ||
-        type == OP_KVASLICE || type == OP_KVHSLICE)
+        type == OP_KVASLICE || type == OP_KVHSLICE || type == OP_REFGEN)
        return TRUE;
 
     if (type == OP_PADAV || type == OP_PADHV)
        return TRUE;
 
     if (type == OP_RV2SV)
-       return FALSE;
+       return ret;
 
-    return FALSE;
+    return ret;
 }
 
 /*
   Helper function for newASSIGNOP to detection commonality between the
-  lhs and the rhs.  Marks all variables with PL_generation.  If it
+  lhs and the rhs.  (It is actually called very indirectly.  newASSIGNOP
+  flags the op and the peephole optimizer calls this helper function
+  if the flag is set.)  Marks all variables with PL_generation.  If it
   returns TRUE the assignment must be able to handle common variables.
+
+  PL_generation sorcery:
+  An assignment like ($a,$b) = ($c,$d) is easier than
+  ($a,$b) = ($c,$a), since there is no need for temporary vars.
+  To detect whether there are common vars, the global var
+  PL_generation is incremented for each assign op we compile.
+  Then, while compiling the assign op, we run through all the
+  variables on both sides of the assignment, setting a spare slot
+  in each of them to PL_generation.  If any of them already have
+  that value, we know we've got commonality.  Also, if the
+  generation number is already set to PERL_INT_MAX, then
+  the variable is involved in aliasing, so we also have
+  potential commonality in that case.  We could use a
+  single bit marker, but then we'd have to make 2 passes, first
+  to clear the flag, then to test and set it.  And that
+  wouldn't help with aliasing, either.  To find somewhere
+  to store these values, evil chicanery is done with SvUVX().
 */
 PERL_STATIC_INLINE bool
 S_aassign_common_vars(pTHX_ OP* o)
@@ -5625,7 +5919,8 @@ S_aassign_common_vars(pTHX_ OP* o)
     OP *curop;
     for (curop = cUNOPo->op_first; curop; curop = OP_SIBLING(curop)) {
        if (PL_opargs[curop->op_type] & OA_DANGEROUS) {
-           if (curop->op_type == OP_GV) {
+           if (curop->op_type == OP_GV || curop->op_type == OP_GVSV
+            || curop->op_type == OP_AELEMFAST) {
                GV *gv = cGVOPx_gv(curop);
                if (gv == PL_defgv
                    || (int)GvASSIGN_GENERATION(gv) == PL_generation)
@@ -5637,8 +5932,10 @@ S_aassign_common_vars(pTHX_ OP* o)
                curop->op_type == OP_PADHV ||
                curop->op_type == OP_PADANY)
                {
+                 padcheck:
                    if (PAD_COMPNAME_GEN(curop->op_targ)
-                       == (STRLEN)PL_generation)
+                       == (STRLEN)PL_generation
+                    || PAD_COMPNAME_GEN(curop->op_targ) == PERL_INT_MAX)
                        return TRUE;
                    PAD_COMPNAME_GEN_set(curop->op_targ, PL_generation);
 
@@ -5667,7 +5964,12 @@ S_aassign_common_vars(pTHX_ OP* o)
                        return TRUE;
                    GvASSIGN_GENERATION_set(gv, PL_generation);
                }
+               else if (curop->op_targ)
+                   goto padcheck;
            }
+           else if (curop->op_type == OP_PADRANGE)
+               /* Ignore padrange; checking its siblings is sufficient. */
+               continue;
            else
                return TRUE;
        }
@@ -5680,6 +5982,33 @@ S_aassign_common_vars(pTHX_ OP* o)
     return FALSE;
 }
 
+/* This variant only handles lexical aliases.  It is called when
+   newASSIGNOP decides that we don’t have any common vars, as lexical ali-
+   ases trump that decision.  */
+PERL_STATIC_INLINE bool
+S_aassign_common_vars_aliases_only(pTHX_ OP *o)
+{
+    OP *curop;
+    for (curop = cUNOPo->op_first; curop; curop = OP_SIBLING(curop)) {
+       if ((curop->op_type == OP_PADSV ||
+            curop->op_type == OP_PADAV ||
+            curop->op_type == OP_PADHV ||
+            curop->op_type == OP_PADANY)
+          && PAD_COMPNAME_GEN(curop->op_targ) == PERL_INT_MAX)
+           return TRUE;
+
+       if (curop->op_type == OP_PUSHRE && curop->op_targ
+        && PAD_COMPNAME_GEN(curop->op_targ) == PERL_INT_MAX)
+           return TRUE;
+
+       if (curop->op_flags & OPf_KIDS) {
+           if (S_aassign_common_vars_aliases_only(aTHX_ curop))
+               return TRUE;
+       }
+    }
+    return FALSE;
+}
+
 /*
 =for apidoc Am|OP *|newASSIGNOP|I32 flags|OP *left|I32 optype|OP *right
 
@@ -5707,6 +6036,7 @@ OP *
 Perl_newASSIGNOP(pTHX_ I32 flags, OP *left, I32 optype, OP *right)
 {
     OP *o;
+    I32 assign_type;
 
     if (optype) {
        if (optype == OP_ANDASSIGN || optype == OP_ORASSIGN || optype == OP_DORASSIGN) {
@@ -5720,7 +6050,7 @@ Perl_newASSIGNOP(pTHX_ I32 flags, OP *left, I32 optype, OP *right)
        }
     }
 
-    if (is_list_assignment(left)) {
+    if ((assign_type = assignment_type(left)) == ASSIGN_LIST) {
        static const char no_list_state[] = "Initialization of state variables"
            " in list context currently forbidden";
        OP *curop;
@@ -5793,67 +6123,78 @@ Perl_newASSIGNOP(pTHX_ I32 flags, OP *left, I32 optype, OP *right)
            }
        }
 
-       /* PL_generation sorcery:
-        * an assignment like ($a,$b) = ($c,$d) is easier than
-        * ($a,$b) = ($c,$a), since there is no need for temporary vars.
-        * To detect whether there are common vars, the global var
-        * PL_generation is incremented for each assign op we compile.
-        * Then, while compiling the assign op, we run through all the
-        * variables on both sides of the assignment, setting a spare slot
-        * in each of them to PL_generation. If any of them already have
-        * that value, we know we've got commonality.  We could use a
-        * single bit marker, but then we'd have to make 2 passes, first
-        * to clear the flag, then to test and set it.  To find somewhere
-        * to store these values, evil chicanery is done with SvUVX().
-        */
-
        if (maybe_common_vars) {
-           PL_generation++;
-           if (aassign_common_vars(o))
+               /* The peephole optimizer will do the full check and pos-
+                  sibly turn this off.  */
                o->op_private |= OPpASSIGN_COMMON;
-           LINKLIST(o);
        }
 
-       if (right && right->op_type == OP_SPLIT) {
+       if (right && right->op_type == OP_SPLIT
+        && !(right->op_flags & OPf_STACKED)) {
            OP* tmpop = ((LISTOP*)right)->op_first;
            if (tmpop && (tmpop->op_type == OP_PUSHRE)) {
                PMOP * const pm = (PMOP*)tmpop;
-               if (left->op_type == OP_RV2AV &&
-                   !(left->op_private & OPpLVAL_INTRO) &&
-                   !(o->op_private & OPpASSIGN_COMMON) )
-               {
-                   tmpop = ((UNOP*)left)->op_first;
-                   if (tmpop->op_type == OP_GV
+               if (
 #ifdef USE_ITHREADS
-                       && !pm->op_pmreplrootu.op_pmtargetoff
+                   !pm->op_pmreplrootu.op_pmtargetoff
 #else
-                       && !pm->op_pmreplrootu.op_pmtargetgv
+                   !pm->op_pmreplrootu.op_pmtargetgv
 #endif
+                && !pm->op_targ
+               ) {
+                   if (!(left->op_private & OPpLVAL_INTRO) &&
+                       ( (left->op_type == OP_RV2AV &&
+                         (tmpop=((UNOP*)left)->op_first)->op_type==OP_GV)
+                       || left->op_type == OP_PADAV )
                        ) {
+                       if (tmpop != (OP *)pm) {
 #ifdef USE_ITHREADS
-                       pm->op_pmreplrootu.op_pmtargetoff
+                         pm->op_pmreplrootu.op_pmtargetoff
                            = cPADOPx(tmpop)->op_padix;
-                       cPADOPx(tmpop)->op_padix = 0;   /* steal it */
+                         cPADOPx(tmpop)->op_padix = 0; /* steal it */
 #else
-                       pm->op_pmreplrootu.op_pmtargetgv
+                         pm->op_pmreplrootu.op_pmtargetgv
                            = MUTABLE_GV(cSVOPx(tmpop)->op_sv);
-                       cSVOPx(tmpop)->op_sv = NULL;    /* steal it */
+                         cSVOPx(tmpop)->op_sv = NULL;  /* steal it */
 #endif
+                         right->op_private |=
+                           left->op_private & OPpOUR_INTRO;
+                       }
+                       else {
+                           pm->op_targ = left->op_targ;
+                           left->op_targ = 0; /* filch it */
+                       }
+                     detach_split:
                        tmpop = cUNOPo->op_first;       /* to list (nulled) */
                        tmpop = ((UNOP*)tmpop)->op_first; /* to pushmark */
                         /* 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;
                                /* "I don't know and I don't care." */
                        return right;
                    }
-               }
-               else {
-                   if (PL_modcount < RETURN_UNLIMITED_NUMBER &&
-                     ((LISTOP*)right)->op_last->op_type == OP_CONST)
+                   else if (left->op_type == OP_RV2AV
+                         || left->op_type == OP_PADAV)
+                   {
+                       /* Detach the array.  */
+#ifdef DEBUGGING
+                       OP * const ary =
+#endif
+                       op_sibling_splice(cBINOPo->op_last,
+                                         cUNOPx(cBINOPo->op_last)
+                                               ->op_first, 1, NULL);
+                       assert(ary == left);
+                       /* Attach it to the split.  */
+                       op_sibling_splice(right, cLISTOPx(right)->op_last,
+                                         0, left);
+                       right->op_flags |= OPf_STACKED;
+                       /* Detach split and expunge aassign as above.  */
+                       goto detach_split;
+                   }
+                   else if (PL_modcount < RETURN_UNLIMITED_NUMBER &&
+                           ((LISTOP*)right)->op_last->op_type == OP_CONST)
                    {
                        SV ** const svp =
                            &((SVOP*)((LISTOP*)right)->op_last)->op_sv;
@@ -5877,6 +6218,8 @@ Perl_newASSIGNOP(pTHX_ I32 flags, OP *left, I32 optype, OP *right)
        }
        return o;
     }
+    if (assign_type == ASSIGN_REF)
+       return newBINOP(OP_REFASSIGN, flags, scalar(right), left);
     if (!right)
        right = newOP(OP_UNDEF, 0);
     if (right->op_type == OP_READLINE) {
@@ -6367,10 +6710,11 @@ Perl_newRANGE(pTHX_ I32 flags, OP *left, OP *right)
     left->op_next = flip;
     right->op_next = flop;
 
-    range->op_targ = pad_alloc(OP_RANGE, SVs_PADMY);
+    range->op_targ = pad_add_name_pvn("$", 1, padadd_NO_DUP_CHECK, 0, 0);
     sv_upgrade(PAD_SV(range->op_targ), SVt_PVNV);
-    flip->op_targ = pad_alloc(OP_RANGE, SVs_PADMY);
+    flip->op_targ = pad_add_name_pvn("$", 1, padadd_NO_DUP_CHECK, 0, 0);;
     sv_upgrade(PAD_SV(flip->op_targ), SVt_PVNV);
+    SvPADTMP_on(PAD_SV(flip->op_targ));
 
     flip->op_private =  left->op_type == OP_CONST ? OPpFLIP_LINENUM : 0;
     flop->op_private = right->op_type == OP_CONST ? OPpFLIP_LINENUM : 0;
@@ -6669,7 +7013,10 @@ Perl_newFOROP(pTHX_ I32 flags, OP *sv, OP *expr, OP *block, OP *cont)
             sv->op_targ = 0;
             op_free(sv);
            sv = NULL;
+           PAD_COMPNAME_GEN_set(padoff, PERL_INT_MAX);
        }
+       else if (sv->op_type == OP_NULL && sv->op_targ == OP_SREFGEN)
+           NOOP;
        else
            Perl_croak(aTHX_ "Can't use %s for loop variable", PL_op_desc[sv->op_type]);
        if (padoff) {
@@ -7417,7 +7764,7 @@ Perl_newMYSUB(pTHX_ I32 floor, OP *o, OP *proto, OP *attrs, OP *block)
     }
     if (const_sv) {
        SvREFCNT_inc_simple_void_NN(const_sv);
-       SvFLAGS(const_sv) = (SvFLAGS(const_sv) & ~SVs_PADMY) | SVs_PADTMP;
+       SvFLAGS(const_sv) |= SVs_PADTMP;
        if (cv) {
            assert(!CvROOT(cv) && !CvCONST(cv));
            cv_forget_slab(cv);
@@ -7609,7 +7956,6 @@ Perl_newMYSUB(pTHX_ I32 floor, OP *o, OP *proto, OP *attrs, OP *block)
        else *spot = cv_clone(clonee);
        SvREFCNT_dec_NN(clonee);
        cv = *spot;
-       SvPADMY_on(cv);
     }
     if (CvDEPTH(outcv) && !reusable && PadnameIsSTATE(name)) {
        PADOFFSET depth = CvDEPTH(outcv);
@@ -7658,8 +8004,8 @@ Perl_newATTRSUB_x(pTHX_ I32 floor, OP *o, OP *proto, OP *attrs,
     bool name_is_utf8 = o && !o_is_gv && SvUTF8(cSVOPo->op_sv);
 #ifdef PERL_DEBUG_READONLY_OPS
     OPSLAB *slab = NULL;
-#endif
     bool special = FALSE;
+#endif
 
     if (o_is_gv) {
        gv = (GV*)o;
@@ -7839,7 +8185,7 @@ Perl_newATTRSUB_x(pTHX_ I32 floor, OP *o, OP *proto, OP *attrs,
     }
     if (const_sv) {
        SvREFCNT_inc_simple_void_NN(const_sv);
-       SvFLAGS(const_sv) = (SvFLAGS(const_sv) & ~SVs_PADMY) | SVs_PADTMP;
+       SvFLAGS(const_sv) |= SVs_PADTMP;
        if (cv) {
            assert(!CvROOT(cv) && !CvCONST(cv));
            cv_forget_slab(cv);
@@ -7889,6 +8235,7 @@ Perl_newATTRSUB_x(pTHX_ I32 floor, OP *o, OP *proto, OP *attrs,
                assert(CvGV(cv) == gv);
            }
            else {
+               dVAR;
                U32 hash;
                PERL_HASH(hash, name, namlen);
                CvNAME_HEK_set(cv,
@@ -7953,6 +8300,7 @@ Perl_newATTRSUB_x(pTHX_ I32 floor, OP *o, OP *proto, OP *attrs,
     if (!CvHASGV(cv)) {
        if (isGV(gv)) CvGV_set(cv, gv);
        else {
+            dVAR;
            U32 hash;
            PERL_HASH(hash, name, namlen);
            CvNAME_HEK_set(cv, share_hek(name,
@@ -8027,7 +8375,7 @@ Perl_newATTRSUB_x(pTHX_ I32 floor, OP *o, OP *proto, OP *attrs,
 
     if (block && has_name) {
        if (PERLDB_SUBLINE && PL_curstash != PL_debstash) {
-           SV * const tmpstr = cv_name(cv,NULL);
+           SV * const tmpstr = cv_name(cv,NULL,0);
            GV * const db_postponed = gv_fetchpvs("DB::postponed",
                                                  GV_ADDMULTI, SVt_PVHV);
            HV *hv;
@@ -8054,7 +8402,10 @@ Perl_newATTRSUB_x(pTHX_ I32 floor, OP *o, OP *proto, OP *attrs,
             if (PL_parser && PL_parser->error_count)
                 clear_special_blocks(name, gv, cv);
             else
-                special = process_special_blocks(floor, name, gv, cv);
+#ifdef PERL_DEBUG_READONLY_OPS
+                special =
+#endif
+                    process_special_blocks(floor, name, gv, cv);
         }
     }
 
@@ -8767,9 +9118,14 @@ Perl_ck_spair(pTHX_ OP *o)
        newop = OP_SIBLING(kidkid);
        if (newop) {
            const OPCODE type = newop->op_type;
-           if (OP_HAS_SIBLING(newop) || !(PL_opargs[type] & OA_RETSCALAR) ||
-                   type == OP_PADAV || type == OP_PADHV ||
-                   type == OP_RV2AV || type == OP_RV2HV)
+           if (OP_HAS_SIBLING(newop))
+               return o;
+           if (o->op_type == OP_REFGEN && !(newop->op_flags & OPf_PARENS)
+               && (type == OP_RV2AV || type == OP_PADAV
+                || type == OP_RV2HV || type == OP_PADHV
+                || type == OP_RV2CV))
+               NOOP; /* OK (allow srefgen for \@a and \%h) */
+           else if (!(PL_opargs[type] & OA_RETSCALAR))
                return o;
        }
         /* excise first sibling */
@@ -9026,7 +9382,6 @@ Perl_ck_rvconst(pTHX_ OP *o)
            assert (sizeof(PADOP) <= sizeof(SVOP));
            kPADOP->op_padix = pad_alloc(OP_GV, SVf_READONLY);
            SvREFCNT_dec(PAD_SVl(kPADOP->op_padix));
-           if (isGV(gv)) GvIN_PAD_on(gv);
            PAD_SETSV(kPADOP->op_padix, MUTABLE_SV(SvREFCNT_inc_simple_NN(gv)));
 #else
            kid->op_sv = SvREFCNT_inc_simple_NN(gv);
@@ -9520,7 +9875,7 @@ Perl_ck_readline(pTHX_ OP *o)
     }
     else {
        OP * const newop
-           = newUNOP(OP_READLINE, 0, newGVOP(OP_GV, 0, PL_argvgv));
+           = newUNOP(OP_READLINE, o->op_flags | OPf_SPECIAL, newGVOP(OP_GV, 0, PL_argvgv));
        op_free(o);
        return newop;
     }
@@ -9660,23 +10015,18 @@ Perl_ck_sassign(pTHX_ OP *o)
            OP *const first = newOP(OP_NULL, 0);
            OP *const nullop = newCONDOP(0, first, o, other);
            OP *const condop = first->op_next;
-           /* hijacking PADSTALE for uninitialized state variables */
-           SvPADSTALE_on(PAD_SVl(target));
 
            condop->op_type = OP_ONCE;
            condop->op_ppaddr = PL_ppaddr[OP_ONCE];
-           condop->op_targ = target;
            other->op_targ = target;
 
-           /* Because we change the type of the op here, we will skip the
-              assignment binop->op_last = OP_SIBLING(binop->op_first); at the
-              end of Perl_newBINOP(). So need to do it here. */
-           cBINOPo->op_last = OP_SIBLING(cBINOPo->op_first);
-            cBINOPo->op_first->op_lastsib = 0;
-            cBINOPo->op_last ->op_lastsib = 1;
-#ifdef PERL_OP_PARENT
-            cBINOPo->op_last->op_sibling = o;
-#endif
+           /* Store the initializedness of state vars in a separate
+              pad entry.  */
+           condop->op_targ =
+             pad_add_name_pvn("$",1,padadd_NO_DUP_CHECK|padadd_STATE,0,0);
+           /* hijacking PADSTALE for uninitialized state variables */
+           SvPADSTALE_on(PAD_SVl(condop->op_targ));
+
            return nullop;
        }
     }
@@ -9703,25 +10053,26 @@ Perl_ck_match(pTHX_ OP *o)
 OP *
 Perl_ck_method(pTHX_ OP *o)
 {
+    SV* sv;
+    const char* method;
     OP * const kid = cUNOPo->op_first;
 
     PERL_ARGS_ASSERT_CK_METHOD;
-
-    if (kid->op_type == OP_CONST) {
-       SV* sv = kSVOP->op_sv;
-       const char * const method = SvPVX_const(sv);
-       if (!(strchr(method, ':') || strchr(method, '\''))) {
-           OP *cmop;
-           if (!SvIsCOW_shared_hash(sv)) {
-               sv = newSVpvn_share(method, SvUTF8(sv) ? -(I32)SvCUR(sv) : (I32)SvCUR(sv), 0);
-           }
-           else {
-               kSVOP->op_sv = NULL;
-           }
-           cmop = newSVOP(OP_METHOD_NAMED, 0, sv);
-           op_free(o);
-           return cmop;
-       }
+    if (kid->op_type != OP_CONST) return o;
+
+    sv = kSVOP->op_sv;
+    method = SvPVX_const(sv);
+    if (!(strchr(method, ':') || strchr(method, '\''))) {
+        OP *cmop;
+        if (!SvIsCOW_shared_hash(sv)) {
+            sv = newSVpvn_share(method, SvUTF8(sv) ? -(I32)SvCUR(sv) : (I32)SvCUR(sv), 0);
+        }
+        else {
+            kSVOP->op_sv = NULL;
+        }
+        cmop = newMETHOP_named(OP_METHOD_NAMED, 0, sv);
+        op_free(o);
+        return cmop;
     }
     return o;
 }
@@ -9764,6 +10115,82 @@ Perl_ck_open(pTHX_ OP *o)
 }
 
 OP *
+Perl_ck_refassign(pTHX_ OP *o)
+{
+    OP * const right = cLISTOPo->op_first;
+    OP * const left = OP_SIBLING(right);
+    OP * const varop = cUNOPx(cUNOPx(left)->op_first)->op_first;
+    bool stacked = 0;
+
+    PERL_ARGS_ASSERT_CK_REFASSIGN;
+    assert (left);
+    assert (left->op_type == OP_SREFGEN);
+
+    switch (varop->op_type) {
+    case OP_PADAV:
+       o->op_private = OPpLVREF_AV;
+       goto settarg;
+    case OP_PADHV:
+       o->op_private = OPpLVREF_HV;
+    case OP_PADSV:
+      settarg:
+       o->op_targ = varop->op_targ;
+       varop->op_targ = 0;
+       PAD_COMPNAME_GEN_set(o->op_targ, PERL_INT_MAX);
+       break;
+    case OP_RV2AV:
+       o->op_private = OPpLVREF_AV;
+       goto checkgv;
+    case OP_RV2HV:
+       o->op_private = OPpLVREF_HV;
+    case OP_RV2SV:
+      checkgv:
+       if (cUNOPx(varop)->op_first->op_type != OP_GV) goto bad;
+       goto null_and_stack;
+    case OP_RV2CV: {
+       OP * const kid =
+           cUNOPx(cUNOPx(cUNOPx(varop)->op_first)->op_first->op_sibling)
+               ->op_first;
+       o->op_private = OPpLVREF_CV;
+       if (kid->op_type == OP_GV)      goto null_and_stack;
+       if (kid->op_type != OP_PADCV)   goto bad;
+       o->op_targ = kid->op_targ;
+       kid->op_targ = 0;
+       break;
+    }
+    case OP_AELEM:
+    case OP_HELEM:
+       o->op_private = OPpLVREF_ELEM;
+      null_and_stack:
+       op_null(varop);
+       op_null(left);
+       stacked = TRUE;
+       break;
+    default:
+      bad:
+       /* diag_listed_as: Can't modify %s in %s */
+       yyerror(Perl_form(aTHX_ "Can't modify reference to %s in scalar "
+                               "assignment",
+                                OP_DESC(varop)));
+       return o;
+    }
+    if (!FEATURE_LVREF_IS_ENABLED)
+       Perl_croak(aTHX_
+                 "Experimental lvalue references not enabled");
+    Perl_ck_warner_d(aTHX_
+                    packWARN(WARN_EXPERIMENTAL__LVALUE_REFS),
+                   "Lvalue references are experimental");
+    o->op_private |= varop->op_private & (OPpLVAL_INTRO|OPpPAD_STATE);
+    if (stacked) o->op_flags |= OPf_STACKED;
+    else {
+       o->op_flags &=~ OPf_STACKED;
+       op_sibling_splice(o, right, 1, NULL);
+       op_free(left);
+    }
+    return o;
+}
+
+OP *
 Perl_ck_repeat(pTHX_ OP *o)
 {
     PERL_ARGS_ASSERT_CK_REPEAT;
@@ -9774,6 +10201,7 @@ Perl_ck_repeat(pTHX_ OP *o)
         kids = op_sibling_splice(o, NULL, -1, NULL); /* detach all kids */
         kids = force_list(kids, 1); /* promote them to a list */
         op_sibling_splice(o, NULL, 0, kids); /* and add back */
+        if (cBINOPo->op_last == kids) cBINOPo->op_last = NULL;
     }
     else
        scalar(o);
@@ -10181,9 +10609,23 @@ Perl_ck_split(pTHX_ OP *o)
 }
 
 OP *
+Perl_ck_stringify(pTHX_ OP *o)
+{
+    OP * const kid = OP_SIBLING(cUNOPo->op_first);
+    PERL_ARGS_ASSERT_CK_STRINGIFY;
+    if (kid->op_type == OP_JOIN) {
+       assert(!OP_HAS_SIBLING(kid));
+       op_sibling_splice(o, cUNOPo->op_first, -1, NULL);
+       op_free(o);
+       return kid;
+    }
+    return ck_fun(o);
+}
+       
+OP *
 Perl_ck_join(pTHX_ OP *o)
 {
-    const OP * const kid = OP_SIBLING(cLISTOPo->op_first);
+    OP * const kid = OP_SIBLING(cLISTOPo->op_first);
 
     PERL_ARGS_ASSERT_CK_JOIN;
 
@@ -10199,6 +10641,23 @@ Perl_ck_join(pTHX_ OP *o)
                        SVfARG(msg), SVfARG(msg));
        }
     }
+    if (kid->op_type == OP_CONST  /* an innocent, unsuspicious separator */
+     || (kid->op_type == OP_PADSV && !(kid->op_private & OPpLVAL_INTRO))
+     || (kid->op_type==OP_RV2SV && kUNOP->op_first->op_type == OP_GV
+       && !(kid->op_private & (OPpLVAL_INTRO|OPpOUR_INTRO))))
+    {
+       const OP * const bairn = OP_SIBLING(kid); /* the list */
+       if (bairn && !OP_HAS_SIBLING(bairn) /* single-item list */
+        && PL_opargs[bairn->op_type] & OA_RETSCALAR)
+       {
+           OP * const ret = convert(OP_STRINGIFY, 0,
+                                    op_sibling_splice(o, kid, 1, NULL));
+           op_free(o);
+           ret->op_folded = 1;
+           return ret;
+       }
+    }
+
     return ck_fun(o);
 }
 
@@ -10415,7 +10874,7 @@ Perl_ck_entersub_args_proto(pTHX_ OP *entersubop, GV *namegv, SV *protosv)
 
        if (proto >= proto_end)
        {
-           SV * const namesv = cv_name((CV *)namegv, NULL);
+           SV * const namesv = cv_name((CV *)namegv, NULL, 0);
            yyerror_pv(Perl_form(aTHX_ "Too many arguments for %"SVf,
                                        SVfARG(namesv)), SvUTF8(namesv));
            return entersubop;
@@ -10444,7 +10903,8 @@ Perl_ck_entersub_args_proto(pTHX_ OP *entersubop, GV *namegv, SV *protosv)
            case '&':
                proto++;
                arg++;
-               if (o3->op_type != OP_REFGEN && o3->op_type != OP_UNDEF)
+               if (o3->op_type != OP_REFGEN && o3->op_type != OP_SREFGEN
+                && o3->op_type != OP_UNDEF)
                    bad_type_gv(arg,
                            arg == 1 ? "block or sub {}" : "sub {}",
                            namegv, 0, o3);
@@ -10570,7 +11030,7 @@ Perl_ck_entersub_args_proto(pTHX_ OP *entersubop, GV *namegv, SV *protosv)
            default:
            oops: {
                Perl_croak(aTHX_ "Malformed prototype for %"SVf": %"SVf,
-                                 SVfARG(cv_name((CV *)namegv, NULL)),
+                                 SVfARG(cv_name((CV *)namegv, NULL, 0)),
                                  SVfARG(protosv));
             }
        }
@@ -10586,7 +11046,7 @@ Perl_ck_entersub_args_proto(pTHX_ OP *entersubop, GV *namegv, SV *protosv)
     if (!optional && proto_end > proto &&
        (*proto != '@' && *proto != '%' && *proto != ';' && *proto != '_'))
     {
-       SV * const namesv = cv_name((CV *)namegv, NULL);
+       SV * const namesv = cv_name((CV *)namegv, NULL, 0);
        yyerror_pv(Perl_form(aTHX_ "Not enough arguments for %"SVf,
                                    SVfARG(namesv)), SvUTF8(namesv));
     }
@@ -11957,7 +12417,9 @@ Perl_rpeep(pTHX_ OP *o)
                  * altering the basic op_first/op_sibling layout. */
                 kid = kLISTOP->op_first;
                 assert(
-                      (kid->op_type == OP_NULL && kid->op_targ == OP_NEXTSTATE)
+                      (kid->op_type == OP_NULL
+                      && (  kid->op_targ == OP_NEXTSTATE
+                         || kid->op_targ == OP_DBSTATE  ))
                     || kid->op_type == OP_STUB
                     || kid->op_type == OP_ENTER);
                 nullop->op_next = kLISTOP->op_next;
@@ -12147,6 +12609,21 @@ Perl_rpeep(pTHX_ OP *o)
            }
            break;
 
+       case OP_AASSIGN:
+           /* We do the common-vars check here, rather than in newASSIGNOP
+              (as formerly), so that all lexical vars that get aliased are
+              marked as such before we do the check.  */
+           if (o->op_private & OPpASSIGN_COMMON) {
+                /* See the comment before S_aassign_common_vars concerning
+                   PL_generation sorcery.  */
+               PL_generation++;
+               if (!aassign_common_vars(o))
+                   o->op_private &=~ OPpASSIGN_COMMON;
+           }
+           else if (S_aassign_common_vars_aliases_only(aTHX_ o))
+               o->op_private |= OPpASSIGN_COMMON;
+           break;
+
        case OP_CUSTOM: {
            Perl_cpeep_t cpeep = 
                XopENTRYCUSTOM(o, xop_peep);