This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Document variants of ‘Can’t modify’ individually
[perl5.git] / op.c
diff --git a/op.c b/op.c
index be9a341..f26f0d3 100644 (file)
--- a/op.c
+++ b/op.c
@@ -496,17 +496,6 @@ Perl_op_refcnt_dec(pTHX_ OP *o)
        o->op_ppaddr = PL_ppaddr[type];         \
     } STMT_END
 
-STATIC SV*
-S_gv_ename(pTHX_ GV *gv)
-{
-    SV* const tmpsv = sv_newmortal();
-
-    PERL_ARGS_ASSERT_GV_ENAME;
-
-    gv_efullname3(tmpsv, gv, NULL);
-    return tmpsv;
-}
-
 STATIC OP *
 S_no_fh_allowed(pTHX_ OP *o)
 {
@@ -518,15 +507,6 @@ S_no_fh_allowed(pTHX_ OP *o)
 }
 
 STATIC OP *
-S_too_few_arguments_sv(pTHX_ OP *o, SV *namesv, U32 flags)
-{
-    PERL_ARGS_ASSERT_TOO_FEW_ARGUMENTS_SV;
-    yyerror_pv(Perl_form(aTHX_ "Not enough arguments for %"SVf, SVfARG(namesv)),
-                                    SvUTF8(namesv) | flags);
-    return o;
-}
-
-STATIC OP *
 S_too_few_arguments_pv(pTHX_ OP *o, const char* name, U32 flags)
 {
     PERL_ARGS_ASSERT_TOO_FEW_ARGUMENTS_PV;
@@ -543,16 +523,6 @@ S_too_many_arguments_pv(pTHX_ OP *o, const char *name, U32 flags)
     return o;
 }
 
-STATIC OP *
-S_too_many_arguments_sv(pTHX_ OP *o, SV *namesv, U32 flags)
-{
-    PERL_ARGS_ASSERT_TOO_MANY_ARGUMENTS_SV;
-
-    yyerror_pv(Perl_form(aTHX_ "Too many arguments for %"SVf, SVfARG(namesv)),
-                SvUTF8(namesv) | flags);
-    return o;
-}
-
 STATIC void
 S_bad_type_pv(pTHX_ I32 n, const char *t, const char *name, U32 flags, const OP *kid)
 {
@@ -565,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 = gv_ename(gv);
+    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)",
@@ -597,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 ||
@@ -608,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\"",
@@ -636,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
                    )
     );
@@ -711,9 +678,7 @@ 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
@@ -728,7 +693,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) {
@@ -837,8 +804,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;
            }
@@ -855,6 +820,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);
@@ -905,8 +879,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
@@ -1068,25 +1040,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.
 
@@ -1190,7 +1162,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.
 
@@ -1723,6 +1695,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
@@ -1764,6 +1738,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)
@@ -1771,7 +1746,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("");
@@ -1829,7 +1804,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;
@@ -1837,7 +1813,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;
@@ -2069,6 +2046,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)
 {
@@ -2121,21 +2119,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;
@@ -2271,6 +2264,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
@@ -2343,6 +2337,129 @@ S_vivifies(const OPCODE type)
     return 0;
 }
 
+static void
+S_lvref(pTHX_ OP *o, I32 type)
+{
+    dVAR;
+    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) {
+                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:
+           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 reference to %s in %s assignment */
+       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)
 {
@@ -2382,10 +2499,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;
@@ -2393,6 +2510,7 @@ Perl_op_lvalue_flags(pTHX_ OP *o, I32 type, U32 flags)
            else {                      /* Compile-time error message: */
                OP *kid = cUNOPo->op_first;
                CV *cv;
+               GV *gv;
 
                if (kid->op_type != OP_PUSHMARK) {
                    if (kid->op_type != OP_NULL || kid->op_targ != OP_LIST)
@@ -2420,7 +2538,12 @@ Perl_op_lvalue_flags(pTHX_ OP *o, I32 type, U32 flags)
                    break;
                }
 
-               cv = GvCV(kGVOP_gv);
+               gv = kGVOP_gv;
+               cv = isGV(gv)
+                   ? GvCV(gv)
+                   : SvROK(gv) && SvTYPE(SvRV(gv)) == SVt_PVCV
+                       ? MUTABLE_CV(SvRV(gv))
+                       : NULL;
                if (!cv)
                    break;
                if (CvLVALUE(cv))
@@ -2618,11 +2741,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;
 
@@ -2635,6 +2753,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_REFALIASING_IS_ENABLED)
+                   Perl_croak(aTHX_
+                      "Experimental aliasing via reference not enabled");
+               Perl_ck_warner_d(aTHX_
+                                packWARN(WARN_EXPERIMENTAL__REFALIASING),
+                               "Aliasing via reference is 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
@@ -2947,7 +3094,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);
@@ -3724,6 +3871,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;
@@ -3870,6 +4018,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);
@@ -3882,7 +4031,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;
 
@@ -4302,6 +4455,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>
@@ -4348,16 +4572,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)));
 }
 
@@ -4852,7 +5076,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)
@@ -5210,7 +5442,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);
@@ -5243,7 +5475,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));
@@ -5356,7 +5587,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)));
        }
     }
 
@@ -5383,7 +5614,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. */
@@ -5592,11 +5823,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;
@@ -5608,40 +5843,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)
@@ -5649,7 +5916,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)
@@ -5659,10 +5927,13 @@ S_aassign_common_vars(pTHX_ OP* o)
            else if (curop->op_type == OP_PADSV ||
                curop->op_type == OP_PADAV ||
                curop->op_type == OP_PADHV ||
+               curop->op_type == OP_AELEMFAST_LEX ||
                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);
 
@@ -5691,7 +5962,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;
        }
@@ -5704,6 +5980,34 @@ 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_AELEMFAST_LEX ||
+            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
 
@@ -5731,6 +6035,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) {
@@ -5744,7 +6049,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;
@@ -5817,67 +6122,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
+           PMOP * const pm = (PMOP*)tmpop;
+           assert (tmpop && (tmpop->op_type == OP_PUSHRE));
+           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;
@@ -5896,11 +6212,12 @@ 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) {
@@ -6391,10 +6708,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;
@@ -6693,7 +7011,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) {
@@ -7058,12 +7379,19 @@ Perl_newWHENOP(pTHX_ OP *cond, OP *block)
     return newGIVWHENOP(cond_op, block, OP_ENTERWHEN, OP_LEAVEWHEN, 0);
 }
 
+/* must not conflict with SVf_UTF8 */
+#define CV_CKPROTO_CURSTASH    0x1
+
 void
 Perl_cv_ckproto_len_flags(pTHX_ const CV *cv, const GV *gv, const char *p,
                    const STRLEN len, const U32 flags)
 {
     SV *name = NULL, *msg;
-    const char * cvp = SvROK(cv) ? "" : CvPROTO(cv);
+    const char * cvp = SvROK(cv)
+                       ? SvTYPE(SvRV_const(cv)) == SVt_PVCV
+                          ? (cv = (const CV *)SvRV_const(cv), CvPROTO(cv))
+                          : ""
+                       : CvPROTO(cv);
     STRLEN clen = CvPROTOLEN(cv), plen = len;
 
     PERL_ARGS_ASSERT_CV_CKPROTO_LEN_FLAGS;
@@ -7100,6 +7428,16 @@ Perl_cv_ckproto_len_flags(pTHX_ const CV *cv, const GV *gv, const char *p,
            gv_efullname3(name = sv_newmortal(), gv, NULL);
        else if (SvPOK(gv) && *SvPVX((SV *)gv) == '&')
            name = newSVpvn_flags(SvPVX((SV *)gv)+1, SvCUR(gv)-1, SvUTF8(gv)|SVs_TEMP);
+       else if (flags & CV_CKPROTO_CURSTASH || SvROK(gv)) {
+           name = sv_2mortal(newSVhek(HvNAME_HEK(PL_curstash)));
+           sv_catpvs(name, "::");
+           if (SvROK(gv)) {
+               assert (SvTYPE(SvRV_const(gv)) == SVt_PVCV);
+               assert (CvNAMED(SvRV_const(gv)));
+               sv_cathek(name, CvNAME_HEK(MUTABLE_CV(SvRV_const(gv))));
+           }
+           else sv_catsv(name, (SV *)gv);
+       }
        else name = (SV *)gv;
     }
     sv_setpvs(msg, "Prototype mismatch:");
@@ -7424,7 +7762,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);
@@ -7616,7 +7954,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);
@@ -7652,7 +7989,7 @@ Perl_newATTRSUB_x(pTHX_ I32 floor, OP *o, OP *proto, OP *attrs,
     /* If the subroutine has no body, no attributes, and no builtin attributes
        then it's just a sub declaration, and we may be able to get away with
        storing with a placeholder scalar in the symbol table, rather than a
-       full GV and CV.  If anything is present then it will take a full CV to
+       full CV.  If anything is present then it will take a full CV to
        store it.  */
     const I32 gv_fetch_flags
        = ec ? GV_NOADD_NOINIT :
@@ -7665,6 +8002,7 @@ 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;
+    bool special = FALSE;
 #endif
 
     if (o_is_gv) {
@@ -7672,7 +8010,20 @@ Perl_newATTRSUB_x(pTHX_ I32 floor, OP *o, OP *proto, OP *attrs,
        o = NULL;
        has_name = TRUE;
     } else if (name) {
-       gv = gv_fetchsv(cSVOPo->op_sv, gv_fetch_flags, SVt_PVCV);
+       /* Try to optimise and avoid creating a GV.  Instead, the CV’s name
+          hek and CvSTASH pointer together can imply the GV.  If the name
+          contains a package name, then GvSTASH(CvGV(cv)) may differ from
+          CvSTASH, so forego the optimisation if we find any.
+          Also, we may be called from load_module at run time, so
+          PL_curstash (which sets CvSTASH) may not point to the stash the
+          sub is stored in.  */
+       const I32 flags =
+          ec ? GV_NOADD_NOINIT
+             :   PL_curstash != CopSTASH(PL_curcop)
+              || memchr(name, ':', namlen) || memchr(name, '\'', namlen)
+                   ? gv_fetch_flags
+                   : GV_ADDMULTI | GV_NOINIT;
+       gv = gv_fetchsv(cSVOPo->op_sv, flags, SVt_PVCV);
        has_name = TRUE;
     } else if (PERLDB_NAMEANON && CopLINE(PL_curcop)) {
        SV * const sv = sv_newmortal();
@@ -7689,7 +8040,8 @@ Perl_newATTRSUB_x(pTHX_ I32 floor, OP *o, OP *proto, OP *attrs,
        has_name = FALSE;
     }
     if (!ec)
-        move_proto_attr(&proto, &attrs, gv);
+       move_proto_attr(&proto, &attrs,
+                       isGV(gv) ? gv : (GV *)cSVOPo->op_sv);
 
     if (proto) {
        assert(proto->op_type == OP_CONST);
@@ -7728,8 +8080,18 @@ Perl_newATTRSUB_x(pTHX_ I32 floor, OP *o, OP *proto, OP *attrs,
        goto done;
     }
 
-    if (SvTYPE(gv) != SVt_PVGV) {      /* Maybe prototype now, and had at
-                                          maximum a prototype before. */
+    if (!block && SvTYPE(gv) != SVt_PVGV) {
+      /* If we are not defining a new sub and the existing one is not a
+         full GV + CV... */
+      if (attrs || (CvFLAGS(PL_compcv) & CVf_BUILTIN_ATTRS)) {
+       /* We are applying attributes to an existing sub, so we need it
+          upgraded if it is a constant.  */
+       if (SvROK(gv) && SvTYPE(SvRV(gv)) != SVt_PVCV)
+           gv_init_pvn(gv, PL_curstash, name, namlen,
+                       SVf_UTF8 * name_is_utf8);
+      }
+      else {                   /* Maybe prototype now, and had at maximum
+                                  a prototype or const/sub ref before.  */
        if (SvTYPE(gv) > SVt_NULL) {
            cv_ckproto_len_flags((const CV *)gv,
                                 o ? (const GV *)cSVOPo->op_sv : NULL, ps,
@@ -7747,9 +8109,17 @@ Perl_newATTRSUB_x(pTHX_ I32 floor, OP *o, OP *proto, OP *attrs,
        SvREFCNT_dec(PL_compcv);
        cv = PL_compcv = NULL;
        goto done;
+      }
     }
 
-    cv = (!name || GvCVGEN(gv)) ? NULL : GvCV(gv);
+    cv = (!name || (isGV(gv) && GvCVGEN(gv)))
+       ? NULL
+       : isGV(gv)
+           ? GvCV(gv)
+           : SvROK(gv) && SvTYPE(SvRV(gv)) == SVt_PVCV
+               ? (CV *)SvRV(gv)
+               : NULL;
+
 
     if (!block || !ps || *ps || attrs
        || (CvFLAGS(PL_compcv) & CVf_BUILTIN_ATTRS)
@@ -7758,6 +8128,38 @@ Perl_newATTRSUB_x(pTHX_ I32 floor, OP *o, OP *proto, OP *attrs,
     else
        const_sv = op_const_sv(block, NULL);
 
+    if (SvPOK(gv) || (SvROK(gv) && SvTYPE(SvRV(gv)) != SVt_PVCV)) {
+       assert (block);
+       cv_ckproto_len_flags((const CV *)gv,
+                            o ? (const GV *)cSVOPo->op_sv : NULL, ps,
+                            ps_len, ps_utf8|CV_CKPROTO_CURSTASH);
+       if (SvROK(gv)) {
+           /* All the other code for sub redefinition warnings expects the
+              clobbered sub to be a CV.  Instead of making all those code
+              paths more complex, just inline the RV version here.  */
+           const line_t oldline = CopLINE(PL_curcop);
+           assert(IN_PERL_COMPILETIME);
+           if (PL_parser && PL_parser->copline != NOLINE)
+               /* This ensures that warnings are reported at the first
+                  line of a redefinition, not the last.  */
+               CopLINE_set(PL_curcop, PL_parser->copline);
+           /* protect against fatal warnings leaking compcv */
+           SAVEFREESV(PL_compcv);
+
+           if (ckWARN(WARN_REDEFINE)
+            || (  ckWARN_d(WARN_REDEFINE)
+               && (  !const_sv || SvRV(gv) == const_sv
+                  || sv_cmp(SvRV(gv), const_sv)  )))
+               Perl_warner(aTHX_ packWARN(WARN_REDEFINE),
+                         "Constant subroutine %"SVf" redefined",
+                         SVfARG(cSVOPo->op_sv));
+
+           SvREFCNT_inc_simple_void_NN(PL_compcv);
+           CopLINE_set(PL_curcop, oldline);
+           SvREFCNT_dec(SvRV(gv));
+       }
+    }
+
     if (cv) {
         const bool exists = CvROOT(cv) || CvXSUB(cv);
 
@@ -7768,7 +8170,7 @@ Perl_newATTRSUB_x(pTHX_ I32 floor, OP *o, OP *proto, OP *attrs,
         if (exists || SvPOK(cv))
             cv_ckproto_len_flags(cv, gv, ps, ps_len, ps_utf8);
        /* already defined (or promised)? */
-       if (exists || GvASSUMECV(gv)) {
+       if (exists || (isGV(gv) && GvASSUMECV(gv))) {
            if (S_already_defined(aTHX_ cv, block, o, NULL, &const_sv))
                cv = NULL;
            else {
@@ -7781,7 +8183,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);
@@ -7792,11 +8194,22 @@ Perl_newATTRSUB_x(pTHX_ I32 floor, OP *o, OP *proto, OP *attrs,
            CvISXSUB_on(cv);
        }
        else {
-           if (name) GvCV_set(gv, NULL);
-           cv = newCONSTSUB_flags(
-               NULL, name, namlen, name_is_utf8 ? SVf_UTF8 : 0,
-               const_sv
-           );
+           if (isGV(gv)) {
+               if (name) GvCV_set(gv, NULL);
+               cv = newCONSTSUB_flags(
+                   NULL, name, namlen, name_is_utf8 ? SVf_UTF8 : 0,
+                   const_sv
+               );
+           }
+           else {
+               if (!SvROK(gv)) {
+                   SV_CHECK_THINKFIRST_COW_DROP((SV *)gv);
+                   prepare_SV_for_RV((SV *)gv);
+                   SvOK_off((SV *)gv);
+                   SvROK_on(gv);
+               }
+               SvRV_set(gv, const_sv);
+           }
        }
        op_free(block);
        SvREFCNT_dec(PL_compcv);
@@ -7814,12 +8227,26 @@ Perl_newATTRSUB_x(pTHX_ I32 floor, OP *o, OP *proto, OP *attrs,
                CvFLAGS(cv) & (CVf_SLABBED|CVf_WEAKOUTSIDE);
            OP * const cvstart = CvSTART(cv);
 
-           CvGV_set(cv,gv);
-           assert(!CvCVGV_RC(cv));
-           assert(CvGV(cv) == gv);
+           if (isGV(gv)) {
+               CvGV_set(cv,gv);
+               assert(!CvCVGV_RC(cv));
+               assert(CvGV(cv) == gv);
+           }
+           else {
+               dVAR;
+               U32 hash;
+               PERL_HASH(hash, name, namlen);
+               CvNAME_HEK_set(cv,
+                              share_hek(name,
+                                        name_is_utf8
+                                           ? -(SSize_t)namlen
+                                           :  (SSize_t)namlen,
+                                        hash));
+           }
 
            SvPOK_off(cv);
-           CvFLAGS(cv) = CvFLAGS(PL_compcv) | existing_builtin_attrs;
+           CvFLAGS(cv) = CvFLAGS(PL_compcv) | existing_builtin_attrs
+                                            | CvNAMED(cv);
            CvOUTSIDE(cv) = CvOUTSIDE(PL_compcv);
            CvOUTSIDE_SEQ(cv) = CvOUTSIDE_SEQ(PL_compcv);
            CvPADLIST(cv) = CvPADLIST(PL_compcv);
@@ -7851,16 +8278,35 @@ Perl_newATTRSUB_x(pTHX_ I32 floor, OP *o, OP *proto, OP *attrs,
     }
     else {
        cv = PL_compcv;
-       if (name) {
+       if (name && isGV(gv)) {
            GvCV_set(gv, cv);
            GvCVGEN(gv) = 0;
            if (HvENAME_HEK(GvSTASH(gv)))
                /* sub Foo::bar { (shift)+1 } */
                gv_method_changed(gv);
        }
+       else if (name) {
+           if (!SvROK(gv)) {
+               SV_CHECK_THINKFIRST_COW_DROP((SV *)gv);
+               prepare_SV_for_RV((SV *)gv);
+               SvOK_off((SV *)gv);
+               SvROK_on(gv);
+           }
+           SvRV_set(gv, (SV *)cv);
+       }
     }
-    if (!CvGV(cv)) {
-       CvGV_set(cv, gv);
+    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,
+                                        name_is_utf8
+                                           ? -(SSize_t)namlen
+                                           :  (SSize_t)namlen,
+                                        hash));
+       }
        CvFILE_set_from_cop(cv, PL_curcop);
        CvSTASH_set(cv, PL_curstash);
     }
@@ -7917,7 +8363,9 @@ Perl_newATTRSUB_x(pTHX_ I32 floor, OP *o, OP *proto, OP *attrs,
   attrs:
     if (attrs) {
        /* Need to do a C<use attributes $stash_of_cv,\&cv,@attrs>. */
-       HV *stash = name && GvSTASH(CvGV(cv)) ? GvSTASH(CvGV(cv)) : PL_curstash;
+       HV *stash = name && !CvNAMED(cv) && GvSTASH(CvGV(cv))
+                       ? GvSTASH(CvGV(cv))
+                       : PL_curstash;
        if (!name) SAVEFREESV(cv);
        apply_attrs(stash, MUTABLE_SV(cv), attrs);
        if (!name) SvREFCNT_inc_simple_void_NN(cv);
@@ -7925,7 +8373,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 = sv_newmortal();
+           SV * const tmpstr = cv_name(cv,NULL,0);
            GV * const db_postponed = gv_fetchpvs("DB::postponed",
                                                  GV_ADDMULTI, SVt_PVHV);
            HV *hv;
@@ -7933,7 +8381,6 @@ Perl_newATTRSUB_x(pTHX_ I32 floor, OP *o, OP *proto, OP *attrs,
                                          CopFILE(PL_curcop),
                                          (long)PL_subline,
                                          (long)CopLINE(PL_curcop));
-           gv_efullname3(tmpstr, gv, NULL);
            (void)hv_store(GvHV(PL_DBsub), SvPVX_const(tmpstr),
                    SvUTF8(tmpstr) ? -(I32)SvCUR(tmpstr) : (I32)SvCUR(tmpstr), sv, 0);
            hv = GvHVn(db_postponed);
@@ -7953,7 +8400,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
-                process_special_blocks(floor, name, gv, cv);
+#ifdef PERL_DEBUG_READONLY_OPS
+                special =
+#endif
+                    process_special_blocks(floor, name, gv, cv);
         }
     }
 
@@ -7963,7 +8413,7 @@ Perl_newATTRSUB_x(pTHX_ I32 floor, OP *o, OP *proto, OP *attrs,
     LEAVE_SCOPE(floor);
 #ifdef PERL_DEBUG_READONLY_OPS
     /* Watch out for BEGIN blocks */
-    if (slab && gv && isGV(gv) && GvCV(gv)) Slab_to_ro(slab);
+    if (!special) Slab_to_ro(slab);
 #endif
     return cv;
 }
@@ -7984,12 +8434,16 @@ S_clear_special_blocks(pTHX_ const char *const fullname,
         || (*name == 'U' && strEQ(name, "UNITCHECK"))
         || (*name == 'C' && strEQ(name, "CHECK"))
         || (*name == 'I' && strEQ(name, "INIT"))) {
+        if (!isGV(gv)) {
+            (void)CvGV(cv);
+            assert(isGV(gv));
+        }
         GvCV_set(gv, NULL);
         SvREFCNT_dec_NN(MUTABLE_SV(cv));
     }
 }
 
-STATIC void
+STATIC bool
 S_process_special_blocks(pTHX_ I32 floor, const char *const fullname,
                         GV *const gv,
                         CV *const cv)
@@ -8003,6 +8457,7 @@ S_process_special_blocks(pTHX_ I32 floor, const char *const fullname,
        if (strEQ(name, "BEGIN")) {
            const I32 oldscope = PL_scopestack_ix;
             dSP;
+            (void)CvGV(cv);
            if (floor) LEAVE_SCOPE(floor);
            ENTER;
             PUSHSTACKi(PERLSI_REQUIRE);
@@ -8017,23 +8472,24 @@ S_process_special_blocks(pTHX_ I32 floor, const char *const fullname,
 
             POPSTACK;
            LEAVE;
+           return TRUE;
        }
        else
-           return;
+           return FALSE;
     } else {
        if (*name == 'E') {
            if strEQ(name, "END") {
                DEBUG_x( dump_sub(gv) );
                Perl_av_create_and_unshift_one(aTHX_ &PL_endav, MUTABLE_SV(cv));
            } else
-               return;
+               return FALSE;
        } else if (*name == 'U') {
            if (strEQ(name, "UNITCHECK")) {
                /* It's never too late to run a unitcheck block */
                Perl_av_create_and_unshift_one(aTHX_ &PL_unitcheckav, MUTABLE_SV(cv));
            }
            else
-               return;
+               return FALSE;
        } else if (*name == 'C') {
            if (strEQ(name, "CHECK")) {
                if (PL_main_start)
@@ -8043,7 +8499,7 @@ S_process_special_blocks(pTHX_ I32 floor, const char *const fullname,
                Perl_av_create_and_unshift_one(aTHX_ &PL_checkav, MUTABLE_SV(cv));
            }
            else
-               return;
+               return FALSE;
        } else if (*name == 'I') {
            if (strEQ(name, "INIT")) {
                if (PL_main_start)
@@ -8053,11 +8509,13 @@ S_process_special_blocks(pTHX_ I32 floor, const char *const fullname,
                Perl_av_create_and_push(aTHX_ &PL_initav, MUTABLE_SV(cv));
            }
            else
-               return;
+               return FALSE;
        } else
-           return;
+           return FALSE;
        DEBUG_x( dump_sub(gv) );
+       (void)CvGV(cv);
        GvCV_set(gv,0);         /* cv has been hijacked */
+       return TRUE;
     }
 }
 
@@ -8658,9 +9116,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 */
@@ -8850,10 +9313,6 @@ Perl_ck_rvconst(pTHX_ OP *o)
 
     if (kid->op_type == OP_CONST) {
        int iscv;
-       const int noexpand = o->op_type == OP_RV2CV
-                         && o->op_private & OPpMAY_RETURN_CONSTANT
-                               ? GV_NOEXPAND
-                               : 0;
        GV *gv;
        SV * const kidsv = kid->op_sv;
 
@@ -8891,10 +9350,11 @@ Perl_ck_rvconst(pTHX_ OP *o)
         * or we get possible typo warnings.  OPpCONST_ENTERED says
         * whether the lexer already added THIS instance of this symbol.
         */
-       iscv = (o->op_type == OP_RV2CV) * 2;
+       iscv = o->op_type == OP_RV2CV ? GV_NOEXPAND|GV_ADDMULTI : 0;
        gv = gv_fetchsv(kidsv,
-               noexpand
-                   ? noexpand
+               o->op_type == OP_RV2CV
+                       && o->op_private & OPpMAY_RETURN_CONSTANT
+                   ? GV_NOEXPAND
                    : iscv | !(kid->op_private & OPpCONST_ENTERED),
                iscv
                    ? SVt_PVCV
@@ -8906,6 +9366,13 @@ Perl_ck_rvconst(pTHX_ OP *o)
                                ? SVt_PVHV
                                : SVt_PVGV);
        if (gv) {
+           if (!isGV(gv)) {
+               assert(iscv);
+               assert(SvROK(gv));
+               if (!(o->op_private & OPpMAY_RETURN_CONSTANT)
+                 && SvTYPE(SvRV(gv)) != SVt_PVCV)
+                   gv_fetchsv(kidsv, GV_ADDMULTI, SVt_PVCV);
+           }
            kid->op_type = OP_GV;
            SvREFCNT_dec(kid->op_sv);
 #ifdef USE_ITHREADS
@@ -8913,7 +9380,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);
@@ -9407,7 +9873,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;
     }
@@ -9547,23 +10013,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;
        }
     }
@@ -9590,25 +10051,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;
 }
@@ -9651,6 +10113,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 reference to %s in %s assignment */
+       yyerror(Perl_form(aTHX_ "Can't modify reference to %s in scalar "
+                               "assignment",
+                                OP_DESC(varop)));
+       return o;
+    }
+    if (!FEATURE_REFALIASING_IS_ENABLED)
+       Perl_croak(aTHX_
+                 "Experimental aliasing via reference not enabled");
+    Perl_ck_warner_d(aTHX_
+                    packWARN(WARN_EXPERIMENTAL__REFALIASING),
+                   "Aliasing via reference is 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;
@@ -9661,6 +10199,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);
@@ -9858,6 +10397,33 @@ Perl_ck_sort(pTHX_ OP *o)
            kid->op_next = kid;
            o->op_flags |= OPf_SPECIAL;
        }
+       else if (kid->op_type == OP_CONST
+             && kid->op_private & OPpCONST_BARE) {
+           char tmpbuf[256];
+           STRLEN len;
+           PADOFFSET off;
+           const char * const name = SvPV(kSVOP_sv, len);
+           *tmpbuf = '&';
+           assert (len < 256);
+           Copy(name, tmpbuf+1, len, char);
+           off = pad_findmy_pvn(tmpbuf, len+1, SvUTF8(kSVOP_sv));
+           if (off != NOT_IN_PAD) {
+               if (PAD_COMPNAME_FLAGS_isOUR(off)) {
+                   SV * const fq =
+                       newSVhek(HvNAME_HEK(PAD_COMPNAME_OURSTASH(off)));
+                   sv_catpvs(fq, "::");
+                   sv_catsv(fq, kSVOP_sv);
+                   SvREFCNT_dec_NN(kSVOP_sv);
+                   kSVOP->op_sv = fq;
+               }
+               else {
+                   OP * const padop = newOP(OP_PADCV, 0);
+                   padop->op_targ = off;
+                   cUNOPx(firstkid)->op_first = padop;
+                   op_free(kid);
+               }
+           }
+       }
 
        firstkid = OP_SIBLING(firstkid);
     }
@@ -10041,9 +10607,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;
 
@@ -10059,6 +10639,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);
 }
 
@@ -10143,6 +10740,11 @@ Perl_rv2cv_op_cv(pTHX_ OP *cvop, U32 flags)
        case OP_GV: {
            gv = cGVOPx_gv(rvop);
            if (!isGV(gv)) {
+               if (SvROK(gv) && SvTYPE(SvRV(gv)) == SVt_PVCV) {
+                   cv = MUTABLE_CV(SvRV(gv));
+                   gv = NULL;
+                   break;
+               }
                if (flags & RV2CVOPCV_RETURN_STUB)
                    return (CV *)gv;
                else return NULL;
@@ -10171,8 +10773,9 @@ Perl_rv2cv_op_cv(pTHX_ OP *cvop, U32 flags)
     }
     if (SvTYPE((SV*)cv) != SVt_PVCV)
        return NULL;
-    if (flags & RV2CVOPCV_RETURN_NAME_GV) {
-       if ((!CvANON(cv) || !gv) && !CvLEXICAL(cv))
+    if (flags & (RV2CVOPCV_RETURN_NAME_GV|RV2CVOPCV_MAYBE_NAME_GV)) {
+       if ((!CvANON(cv) || !gv) && !CvLEXICAL(cv)
+        && ((flags & RV2CVOPCV_RETURN_NAME_GV) || !CvNAMED(cv)))
            gv = CvGV(cv);
        return (CV*)gv;
     } else {
@@ -10268,7 +10871,12 @@ Perl_ck_entersub_args_proto(pTHX_ OP *entersubop, GV *namegv, SV *protosv)
        OP* o3 = aop;
 
        if (proto >= proto_end)
-           return too_many_arguments_sv(entersubop, gv_ename(namegv), 0);
+       {
+           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;
+       }
 
        switch (*proto) {
            case ';':
@@ -10293,7 +10901,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);
@@ -10418,10 +11027,9 @@ Perl_ck_entersub_args_proto(pTHX_ OP *entersubop, GV *namegv, SV *protosv)
                continue;
            default:
            oops: {
-                SV* const tmpsv = sv_newmortal();
-                gv_efullname3(tmpsv, namegv, NULL);
                Perl_croak(aTHX_ "Malformed prototype for %"SVf": %"SVf,
-                       SVfARG(tmpsv), SVfARG(protosv));
+                                 SVfARG(cv_name((CV *)namegv, NULL, 0)),
+                                 SVfARG(protosv));
             }
        }
 
@@ -10435,7 +11043,11 @@ Perl_ck_entersub_args_proto(pTHX_ OP *entersubop, GV *namegv, SV *protosv)
     }
     if (!optional && proto_end > proto &&
        (*proto != '@' && *proto != '%' && *proto != ';' && *proto != '_'))
-       return too_few_arguments_sv(entersubop, gv_ename(namegv), 0);
+    {
+       SV * const namesv = cv_name((CV *)namegv, NULL, 0);
+       yyerror_pv(Perl_form(aTHX_ "Not enough arguments for %"SVf,
+                                   SVfARG(namesv)), SvUTF8(namesv));
+    }
     return entersubop;
 }
 
@@ -10603,24 +11215,33 @@ by L</cv_set_call_checker>.
 =cut
 */
 
-void
-Perl_cv_get_call_checker(pTHX_ CV *cv, Perl_call_checker *ckfun_p, SV **ckobj_p)
+static void
+S_cv_get_call_checker(CV *cv, Perl_call_checker *ckfun_p, SV **ckobj_p,
+                     U8 *flagsp)
 {
     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);
        *ckobj_p = callmg->mg_obj;
+       if (flagsp) *flagsp = callmg->mg_flags;
     } else {
        *ckfun_p = Perl_ck_entersub_args_proto_or_list;
        *ckobj_p = (SV*)cv;
+       if (flagsp) *flagsp = 0;
     }
 }
 
+void
+Perl_cv_get_call_checker(pTHX_ CV *cv, Perl_call_checker *ckfun_p, SV **ckobj_p)
+{
+    PERL_ARGS_ASSERT_CV_GET_CALL_CHECKER;
+    PERL_UNUSED_CONTEXT;
+    S_cv_get_call_checker(cv, ckfun_p, ckobj_p, NULL);
+}
+
 /*
-=for apidoc Am|void|cv_set_call_checker|CV *cv|Perl_call_checker ckfun|SV *ckobj
+=for apidoc Am|void|cv_set_call_checker_flags|CV *cv|Perl_call_checker ckfun|SV *ckobj|U32 flags
 
 Sets the function that will be used to fix up a call to I<cv>.
 Specifically, the function is applied to an C<entersub> op tree for a
@@ -10637,15 +11258,25 @@ It is intended to be called in this manner:
     entersubop = ckfun(aTHX_ entersubop, namegv, ckobj);
 
 In this call, I<entersubop> is a pointer to the C<entersub> op,
-which may be replaced by the check function, and I<namegv> is a GV
-supplying the name that should be used by the check function to refer
+which may be replaced by the check function, and I<namegv> supplies
+the name that should be used by the check function to refer
 to the callee of the C<entersub> op if it needs to emit any diagnostics.
 It is permitted to apply the check function in non-standard situations,
 such as to a call to a different subroutine or to a method call.
 
+I<namegv> may not actually be a GV.  For efficiency, perl may pass a
+CV or other SV instead.  Whatever is passed can be used as the first
+argument to L</cv_name>.  You can force perl to pass a GV by including
+C<CALL_CHECKER_REQUIRE_GV> in the I<flags>.
+
 The current setting for a particular CV can be retrieved by
 L</cv_get_call_checker>.
 
+=for apidoc Am|void|cv_set_call_checker|CV *cv|Perl_call_checker ckfun|SV *ckobj
+
+The original form of L</cv_set_call_checker_flags>, which passes it the
+C<CALL_CHECKER_REQUIRE_GV> flag for backward-compatibility.
+
 =cut
 */
 
@@ -10653,6 +11284,14 @@ void
 Perl_cv_set_call_checker(pTHX_ CV *cv, Perl_call_checker ckfun, SV *ckobj)
 {
     PERL_ARGS_ASSERT_CV_SET_CALL_CHECKER;
+    cv_set_call_checker_flags(cv, ckfun, ckobj, CALL_CHECKER_REQUIRE_GV);
+}
+
+void
+Perl_cv_set_call_checker_flags(pTHX_ CV *cv, Perl_call_checker ckfun,
+                                    SV *ckobj, U32 flags)
+{
+    PERL_ARGS_ASSERT_CV_SET_CALL_CHECKER_FLAGS;
     if (ckfun == Perl_ck_entersub_args_proto_or_list && ckobj == (SV*)cv) {
        if (SvMAGICAL((SV*)cv))
            mg_free_type((SV*)cv, PERL_MAGIC_checkcall);
@@ -10671,7 +11310,8 @@ Perl_cv_set_call_checker(pTHX_ CV *cv, Perl_call_checker ckfun, SV *ckobj)
            SvREFCNT_inc_simple_void_NN(ckobj);
            callmg->mg_flags |= MGf_REFCOUNTED;
        }
-       callmg->mg_flags |= MGf_COPY;
+       callmg->mg_flags = (callmg->mg_flags &~ MGf_REQUIRE_GV)
+                        | (U8)(flags & MGf_REQUIRE_GV) | MGf_COPY;
     }
 }
 
@@ -10690,7 +11330,7 @@ Perl_ck_subr(pTHX_ OP *o)
     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;
+    namegv = cv ? (GV*)rv2cv_op_cv(cvop, RV2CVOPCV_MAYBE_NAME_GV) : NULL;
 
     o->op_private &= ~1;
     o->op_private |= OPpENTERSUB_HASTARG;
@@ -10715,21 +11355,24 @@ Perl_ck_subr(pTHX_ OP *o)
     } else {
        Perl_call_checker ckfun;
        SV *ckobj;
-       cv_get_call_checker(cv, &ckfun, &ckobj);
-       if (!namegv) { /* expletive! */
-           /* XXX The call checker API is public.  And it guarantees that
-                  a GV will be provided with the right name.  So we have
-                  to create a GV.  But it is still not correct, as its
-                  stringification will include the package.  What we
-                  really need is a new call checker API that accepts a
-                  GV or string (or GV or CV). */
-           HEK * const hek = CvNAME_HEK(cv);
+       U8 flags;
+       S_cv_get_call_checker(cv, &ckfun, &ckobj, &flags);
+       if (!namegv) {
+           /* The original call checker API guarantees that a GV will be
+              be provided with the right name.  So, if the old API was
+              used (or the REQUIRE_GV flag was passed), we have to reify
+              the CV’s GV, unless this is an anonymous sub.  This is not
+              ideal for lexical subs, as its stringification will include
+              the package.  But it is the best we can do.  */
+           if (flags & MGf_REQUIRE_GV) {
+               if (!CvANON(cv) && (!CvNAMED(cv) || CvNAME_HEK(cv)))
+                   namegv = CvGV(cv);
+           }
+           else namegv = MUTABLE_GV(cv);
            /* After a syntax error in a lexical sub, the cv that
               rv2cv_op_cv returns may be a nameless stub. */
-           if (!hek) return ck_entersub_args_list(o);;
-           namegv = (GV *)sv_newmortal();
-           gv_init_pvn(namegv, PL_curstash, HEK_KEY(hek), HEK_LEN(hek),
-                       SVf_UTF8 * !!HEK_UTF8(hek));
+           if (!namegv) return ck_entersub_args_list(o);
+
        }
        return ckfun(aTHX_ o, namegv, ckobj);
     }
@@ -11010,19 +11653,11 @@ S_inplace_aassign(pTHX_ OP *o) {
 STATIC void
 S_null_listop_in_list_context(pTHX_ OP *o)
 {
-    OP *kid;
-
     PERL_ARGS_ASSERT_NULL_LISTOP_IN_LIST_CONTEXT;
 
-    /* This is an OP_LIST in list context. That means we
+    /* This is an OP_LIST in list (or void) context. That means we
      * can ditch the OP_LIST and the OP_PUSHMARK within. */
 
-    kid = cLISTOPo->op_first;
-    /* Find the end of the chain of OPs executed within the OP_LIST. */
-    while (kid->op_next != o)
-        kid = kid->op_next;
-
-    kid->op_next = o->op_next; /* patch list out of exec chain */
     op_null(cUNOPo->op_first); /* NULL the pushmark */
     op_null(o); /* NULL the list */
 }
@@ -11061,6 +11696,7 @@ Perl_rpeep(pTHX_ OP *o)
            break;
        }
 
+      redo:
        /* By default, this op has now been optimised. A couple of cases below
           clear this again.  */
        o->op_opt = 1;
@@ -11068,7 +11704,8 @@ Perl_rpeep(pTHX_ OP *o)
 
 
         /* The following will have the OP_LIST and OP_PUSHMARK
-         * patched out later IF the OP_LIST is in list context.
+         * patched out later IF the OP_LIST is in list context, or
+         * if it is in void context and padrange is not possible.
          * So in that case, we can set the this OP's op_next
          * to skip to after the OP_PUSHMARK:
          *   a THIS -> b
@@ -11086,17 +11723,28 @@ Perl_rpeep(pTHX_ OP *o)
         {
             OP *sibling;
             OP *other_pushmark;
+            OP *pushsib;
             if (OP_TYPE_IS(o->op_next, OP_PUSHMARK)
                 && (sibling = OP_SIBLING(o))
                 && sibling->op_type == OP_LIST
                 /* This KIDS check is likely superfluous since OP_LIST
                  * would otherwise be an OP_STUB. */
                 && sibling->op_flags & OPf_KIDS
-                && (sibling->op_flags & OPf_WANT) == OPf_WANT_LIST
                 && (other_pushmark = cLISTOPx(sibling)->op_first)
                 /* Pointer equality also effectively checks that it's a
                  * pushmark. */
-                && other_pushmark == o->op_next)
+                && other_pushmark == o->op_next
+                /* List context */
+                && (  (sibling->op_flags & OPf_WANT) == OPf_WANT_LIST
+                   /* ... or void context... */
+                   || (  (sibling->op_flags & OPf_WANT) == OPf_WANT_VOID
+                      /* ...and something padrange would reject */
+                      && (  !(pushsib = OP_SIBLING(other_pushmark))
+                         || (  pushsib->op_type != OP_PADSV
+                            && pushsib->op_type != OP_PADAV
+                            && pushsib->op_type != OP_PADHV)
+                         || pushsib->op_private & ~OPpLVAL_INTRO))
+                   ))
             {
                 o->op_next = other_pushmark->op_next;
                 null_listop_in_list_context(sibling);
@@ -11233,44 +11881,9 @@ Perl_rpeep(pTHX_ OP *o)
                    nextop = nextop->op_next;
 
                if (nextop && (nextop->op_type == OP_NEXTSTATE)) {
-                   COP *firstcop = (COP *)o;
-                   COP *secondcop = (COP *)nextop;
-                   /* We want the COP pointed to by o (and anything else) to
-                      become the next COP down the line.  */
-                   cop_free(firstcop);
-
-                   firstcop->op_next = secondcop->op_next;
-
-                   /* Now steal all its pointers, and duplicate the other
-                      data.  */
-                   firstcop->cop_line = secondcop->cop_line;
-#ifdef USE_ITHREADS
-                   firstcop->cop_stashoff = secondcop->cop_stashoff;
-                   firstcop->cop_file = secondcop->cop_file;
-#else
-                   firstcop->cop_stash = secondcop->cop_stash;
-                   firstcop->cop_filegv = secondcop->cop_filegv;
-#endif
-                   firstcop->cop_hints = secondcop->cop_hints;
-                   firstcop->cop_seq = secondcop->cop_seq;
-                   firstcop->cop_warnings = secondcop->cop_warnings;
-                   firstcop->cop_hints_hash = secondcop->cop_hints_hash;
-
-#ifdef USE_ITHREADS
-                   secondcop->cop_stashoff = 0;
-                   secondcop->cop_file = NULL;
-#else
-                   secondcop->cop_stash = NULL;
-                   secondcop->cop_filegv = NULL;
-#endif
-                   secondcop->cop_warnings = NULL;
-                   secondcop->cop_hints_hash = NULL;
-
-                   /* If we use op_null(), and hence leave an ex-COP, some
-                      warnings are misreported. For example, the compile-time
-                      error in 'use strict; no strict refs;'  */
-                   secondcop->op_type = OP_NULL;
-                   secondcop->op_ppaddr = PL_ppaddr[OP_NULL];
+                   op_null(o);
+                   if (oldop)
+                       oldop->op_next = nextop;
                }
            }
            break;
@@ -11358,7 +11971,7 @@ Perl_rpeep(pTHX_ OP *o)
                 OP *rv2av, *q;
                 p = o->op_next;
                 if (   p->op_type == OP_GV
-                    && (gv = cGVOPx_gv(p))
+                    && (gv = cGVOPx_gv(p)) && isGV(gv)
                     && GvNAMELEN_get(gv) == 1
                     && *GvNAME_get(gv) == '_'
                     && GvSTASH(gv) == PL_defstash
@@ -11457,7 +12070,7 @@ Perl_rpeep(pTHX_ OP *o)
                 followop = p->op_next;
             }
 
-            if (count < 1)
+            if (count < 1 || (count == 1 && !defav))
                 break;
 
             /* pp_padrange in specifically compile-time void context
@@ -11468,17 +12081,16 @@ Perl_rpeep(pTHX_ OP *o)
              * padrange.
              * In particular in void context, we can only optimise to
              * a padrange if see see the complete sequence
-             *     pushmark, pad*v, ...., list, nextstate
-             * which has the net effect of of leaving the stack empty
-             * (for now we leave the nextstate in the execution chain, for
-             * its other side-effects).
+             *     pushmark, pad*v, ...., list
+             * which has the net effect of of leaving the markstack as it
+             * was.  Not pushing on to the stack (whereas padsv does touch
+             * the stack) makes no difference in void context.
              */
             assert(followop);
             if (gimme == OPf_WANT_VOID) {
-                if (OP_TYPE_IS_OR_WAS(followop, OP_LIST)
+                if (followop->op_type == OP_LIST
                         && gimme == (followop->op_flags & OPf_WANT)
-                        && (   followop->op_next->op_type == OP_NEXTSTATE
-                            || followop->op_next->op_type == OP_DBSTATE))
+                   )
                 {
                     followop = followop->op_next; /* skip OP_LIST */
 
@@ -11598,10 +12210,31 @@ Perl_rpeep(pTHX_ OP *o)
                    else
                        o->op_type = OP_AELEMFAST_LEX;
                }
-               break;
+               if (o->op_type != OP_GV)
+                   break;
            }
 
-           if (o->op_next->op_type == OP_RV2SV) {
+           /* Remove $foo from the op_next chain in void context.  */
+           if (oldop
+            && (  o->op_next->op_type == OP_RV2SV
+               || o->op_next->op_type == OP_RV2AV
+               || o->op_next->op_type == OP_RV2HV  )
+            && (o->op_next->op_flags & OPf_WANT) == OPf_WANT_VOID
+            && !(o->op_next->op_private & OPpLVAL_INTRO))
+           {
+               oldop->op_next = o->op_next->op_next;
+               /* Reprocess the previous op if it is a nextstate, to
+                  allow double-nextstate optimisation.  */
+               if (oldop->op_type == OP_NEXTSTATE) {
+                   oldop->op_opt = 0;
+                   o = oldop;
+                   oldop = oldoldop;
+                   oldoldop = NULL;
+                   goto redo;
+               }
+               o = oldop;
+           }
+           else if (o->op_next->op_type == OP_RV2SV) {
                if (!(o->op_next->op_private & OPpDEREF)) {
                    op_null(o->op_next);
                    o->op_private |= o->op_next->op_private & (OPpLVAL_INTRO
@@ -11772,7 +12405,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;
@@ -11962,6 +12597,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);