This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Restore strict refs on stashes, removed by ce10b5d1ec5b5f68b0811018a415bc37.
[perl5.git] / op.c
diff --git a/op.c b/op.c
index f1faf42..47f8300 100644 (file)
--- a/op.c
+++ b/op.c
@@ -1,3 +1,4 @@
+#line 2 "op.c"
 /*    op.c
  *
  *    Copyright (C) 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
@@ -57,7 +58,7 @@ context is, either upward in the syntax tree, or either forward or
 backward in the execution order.  (The bottom-up parser builds that
 part of the execution order it knows about, but if you follow the "next"
 links around, you'll find it's actually a closed loop through the
-top level node.
+top level node.)
 
 Whenever the bottom-up parser gets to a node that supplies context to
 its components, it invokes that portion of the top-down pass that applies
@@ -103,6 +104,7 @@ recursive, but it's recursive on basic blocks, not on tree nodes.
 #include "keywords.h"
 
 #define CALL_PEEP(o) CALL_FPTR(PL_peepp)(aTHX_ o)
+#define CALL_OPFREEHOOK(o) if (PL_opfreehook) CALL_FPTR(PL_opfreehook)(aTHX_ o)
 
 #if defined(PL_OP_SLAB_ALLOC)
 
@@ -370,7 +372,7 @@ S_no_bareword_allowed(pTHX_ const OP *o)
 /* "register" allocation */
 
 PADOFFSET
-Perl_allocmy(pTHX_ const char *const name)
+Perl_allocmy(pTHX_ const char *const name, const STRLEN len, const U32 flags)
 {
     dVAR;
     PADOFFSET off;
@@ -378,46 +380,43 @@ Perl_allocmy(pTHX_ const char *const name)
 
     PERL_ARGS_ASSERT_ALLOCMY;
 
+    if (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 (*name &&
+    if (len &&
        !(is_our ||
          isALPHA(name[1]) ||
          (USE_UTF8_IN_NAMES && UTF8_IS_START(name[1])) ||
-         (name[1] == '_' && (*name == '$' || name[2]))))
+         (name[1] == '_' && (*name == '$' || len > 2))))
     {
        /* name[2] is true if strlen(name) > 2  */
        if (!isPRINT(name[1]) || strchr("\t\n\r\f", name[1])) {
-           yyerror(Perl_form(aTHX_ "Can't use global %c^%c%s in \"%s\"",
-                             name[0], toCTRL(name[1]), name + 2,
+           yyerror(Perl_form(aTHX_ "Can't use global %c^%c%.*s in \"%s\"",
+                             name[0], toCTRL(name[1]), (int)(len - 2), name + 2,
                              PL_parser->in_my == KEY_state ? "state" : "my"));
        } else {
-           yyerror(Perl_form(aTHX_ "Can't use global %s in \"%s\"",name,
+           yyerror(Perl_form(aTHX_ "Can't use global %.*s in \"%s\"", (int) len, name,
                              PL_parser->in_my == KEY_state ? "state" : "my"));
        }
     }
 
-    /* check for duplicate declaration */
-    pad_check_dup(name, is_our, (PL_curstash ? PL_curstash : PL_defstash));
-
-    if (PL_parser->in_my_stash && *name != '$') {
-       yyerror(Perl_form(aTHX_
-                   "Can't declare class for non-scalar %s in \"%s\"",
-                    name,
-                    is_our ? "our"
-                           : PL_parser->in_my == KEY_state ? "state" : "my"));
-    }
-
     /* allocate a spare slot and store the name in that slot */
 
-    off = pad_add_name(name,
+    off = pad_add_name(name, len,
+                      is_our ? padadd_OUR :
+                      PL_parser->in_my == KEY_state ? padadd_STATE : 0,
                    PL_parser->in_my_stash,
                    (is_our
                        /* $_ is always in main::, even with our */
                        ? (PL_curstash && !strEQ(name,"$_") ? PL_curstash : PL_defstash)
                        : NULL
-                   ),
-                   0, /*  not fake */
-                   PL_parser->in_my == KEY_state
+                   )
     );
     /* anon sub prototypes contains state vars should always be cloned,
      * otherwise the state var would be shared between anon subs */
@@ -490,6 +489,11 @@ Perl_op_free(pTHX_ OP *o)
        }
     }
 
+    /* Call the op_free hook if it has been set. Do it now so that it's called
+     * at the right time for refcounted ops, but still before all of the kids
+     * are freed. */
+    CALL_OPFREEHOOK(o);
+
     if (o->op_flags & OPf_KIDS) {
         register OP *kid, *nextkid;
        for (kid = cUNOPo->op_first; kid; kid = nextkid) {
@@ -558,6 +562,7 @@ Perl_op_clear(pTHX_ OP *o)
            o->op_targ = 0;
            goto retry;
        }
+    case OP_ENTERTRY:
     case OP_ENTEREVAL: /* Was holding hints. */
        o->op_targ = 0;
        break;
@@ -571,6 +576,29 @@ Perl_op_clear(pTHX_ OP *o)
     case OP_AELEMFAST:
        if (! (o->op_type == OP_AELEMFAST && o->op_flags & OPf_SPECIAL)) {
            /* not an OP_PADAV replacement */
+           GV *gv = (o->op_type == OP_GV || o->op_type == OP_GVSV)
+#ifdef USE_ITHREADS
+                       && PL_curpad
+#endif
+                       ? cGVOPo_gv : NULL;
+           /* It's possible during global destruction that the GV is freed
+              before the optree. Whilst the SvREFCNT_inc is happy to bump from
+              0 to 1 on a freed SV, the corresponding SvREFCNT_dec from 1 to 0
+              will trigger an assertion failure, because the entry to sv_clear
+              checks that the scalar is not already freed.  A check of for
+              !SvIS_FREED(gv) turns out to be invalid, because during global
+              destruction the reference count can be forced down to zero
+              (with SVf_BREAK set).  In which case raising to 1 and then
+              dropping to 0 triggers cleanup before it should happen.  I
+              *think* that this might actually be a general, systematic,
+              weakness of the whole idea of SVf_BREAK, in that code *is*
+              allowed to raise and lower references during global destruction,
+              so any *valid* code that happens to do this during global
+              destruction might well trigger premature cleanup.  */
+           bool still_valid = gv && SvREFCNT(gv);
+
+           if (still_valid)
+               SvREFCNT_inc_simple_void(gv);
 #ifdef USE_ITHREADS
            if (cPADOPo->op_padix > 0) {
                /* No GvIN_PAD_off(cGVOPo_gv) here, because other references
@@ -582,6 +610,12 @@ Perl_op_clear(pTHX_ OP *o)
            SvREFCNT_dec(cSVOPo->op_sv);
            cSVOPo->op_sv = NULL;
 #endif
+           if (still_valid) {
+               int try_downgrade = SvREFCNT(gv) == 2;
+               SvREFCNT_dec(gv);
+               if (try_downgrade)
+                   gv_try_downgrade(gv);
+           }
        }
        break;
     case OP_METHOD_NAMED:
@@ -874,12 +908,8 @@ Perl_scalar(pTHX_ OP *o)
        for (kid = cUNOPo->op_first->op_sibling; kid; kid = kid->op_sibling)
            scalar(kid);
        break;
-    case OP_SPLIT:
-       if ((kid = cLISTOPo->op_first) && kid->op_type == OP_PUSHRE) {
-           if (!kPMOP->op_pmreplrootu.op_pmreplroot)
-               deprecate_old("implicit split to @_");
-       }
        /* FALL THROUGH */
+    case OP_SPLIT:
     case OP_MATCH:
     case OP_QR:
     case OP_SUBST:
@@ -894,28 +924,30 @@ Perl_scalar(pTHX_ OP *o)
     case OP_LEAVETRY:
        kid = cLISTOPo->op_first;
        scalar(kid);
-       while ((kid = kid->op_sibling)) {
-           if (kid->op_sibling)
-               scalarvoid(kid);
-           else
+       kid = kid->op_sibling;
+    do_kids:
+       while (kid) {
+           OP *sib = kid->op_sibling;
+           if (sib && kid->op_type != OP_LEAVEWHEN) {
+               if (sib->op_type == OP_BREAK && sib->op_flags & OPf_SPECIAL) {
+                   scalar(kid);
+                   scalarvoid(sib);
+                   break;
+               } else
+                   scalarvoid(kid);
+           } else
                scalar(kid);
+           kid = sib;
        }
        PL_curcop = &PL_compiling;
        break;
     case OP_SCOPE:
     case OP_LINESEQ:
     case OP_LIST:
-       for (kid = cLISTOPo->op_first; kid; kid = kid->op_sibling) {
-           if (kid->op_sibling)
-               scalarvoid(kid);
-           else
-               scalar(kid);
-       }
-       PL_curcop = &PL_compiling;
-       break;
+       kid = cLISTOPo->op_first;
+       goto do_kids;
     case OP_SORT:
-       if (ckWARN(WARN_VOID))
-           Perl_warner(aTHX_ packWARN(WARN_VOID), "Useless use of sort in scalar context");
+       Perl_ck_warner(aTHX_ packWARN(WARN_VOID), "Useless use of sort in scalar context");
        break;
     }
     return o;
@@ -957,7 +989,7 @@ Perl_scalarvoid(pTHX_ OP *o)
     want = o->op_flags & OPf_WANT;
     if ((want && want != OPf_WANT_SCALAR)
         || (PL_parser && PL_parser->error_count)
-        || o->op_type == OP_RETURN)
+        || o->op_type == OP_RETURN || o->op_type == OP_REQUIRE || o->op_type == OP_LEAVEWHEN)
     {
        return o;
     }
@@ -1058,6 +1090,17 @@ Perl_scalarvoid(pTHX_ OP *o)
            useless = OP_DESC(o);
        break;
 
+    case OP_SPLIT:
+       kid = cLISTOPo->op_first;
+       if (kid && kid->op_type == OP_PUSHRE
+#ifdef USE_ITHREADS
+               && !((PMOP*)kid)->op_pmreplrootu.op_pmtargetoff)
+#else
+               && !((PMOP*)kid)->op_pmreplrootu.op_pmtargetgv)
+#endif
+           useless = OP_DESC(o);
+       break;
+
     case OP_NOT:
        kid = cUNOPo->op_first;
        if (kid->op_type != OP_MATCH && kid->op_type != OP_SUBST &&
@@ -1187,21 +1230,11 @@ Perl_scalarvoid(pTHX_ OP *o)
     case OP_ENTEREVAL:
        scalarkids(o);
        break;
-    case OP_REQUIRE:
-       /* all requires must return a boolean value */
-       o->op_flags &= ~OPf_WANT;
-       /* FALL THROUGH */
     case OP_SCALAR:
        return scalar(o);
-    case OP_SPLIT:
-       if ((kid = cLISTOPo->op_first) && kid->op_type == OP_PUSHRE) {
-           if (!kPMOP->op_pmreplrootu.op_pmreplroot)
-               deprecate_old("implicit split to @_");
-       }
-       break;
     }
-    if (useless && ckWARN(WARN_VOID))
-       Perl_warner(aTHX_ packWARN(WARN_VOID), "Useless use of %s in void context", useless);
+    if (useless)
+       Perl_ck_warner(aTHX_ packWARN(WARN_VOID), "Useless use of %s in void context", useless);
     return o;
 }
 
@@ -1267,28 +1300,27 @@ Perl_list(pTHX_ OP *o)
     case OP_LEAVETRY:
        kid = cLISTOPo->op_first;
        list(kid);
-       while ((kid = kid->op_sibling)) {
-           if (kid->op_sibling)
-               scalarvoid(kid);
-           else
+       kid = kid->op_sibling;
+    do_kids:
+       while (kid) {
+           OP *sib = kid->op_sibling;
+           if (sib && kid->op_type != OP_LEAVEWHEN) {
+               if (sib->op_type == OP_BREAK && sib->op_flags & OPf_SPECIAL) {
+                   list(kid);
+                   scalarvoid(sib);
+                   break;
+               } else
+                   scalarvoid(kid);
+           } else
                list(kid);
+           kid = sib;
        }
        PL_curcop = &PL_compiling;
        break;
     case OP_SCOPE:
     case OP_LINESEQ:
-       for (kid = cLISTOPo->op_first; kid; kid = kid->op_sibling) {
-           if (kid->op_sibling)
-               scalarvoid(kid);
-           else
-               list(kid);
-       }
-       PL_curcop = &PL_compiling;
-       break;
-    case OP_REQUIRE:
-       /* all requires must return a boolean value */
-       o->op_flags &= ~OPf_WANT;
-       return scalar(o);
+       kid = cLISTOPo->op_first;
+       goto do_kids;
     }
     return o;
 }
@@ -1553,12 +1585,17 @@ Perl_mod(pTHX_ OP *o, I32 type)
     case OP_DBSTATE:
        PL_modcount = RETURN_UNLIMITED_NUMBER;
        break;
+    case OP_AV2ARYLEN:
+       PL_hints |= HINT_BLOCK_SCOPE;
+       if (type == OP_LEAVESUBLV)
+           o->op_private |= OPpMAYBE_LVSUB;
+       PL_modcount++;
+       break;
     case OP_RV2SV:
        ref(cUNOPo->op_first, o->op_type);
        localize = 1;
        /* FALL THROUGH */
     case OP_GV:
-    case OP_AV2ARYLEN:
        PL_hints |= HINT_BLOCK_SCOPE;
     case OP_SASSIGN:
     case OP_ANDASSIGN:
@@ -1679,10 +1716,8 @@ Perl_mod(pTHX_ OP *o, I32 type)
        case 0:
            break;
        case -1:
-           if (ckWARN(WARN_SYNTAX)) {
-               Perl_warner(aTHX_ packWARN(WARN_SYNTAX),
-                   "Useless localization of %s", OP_DESC(o));
-           }
+           Perl_ck_warner(aTHX_ packWARN(WARN_SYNTAX),
+                          "Useless localization of %s", OP_DESC(o));
        }
     }
     else if (type != OP_GREPSTART && type != OP_ENTERSUB
@@ -2290,7 +2325,7 @@ STATIC OP *
 S_newDEFSVOP(pTHX)
 {
     dVAR;
-    const PADOFFSET offset = pad_findmy("$_");
+    const PADOFFSET offset = Perl_pad_findmy(aTHX_ STR_WITH_LEN("$_"), 0);
     if (offset == NOT_IN_PAD || PAD_COMPNAME_FLAGS_isOUR(offset)) {
        return newSVREF(newGVOP(OP_GV, 0, PL_defgv));
     }
@@ -2772,7 +2807,7 @@ Perl_token_getmad(pTHX_ TOKEN* tk, OP* o, char slot)
     /* faked up qw list? */
     if (slot == '(' &&
        tm->mad_type == MAD_SV &&
-       SvPVX((const SV *)tm->mad_val)[0] == 'q')
+       SvPVX((SV *)tm->mad_val)[0] == 'q')
            slot = 'x';
 
     if (o) {
@@ -2929,7 +2964,7 @@ Perl_newMADsv(pTHX_ char key, SV* sv)
 }
 
 MADPROP *
-Perl_newMADPROP(pTHX_ char key, char type, const void* val, I32 vlen)
+Perl_newMADPROP(pTHX_ char key, char type, void* val, I32 vlen)
 {
     MADPROP *mp;
     Newxz(mp, 1, MADPROP);
@@ -2995,6 +3030,8 @@ Perl_newLISTOP(pTHX_ I32 type, I32 flags, OP *first, OP *last)
     dVAR;
     LISTOP *listop;
 
+    assert((PL_opargs[type] & OA_CLASS_MASK) == OA_LISTOP);
+
     NewOp(1101, listop, 1, LISTOP);
 
     listop->op_type = (OPCODE)type;
@@ -3028,6 +3065,12 @@ Perl_newOP(pTHX_ I32 type, I32 flags)
 {
     dVAR;
     OP *o;
+
+    assert((PL_opargs[type] & OA_CLASS_MASK) == OA_BASEOP
+       || (PL_opargs[type] & OA_CLASS_MASK) == OA_BASEOP_OR_UNOP
+       || (PL_opargs[type] & OA_CLASS_MASK) == OA_FILESTATOP
+       || (PL_opargs[type] & OA_CLASS_MASK) == OA_LOOPEXOP);
+
     NewOp(1101, o, 1, OP);
     o->op_type = (OPCODE)type;
     o->op_ppaddr = PL_ppaddr[type];
@@ -3051,6 +3094,14 @@ Perl_newUNOP(pTHX_ I32 type, I32 flags, OP *first)
     dVAR;
     UNOP *unop;
 
+    assert((PL_opargs[type] & OA_CLASS_MASK) == OA_UNOP
+       || (PL_opargs[type] & OA_CLASS_MASK) == OA_BASEOP_OR_UNOP
+       || (PL_opargs[type] & OA_CLASS_MASK) == OA_FILESTATOP
+       || (PL_opargs[type] & OA_CLASS_MASK) == OA_LOOPEXOP
+       || type == OP_SASSIGN
+       || type == OP_ENTERTRY
+       || type == OP_NULL );
+
     if (!first)
        first = newOP(OP_STUB, 0);
     if (PL_opargs[type] & OA_MARK)
@@ -3074,6 +3125,10 @@ Perl_newBINOP(pTHX_ I32 type, I32 flags, OP *first, OP *last)
 {
     dVAR;
     BINOP *binop;
+
+    assert((PL_opargs[type] & OA_CLASS_MASK) == OA_BINOP
+       || type == OP_SASSIGN || type == OP_NULL );
+
     NewOp(1101, binop, 1, BINOP);
 
     if (!first)
@@ -3347,6 +3402,7 @@ S_pmtrans(pTHX_ OP *o, OP *expr, OP *repl)
        SvREFCNT_dec(PAD_SVl(cPADOPo->op_padix));
        PAD_SETSV(cPADOPo->op_padix, swash);
        SvPADTMP_on(swash);
+       SvREADONLY_on(swash);
 #else
        cSVOPo->op_sv = swash;
 #endif
@@ -3443,12 +3499,10 @@ S_pmtrans(pTHX_ OP *o, OP *expr, OP *repl)
        }
     }
 
-    if(ckWARN(WARN_MISC)) {
-        if(del && rlen == tlen) {
-            Perl_warner(aTHX_ packWARN(WARN_MISC), "Useless use of /d modifier in transliteration operator"); 
-        } else if(rlen > tlen) {
-            Perl_warner(aTHX_ packWARN(WARN_MISC), "Replacement list is longer than search list");
-        } 
+    if(del && rlen == tlen) {
+       Perl_ck_warner(aTHX_ packWARN(WARN_MISC), "Useless use of /d modifier in transliteration operator"); 
+    } else if(rlen > tlen) {
+       Perl_ck_warner(aTHX_ packWARN(WARN_MISC), "Replacement list is longer than search list");
     }
 
     if (grows)
@@ -3470,6 +3524,8 @@ Perl_newPMOP(pTHX_ I32 type, I32 flags)
     dVAR;
     PMOP *pmop;
 
+    assert((PL_opargs[type] & OA_CLASS_MASK) == OA_PMOP);
+
     NewOp(1101, pmop, 1, PMOP);
     pmop->op_type = (OPCODE)type;
     pmop->op_ppaddr = PL_ppaddr[type];
@@ -3714,6 +3770,10 @@ Perl_newSVOP(pTHX_ I32 type, I32 flags, SV *sv)
 
     PERL_ARGS_ASSERT_NEWSVOP;
 
+    assert((PL_opargs[type] & OA_CLASS_MASK) == OA_SVOP
+       || (PL_opargs[type] & OA_CLASS_MASK) == OA_PVOP_OR_SVOP
+       || (PL_opargs[type] & OA_CLASS_MASK) == OA_FILESTATOP);
+
     NewOp(1101, svop, 1, SVOP);
     svop->op_type = (OPCODE)type;
     svop->op_ppaddr = PL_ppaddr[type];
@@ -3736,6 +3796,10 @@ Perl_newPADOP(pTHX_ I32 type, I32 flags, SV *sv)
 
     PERL_ARGS_ASSERT_NEWPADOP;
 
+    assert((PL_opargs[type] & OA_CLASS_MASK) == OA_SVOP
+       || (PL_opargs[type] & OA_CLASS_MASK) == OA_PVOP_OR_SVOP
+       || (PL_opargs[type] & OA_CLASS_MASK) == OA_FILESTATOP);
+
     NewOp(1101, padop, 1, PADOP);
     padop->op_type = (OPCODE)type;
     padop->op_ppaddr = PL_ppaddr[type];
@@ -3774,6 +3838,10 @@ Perl_newPVOP(pTHX_ I32 type, I32 flags, char *pv)
 {
     dVAR;
     PVOP *pvop;
+
+    assert((PL_opargs[type] & OA_CLASS_MASK) == OA_PVOP_OR_SVOP
+       || (PL_opargs[type] & OA_CLASS_MASK) == OA_LOOPEXOP);
+
     NewOp(1101, pvop, 1, PVOP);
     pvop->op_type = (OPCODE)type;
     pvop->op_ppaddr = PL_ppaddr[type];
@@ -3827,6 +3895,18 @@ Perl_package(pTHX_ OP *o)
 #endif
 }
 
+void
+Perl_package_version( pTHX_ OP *v )
+{
+    dVAR;
+    U32 savehints = PL_hints;
+    PERL_ARGS_ASSERT_PACKAGE_VERSION;
+    PL_hints &= ~HINT_STRICT_VARS;
+    sv_setsv( GvSV(gv_fetchpvs("VERSION", GV_ADDMULTI, SVt_PV)), cSVOPx(v)->op_sv );
+    PL_hints = savehints;
+    op_free(v);
+}
+
 #ifdef PERL_MAD
 OP*
 #else
@@ -3865,7 +3945,7 @@ Perl_utilize(pTHX_ int aver, I32 floor, OP *version, OP *idop, OP *arg)
            SV *meth;
 
            if (version->op_type != OP_CONST || !SvNIOKp(vesv))
-               Perl_croak(aTHX_ "Version number must be constant number");
+               Perl_croak(aTHX_ "Version number must be constant number");
 
            /* Make copy of idop so we don't free it twice */
            pack = newSVOP(OP_CONST, 0, newSVsv(((SVOP*)idop)->op_sv));
@@ -3963,7 +4043,11 @@ PERL_LOADMOD_DENY, PERL_LOADMOD_NOIMPORT, or PERL_LOADMOD_IMPORT_OPS
 (or 0 for no flags). ver, if specified, provides version semantics
 similar to C<use Foo::Bar VERSION>.  The optional trailing SV*
 arguments can be used to specify arguments to the module's import()
-method, similar to C<use Foo::Bar VERSION LIST>.
+method, similar to C<use Foo::Bar VERSION LIST>.  They must be
+terminated with a final NULL pointer.  Note that this list can only
+be omitted when the PERL_LOADMOD_NOIMPORT flag has been used.
+Otherwise at least a single NULL pointer to designate the default
+import list is required.
 
 =cut */
 
@@ -4201,7 +4285,7 @@ Perl_newASSIGNOP(pTHX_ I32 flags, OP *left, I32 optype, OP *right)
                    || left->op_type == OP_PADHV
                    || left->op_type == OP_PADANY))
        {
-           maybe_common_vars = FALSE;
+           if (left->op_type == OP_PADSV) maybe_common_vars = FALSE;
            if (left->op_private & OPpPAD_STATE) {
                /* All single variable list context state assignments, hence
                   state ($a) = ...
@@ -4333,7 +4417,7 @@ Perl_newASSIGNOP(pTHX_ I32 flags, OP *left, I32 optype, OP *right)
                      ((LISTOP*)right)->op_last->op_type == OP_CONST)
                    {
                        SV *sv = ((SVOP*)((LISTOP*)right)->op_last)->op_sv;
-                       if (SvIVX(sv) == 0)
+                       if (SvIOK(sv) && SvIVX(sv) == 0)
                            sv_setiv(sv, PL_modcount+1);
                    }
                }
@@ -4515,6 +4599,8 @@ S_new_logop(pTHX_ I32 type, I32 flags, OP** firstp, OP** otherp)
     if (type == OP_XOR)                /* Not short circuit, but here by precedence. */
        return newBINOP(type, flags, scalar(first), scalar(other));
 
+    assert((PL_opargs[type] & OA_CLASS_MASK) == OA_LOGOP);
+
     scalarboolean(first);
     /* optimize AND and OR ops that have NOTs as children */
     if (first->op_type == OP_NOT
@@ -4538,8 +4624,8 @@ S_new_logop(pTHX_ I32 type, I32 flags, OP** firstp, OP** otherp)
     if ((cstop = search_const(first))) {
        if (cstop->op_private & OPpCONST_STRICT)
            no_bareword_allowed(cstop);
-       else if ((cstop->op_private & OPpCONST_BARE) && ckWARN(WARN_BAREWORD))
-               Perl_warner(aTHX_ packWARN(WARN_BAREWORD), "Bareword found in conditional");
+       else if ((cstop->op_private & OPpCONST_BARE))
+               Perl_ck_warner(aTHX_ packWARN(WARN_BAREWORD), "Bareword found in conditional");
        if ((type == OP_AND &&  SvTRUE(((SVOP*)cstop)->op_sv)) ||
            (type == OP_OR  && !SvTRUE(((SVOP*)cstop)->op_sv)) ||
            (type == OP_DOR && !SvOK(((SVOP*)cstop)->op_sv))) {
@@ -4553,6 +4639,8 @@ S_new_logop(pTHX_ I32 type, I32 flags, OP** firstp, OP** otherp)
                return newop;
            }
            op_free(first);
+           if (other->op_type == OP_LEAVE)
+               other = newUNOP(OP_NULL, OPf_SPECIAL, other);
            return other;
        }
        else {
@@ -4567,11 +4655,10 @@ S_new_logop(pTHX_ I32 type, I32 flags, OP** firstp, OP** otherp)
            if ((o2->op_type == OP_PADSV || o2->op_type == OP_PADAV
                        || o2->op_type == OP_PADHV)
                && o2->op_private & OPpLVAL_INTRO
-               && !(o2->op_private & OPpPAD_STATE)
-               && ckWARN(WARN_DEPRECATED))
+               && !(o2->op_private & OPpPAD_STATE))
            {
-               Perl_warner(aTHX_ packWARN(WARN_DEPRECATED),
-                           "Deprecated use of my() in false conditional");
+               Perl_ck_warner_d(aTHX_ packWARN(WARN_DEPRECATED),
+                                "Deprecated use of my() in false conditional");
            }
 
            *otherp = NULL;
@@ -4690,6 +4777,8 @@ Perl_newCONDOP(pTHX_ I32 flags, OP *first, OP *trueop, OP *falseop)
            op_free(first);
            op_free(dead);
        }
+       if (live->op_type == OP_LEAVE)
+           live = newUNOP(OP_NULL, OPf_SPECIAL, live);
        return live;
     }
     NewOp(1101, logop, 1, LOGOP);
@@ -4781,7 +4870,9 @@ Perl_newLOOPOP(pTHX_ I32 flags, I32 debuggable, OP *expr, OP *block)
     if (expr) {
        if (once && expr->op_type == OP_CONST && !SvTRUE(((SVOP*)expr)->op_sv))
            return block;       /* do {} while 0 does once */
-       if (expr->op_type == OP_READLINE || expr->op_type == OP_GLOB
+       if (expr->op_type == OP_READLINE
+           || expr->op_type == OP_READDIR
+           || expr->op_type == OP_GLOB
            || (expr->op_type == OP_NULL && expr->op_targ == OP_GLOB)) {
            expr = newUNOP(OP_DEFINED, 0,
                newASSIGNOP(0, newDEFSVOP(), 0, expr) );
@@ -4790,7 +4881,7 @@ Perl_newLOOPOP(pTHX_ I32 flags, I32 debuggable, OP *expr, OP *block)
            const OP * const k2 = k1 ? k1->op_sibling : NULL;
            switch (expr->op_type) {
              case OP_NULL:
-               if (k2 && k2->op_type == OP_READLINE
+               if (k2 && (k2->op_type == OP_READLINE || k2->op_type == OP_READDIR)
                      && (k2->op_flags & OPf_STACKED)
                      && ((k1->op_flags & OPf_WANT) == OPf_WANT_SCALAR))
                    expr = newUNOP(OP_DEFINED, 0, expr);
@@ -4843,7 +4934,9 @@ whileline, OP *expr, OP *block, OP *cont, I32 has_my)
     PERL_UNUSED_ARG(debuggable);
 
     if (expr) {
-       if (expr->op_type == OP_READLINE || expr->op_type == OP_GLOB
+       if (expr->op_type == OP_READLINE
+         || expr->op_type == OP_READDIR
+         || expr->op_type == OP_GLOB
                     || (expr->op_type == OP_NULL && expr->op_targ == OP_GLOB)) {
            expr = newUNOP(OP_DEFINED, 0,
                newASSIGNOP(0, newDEFSVOP(), 0, expr) );
@@ -4852,7 +4945,7 @@ whileline, OP *expr, OP *block, OP *cont, I32 has_my)
            const OP * const k2 = (k1) ? k1->op_sibling : NULL;
            switch (expr->op_type) {
              case OP_NULL:
-               if (k2 && k2->op_type == OP_READLINE
+               if (k2 && (k2->op_type == OP_READLINE || k2->op_type == OP_READDIR)
                      && (k2->op_flags & OPf_STACKED)
                      && ((k1->op_flags & OPf_WANT) == OPf_WANT_SCALAR))
                    expr = newUNOP(OP_DEFINED, 0, expr);
@@ -4982,7 +5075,7 @@ Perl_newFOROP(pTHX_ I32 flags, char *label, line_t forline, OP *sv, OP *expr, OP
        }
     }
     else {
-        const PADOFFSET offset = pad_findmy("$_");
+        const PADOFFSET offset = Perl_pad_findmy(aTHX_ STR_WITH_LEN("$_"), 0);
        if (offset == NOT_IN_PAD || PAD_COMPNAME_FLAGS_isOUR(offset)) {
            sv = newGVOP(OP_GV, 0, PL_defgv);
        }
@@ -5064,6 +5157,8 @@ Perl_newLOOPEX(pTHX_ I32 type, OP *label)
 
     PERL_ARGS_ASSERT_NEWLOOPEX;
 
+    assert((PL_opargs[type] & OA_CLASS_MASK) == OA_LOOPEXOP);
+
     if (type != OP_GOTO || label->op_type == OP_CONST) {
        /* "last()" means "last" */
        if (label->op_type == OP_STUB && (label->op_flags & OPf_PARENS))
@@ -5193,6 +5288,7 @@ S_looks_like_bool(pTHX_ const OP *o)
             && looks_like_bool(cLOGOPo->op_first->op_sibling));
 
        case OP_NULL:
+       case OP_SCALAR:
            return (
                o->op_flags & OPf_KIDS
            && looks_like_bool(cUNOPo->op_first));
@@ -5224,6 +5320,8 @@ S_looks_like_bool(pTHX_ const OP *o)
        case OP_DEFINED: case OP_EXISTS:
        case OP_MATCH:   case OP_EOF:
 
+       case OP_FLOP:
+
            return TRUE;
        
        case OP_CONST:
@@ -5234,11 +5332,6 @@ S_looks_like_bool(pTHX_ const OP *o)
                return TRUE;
            else
                return FALSE;
-               
-       case OP_FLOP:
-           /* Detect "..." flip-flop operator */
-           if (cUNOPo->op_first->op_flags & OPf_SPECIAL)
-               return TRUE;
 
        /* FALL THROUGH */
        default:
@@ -5524,7 +5617,6 @@ CV *
 Perl_newATTRSUB(pTHX_ I32 floor, OP *o, OP *proto, OP *attrs, OP *block)
 {
     dVAR;
-    const char *aname;
     GV *gv;
     const char *ps;
     STRLEN ps_len;
@@ -5540,6 +5632,7 @@ Perl_newATTRSUB(pTHX_ I32 floor, OP *o, OP *proto, OP *attrs, OP *block)
           || PL_madskills)
        ? GV_ADDMULTI : GV_ADDMULTI | GV_NOINIT;
     const char * const name = o ? SvPV_nolen_const(cSVOPo->op_sv) : NULL;
+    bool has_name;
 
     if (proto) {
        assert(proto->op_type == OP_CONST);
@@ -5548,20 +5641,23 @@ Perl_newATTRSUB(pTHX_ I32 floor, OP *o, OP *proto, OP *attrs, OP *block)
     else
        ps = NULL;
 
-    if (!name && PERLDB_NAMEANON && CopLINE(PL_curcop)) {
+    if (name) {
+       gv = gv_fetchsv(cSVOPo->op_sv, gv_fetch_flags, SVt_PVCV);
+       has_name = TRUE;
+    } else if (PERLDB_NAMEANON && CopLINE(PL_curcop)) {
        SV * const sv = sv_newmortal();
        Perl_sv_setpvf(aTHX_ sv, "%s[%s:%"IVdf"]",
                       PL_curstash ? "__ANON__" : "__ANON__::__ANON__",
                       CopFILE(PL_curcop), (IV)CopLINE(PL_curcop));
-       aname = SvPVX_const(sv);
+       gv = gv_fetchsv(sv, gv_fetch_flags, SVt_PVCV);
+       has_name = TRUE;
+    } else if (PL_curstash) {
+       gv = gv_fetchpvs("__ANON__", gv_fetch_flags, SVt_PVCV);
+       has_name = FALSE;
+    } else {
+       gv = gv_fetchpvs("__ANON__::__ANON__", gv_fetch_flags, SVt_PVCV);
+       has_name = FALSE;
     }
-    else
-       aname = NULL;
-
-    gv = name ? gv_fetchsv(cSVOPo->op_sv, gv_fetch_flags, SVt_PVCV)
-       : gv_fetchpv(aname ? aname
-                    : (PL_curstash ? "__ANON__" : "__ANON__::__ANON__"),
-                    gv_fetch_flags, SVt_PVCV);
 
     if (!PL_madskills) {
        if (o)
@@ -5576,10 +5672,9 @@ Perl_newATTRSUB(pTHX_ I32 floor, OP *o, OP *proto, OP *attrs, OP *block)
                                           maximum a prototype before. */
        if (SvTYPE(gv) > SVt_NULL) {
            if (!SvPOK((const SV *)gv)
-               && !(SvIOK((const SV *)gv) && SvIVX((const SV *)gv) == -1)
-               && ckWARN_d(WARN_PROTOTYPE))
+               && !(SvIOK((const SV *)gv) && SvIVX((const SV *)gv) == -1))
            {
-               Perl_warner(aTHX_ packWARN(WARN_PROTOTYPE), "Runaway prototype");
+               Perl_ck_warner_d(aTHX_ packWARN(WARN_PROTOTYPE), "Runaway prototype");
            }
            cv_ckproto_len((const CV *)gv, NULL, ps, ps_len);
        }
@@ -5623,7 +5718,9 @@ Perl_newATTRSUB(pTHX_ I32 floor, OP *o, OP *proto, OP *attrs, OP *block)
                 )&& !attrs) {
                if (CvFLAGS(PL_compcv)) {
                    /* might have had built-in attrs applied */
-                   CvFLAGS(cv) |= (CvFLAGS(PL_compcv) & CVf_BUILTIN_ATTRS);
+                   if (CvLVALUE(PL_compcv) && ! CvLVALUE(cv) && ckWARN(WARN_MISC))
+                       Perl_warner(aTHX_ packWARN(WARN_MISC), "lvalue attribute ignored after the subroutine has been defined");
+                   CvFLAGS(cv) |= (CvFLAGS(PL_compcv) & CVf_BUILTIN_ATTRS & ~CVf_LVALUE);
                }
                /* just a "sub foo;" when &foo is already defined */
                SAVEFREESV(PL_compcv);
@@ -5685,69 +5782,35 @@ Perl_newATTRSUB(pTHX_ I32 floor, OP *o, OP *proto, OP *attrs, OP *block)
        PL_compcv = NULL;
        goto done;
     }
-    if (attrs) {
-       HV *stash;
-       SV *rcv;
-
-       /* Need to do a C<use attributes $stash_of_cv,\&cv,@attrs>
-        * before we clobber PL_compcv.
-        */
-       if (cv && (!block
+    if (cv) {                          /* must reuse cv if autoloaded */
+       /* transfer PL_compcv to cv */
+       if (block
 #ifdef PERL_MAD
-                   || block->op_type == OP_NULL
+                  && block->op_type != OP_NULL
 #endif
-                   )) {
-           rcv = MUTABLE_SV(cv);
-           /* Might have had built-in attributes applied -- propagate them. */
-           CvFLAGS(cv) |= (CvFLAGS(PL_compcv) & CVf_BUILTIN_ATTRS);
-           if (CvGV(cv) && GvSTASH(CvGV(cv)))
-               stash = GvSTASH(CvGV(cv));
-           else if (CvSTASH(cv))
-               stash = CvSTASH(cv);
-           else
-               stash = PL_curstash;
+       ) {
+           cv_flags_t existing_builtin_attrs = CvFLAGS(cv) & CVf_BUILTIN_ATTRS;
+           cv_undef(cv);
+           CvFLAGS(cv) = CvFLAGS(PL_compcv) | existing_builtin_attrs;
+           if (!CvWEAKOUTSIDE(cv))
+               SvREFCNT_dec(CvOUTSIDE(cv));
+           CvOUTSIDE(cv) = CvOUTSIDE(PL_compcv);
+           CvOUTSIDE_SEQ(cv) = CvOUTSIDE_SEQ(PL_compcv);
+           CvOUTSIDE(PL_compcv) = 0;
+           CvPADLIST(cv) = CvPADLIST(PL_compcv);
+           CvPADLIST(PL_compcv) = 0;
+           /* inner references to PL_compcv must be fixed up ... */
+           pad_fixup_inner_anons(CvPADLIST(cv), PL_compcv, cv);
+           if (PERLDB_INTER)/* Advice debugger on the new sub. */
+             ++PL_sub_generation;
        }
        else {
-           /* possibly about to re-define existing subr -- ignore old cv */
-           rcv = MUTABLE_SV(PL_compcv);
-           if (name && GvSTASH(gv))
-               stash = GvSTASH(gv);
-           else
-               stash = PL_curstash;
-       }
-       apply_attrs(stash, rcv, attrs, FALSE);
-    }
-    if (cv) {                          /* must reuse cv if autoloaded */
-       if (
-#ifdef PERL_MAD
-           (
-#endif
-            !block
-#ifdef PERL_MAD
-            || block->op_type == OP_NULL) && !PL_madskills
-#endif
-            ) {
-           /* got here with just attrs -- work done, so bug out */
-           SAVEFREESV(PL_compcv);
-           goto done;
+           /* Might have had built-in attributes applied -- propagate them. */
+           CvFLAGS(cv) |= (CvFLAGS(PL_compcv) & CVf_BUILTIN_ATTRS);
        }
-       /* transfer PL_compcv to cv */
-       cv_undef(cv);
-       CvFLAGS(cv) = CvFLAGS(PL_compcv);
-       if (!CvWEAKOUTSIDE(cv))
-           SvREFCNT_dec(CvOUTSIDE(cv));
-       CvOUTSIDE(cv) = CvOUTSIDE(PL_compcv);
-       CvOUTSIDE_SEQ(cv) = CvOUTSIDE_SEQ(PL_compcv);
-       CvOUTSIDE(PL_compcv) = 0;
-       CvPADLIST(cv) = CvPADLIST(PL_compcv);
-       CvPADLIST(PL_compcv) = 0;
-       /* inner references to PL_compcv must be fixed up ... */
-       pad_fixup_inner_anons(CvPADLIST(cv), PL_compcv, cv);
        /* ... before we throw it away */
        SvREFCNT_dec(PL_compcv);
        PL_compcv = cv;
-       if (PERLDB_INTER)/* Advice debugger on the new sub. */
-         ++PL_sub_generation;
     }
     else {
        cv = PL_compcv;
@@ -5756,16 +5819,24 @@ Perl_newATTRSUB(pTHX_ I32 floor, OP *o, OP *proto, OP *attrs, OP *block)
            if (PL_madskills) {
                if (strEQ(name, "import")) {
                    PL_formfeed = MUTABLE_SV(cv);
-                   Perl_warner(aTHX_ packWARN(WARN_VOID), "%lx\n", (long)cv);
+                   /* diag_listed_as: SKIPME */
+                   Perl_warner(aTHX_ packWARN(WARN_VOID), "0x%"UVxf"\n", PTR2UV(cv));
                }
            }
            GvCVGEN(gv) = 0;
             mro_method_changed_in(GvSTASH(gv)); /* sub Foo::bar { (shift)+1 } */
        }
     }
-    CvGV(cv) = gv;
-    CvFILE_set_from_cop(cv, PL_curcop);
-    CvSTASH(cv) = PL_curstash;
+    if (!CvGV(cv)) {
+       CvGV(cv) = gv;
+       CvFILE_set_from_cop(cv, PL_curcop);
+       CvSTASH(cv) = PL_curstash;
+    }
+    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;
+       apply_attrs(stash, MUTABLE_SV(cv), attrs, FALSE);
+    }
 
     if (ps)
        sv_setpvn(MUTABLE_SV(cv), ps, ps_len);
@@ -5835,7 +5906,7 @@ Perl_newATTRSUB(pTHX_ I32 floor, OP *o, OP *proto, OP *attrs, OP *block)
            CvCONST_on(cv);
     }
 
-    if (name || aname) {
+    if (has_name) {
        if (PERLDB_SUBLINE && PL_curstash != PL_debstash) {
            SV * const sv = newSV(0);
            SV * const tmpstr = sv_newmortal();
@@ -5850,7 +5921,7 @@ Perl_newATTRSUB(pTHX_ I32 floor, OP *o, OP *proto, OP *attrs, OP *block)
            (void)hv_store(GvHV(PL_DBsub), SvPVX_const(tmpstr),
                    SvCUR(tmpstr), sv, 0);
            hv = GvHVn(db_postponed);
-           if (HvFILL(hv) > 0 && hv_exists(hv, SvPVX_const(tmpstr), SvCUR(tmpstr))) {
+           if (HvTOTALKEYS(hv) > 0 && hv_exists(hv, SvPVX_const(tmpstr), SvCUR(tmpstr))) {
                CV * const pcv = GvCV(db_postponed);
                if (pcv) {
                    dSP;
@@ -5916,18 +5987,18 @@ S_process_special_blocks(pTHX_ const char *const fullname, GV *const gv,
                return;
        } else if (*name == 'C') {
            if (strEQ(name, "CHECK")) {
-               if (PL_main_start && ckWARN(WARN_VOID))
-                   Perl_warner(aTHX_ packWARN(WARN_VOID),
-                               "Too late to run CHECK block");
+               if (PL_main_start)
+                   Perl_ck_warner(aTHX_ packWARN(WARN_VOID),
+                                  "Too late to run CHECK block");
                Perl_av_create_and_unshift_one(aTHX_ &PL_checkav, MUTABLE_SV(cv));
            }
            else
                return;
        } else if (*name == 'I') {
            if (strEQ(name, "INIT")) {
-               if (PL_main_start && ckWARN(WARN_VOID))
-                   Perl_warner(aTHX_ packWARN(WARN_VOID),
-                               "Too late to run INIT block");
+               if (PL_main_start)
+                   Perl_ck_warner(aTHX_ packWARN(WARN_VOID),
+                                  "Too late to run INIT block");
                Perl_av_create_and_push(aTHX_ &PL_initav, MUTABLE_SV(cv));
            }
            else
@@ -6240,8 +6311,7 @@ Perl_oopsAV(pTHX_ OP *o)
        break;
 
     default:
-       if (ckWARN_d(WARN_INTERNAL))
-           Perl_warner(aTHX_ packWARN(WARN_INTERNAL), "oops: oopsAV");
+       Perl_ck_warner_d(aTHX_ packWARN(WARN_INTERNAL), "oops: oopsAV");
        break;
     }
     return o;
@@ -6269,8 +6339,7 @@ Perl_oopsHV(pTHX_ OP *o)
        break;
 
     default:
-       if (ckWARN_d(WARN_INTERNAL))
-           Perl_warner(aTHX_ packWARN(WARN_INTERNAL), "oops: oopsHV");
+       Perl_ck_warner_d(aTHX_ packWARN(WARN_INTERNAL), "oops: oopsHV");
        break;
     }
     return o;
@@ -6288,10 +6357,9 @@ Perl_newAVREF(pTHX_ OP *o)
        o->op_ppaddr = PL_ppaddr[OP_PADAV];
        return o;
     }
-    else if ((o->op_type == OP_RV2AV || o->op_type == OP_PADAV)
-               && ckWARN(WARN_DEPRECATED)) {
-       Perl_warner(aTHX_ packWARN(WARN_DEPRECATED),
-               "Using an array as a reference is deprecated");
+    else if ((o->op_type == OP_RV2AV || o->op_type == OP_PADAV)) {
+       Perl_ck_warner_d(aTHX_ packWARN(WARN_DEPRECATED),
+                      "Using an array as a reference is deprecated");
     }
     return newUNOP(OP_RV2AV, 0, scalar(o));
 }
@@ -6316,10 +6384,9 @@ Perl_newHVREF(pTHX_ OP *o)
        o->op_ppaddr = PL_ppaddr[OP_PADHV];
        return o;
     }
-    else if ((o->op_type == OP_RV2HV || o->op_type == OP_PADHV)
-               && ckWARN(WARN_DEPRECATED)) {
-       Perl_warner(aTHX_ packWARN(WARN_DEPRECATED),
-               "Using a hash as a reference is deprecated");
+    else if ((o->op_type == OP_RV2HV || o->op_type == OP_PADHV)) {
+       Perl_ck_warner_d(aTHX_ packWARN(WARN_DEPRECATED),
+                      "Using a hash as a reference is deprecated");
     }
     return newUNOP(OP_RV2HV, 0, scalar(o));
 }
@@ -6386,12 +6453,11 @@ Perl_ck_bitop(pTHX_ OP *o)
                (left->op_flags & OPf_PARENS) == 0) ||
            (OP_IS_NUMCOMPARE(right->op_type) &&
                (right->op_flags & OPf_PARENS) == 0))
-           if (ckWARN(WARN_PRECEDENCE))
-               Perl_warner(aTHX_ packWARN(WARN_PRECEDENCE),
-                       "Possible precedence problem on bitwise %c operator",
-                       o->op_type == OP_BIT_OR ? '|'
-                           : o->op_type == OP_BIT_AND ? '&' : '^'
-                       );
+           Perl_ck_warner(aTHX_ packWARN(WARN_PRECEDENCE),
+                          "Possible precedence problem on bitwise %c operator",
+                          o->op_type == OP_BIT_OR ? '|'
+                          : o->op_type == OP_BIT_AND ? '&' : '^'
+                          );
     }
     return o;
 }
@@ -6467,6 +6533,8 @@ Perl_ck_delete(pTHX_ OP *o)
            Perl_croak(aTHX_ "%s argument is not a HASH or ARRAY element or slice",
                  OP_DESC(o));
        }
+       if (kid->op_private & OPpLVAL_INTRO)
+           o->op_private |= OPpLVAL_INTRO;
        op_null(kid);
     }
     return o;
@@ -6540,8 +6608,6 @@ Perl_ck_eval(pTHX_ OP *o)
            /* establish postfix order */
            enter->op_next = (OP*)enter;
 
-           CHECKOP(OP_ENTERTRY, enter);
-
            o = prepend_elem(OP_LINESEQ, (OP*)enter, (OP*)kid);
            o->op_type = OP_LEAVETRY;
            o->op_ppaddr = PL_ppaddr[OP_LEAVETRY];
@@ -6681,17 +6747,6 @@ Perl_ck_rvconst(pTHX_ register OP *o)
                Perl_croak(aTHX_ "Constant is not %s reference", badtype);
            return o;
        }
-       else if ((o->op_type == OP_RV2HV || o->op_type == OP_RV2SV) &&
-               (PL_hints & HINT_STRICT_REFS) && SvPOK(kidsv)) {
-           /* If this is an access to a stash, disable "strict refs", because
-            * stashes aren't auto-vivified at compile-time (unless we store
-            * symbols in them), and we don't want to produce a run-time
-            * stricture error when auto-vivifying the stash. */
-           const char *s = SvPV_nolen(kidsv);
-           const STRLEN l = SvCUR(kidsv);
-           if (l > 1 && s[l-1] == ':' && s[l-2] == ':')
-               o->op_private &= ~HINT_STRICT_REFS;
-       }
        if ((o->op_private & HINT_STRICT_REFS) && (kid->op_private & OPpCONST_BARE)) {
            const char *badthing;
            switch (o->op_type) {
@@ -6860,20 +6915,19 @@ Perl_ck_fun(pTHX_ OP *o)
                break;
            case OA_AVREF:
                if ((type == OP_PUSH || type == OP_UNSHIFT)
-                   && !kid->op_sibling && ckWARN(WARN_SYNTAX))
-                   Perl_warner(aTHX_ packWARN(WARN_SYNTAX),
-                       "Useless use of %s with no values",
-                       PL_op_desc[type]);
+                   && !kid->op_sibling)
+                   Perl_ck_warner(aTHX_ packWARN(WARN_SYNTAX),
+                                  "Useless use of %s with no values",
+                                  PL_op_desc[type]);
 
                if (kid->op_type == OP_CONST &&
                    (kid->op_private & OPpCONST_BARE))
                {
                    OP * const newop = newAVREF(newGVOP(OP_GV, 0,
                        gv_fetchsv(((SVOP*)kid)->op_sv, GV_ADD, SVt_PVAV) ));
-                   if (ckWARN2(WARN_DEPRECATED, WARN_SYNTAX))
-                       Perl_warner(aTHX_ packWARN2(WARN_DEPRECATED, WARN_SYNTAX),
-                           "Array @%"SVf" missing the @ in argument %"IVdf" of %s()",
-                           SVfARG(((SVOP*)kid)->op_sv), (IV)numargs, PL_op_desc[type]);
+                   Perl_ck_warner_d(aTHX_ packWARN(WARN_DEPRECATED),
+                                  "Array @%"SVf" missing the @ in argument %"IVdf" of %s()",
+                                  SVfARG(((SVOP*)kid)->op_sv), (IV)numargs, PL_op_desc[type]);
 #ifdef PERL_MAD
                    op_getmad(kid,newop,'K');
 #else
@@ -6893,10 +6947,9 @@ Perl_ck_fun(pTHX_ OP *o)
                {
                    OP * const newop = newHVREF(newGVOP(OP_GV, 0,
                        gv_fetchsv(((SVOP*)kid)->op_sv, GV_ADD, SVt_PVHV) ));
-                   if (ckWARN2(WARN_DEPRECATED, WARN_SYNTAX))
-                       Perl_warner(aTHX_ packWARN2(WARN_DEPRECATED, WARN_SYNTAX),
-                           "Hash %%%"SVf" missing the %% in argument %"IVdf" of %s()",
-                           SVfARG(((SVOP*)kid)->op_sv), (IV)numargs, PL_op_desc[type]);
+                   Perl_ck_warner_d(aTHX_ packWARN(WARN_DEPRECATED),
+                                  "Hash %%%"SVf" missing the %% in argument %"IVdf" of %s()",
+                                  SVfARG(((SVOP*)kid)->op_sv), (IV)numargs, PL_op_desc[type]);
 #ifdef PERL_MAD
                    op_getmad(kid,newop,'K');
 #else
@@ -7152,10 +7205,10 @@ Perl_ck_grep(pTHX_ OP *o)
     if (o->op_flags & OPf_STACKED) {
        OP* k;
        o = ck_sort(o);
-        kid = cLISTOPo->op_first->op_sibling;
-       if (!cUNOPx(kid)->op_next)
-           Perl_croak(aTHX_ "panic: ck_grep");
-       for (k = cUNOPx(kid)->op_first; k; k = k->op_next) {
+        kid = cUNOPx(cLISTOPo->op_first->op_sibling)->op_first;
+       if (kid->op_type != OP_SCOPE && kid->op_type != OP_LEAVE)
+           return no_fh_allowed(o);
+       for (k = kid; k; k = k->op_next) {
            kid = k;
        }
        NewOp(1101, gwop, 1, LOGOP);
@@ -7183,7 +7236,7 @@ Perl_ck_grep(pTHX_ OP *o)
     gwop->op_flags |= OPf_KIDS;
     gwop->op_other = LINKLIST(kid);
     kid->op_next = (OP*)gwop;
-    offset = pad_findmy("$_");
+    offset = Perl_pad_findmy(aTHX_ STR_WITH_LEN("$_"), 0);
     if (offset == NOT_IN_PAD || PAD_COMPNAME_FLAGS_isOUR(offset)) {
        o->op_private = gwop->op_private = 0;
        gwop->op_targ = pad_alloc(type, SVs_PADTMP);
@@ -7232,7 +7285,7 @@ Perl_ck_defined(pTHX_ OP *o)              /* 19990527 MJD */
 {
     PERL_ARGS_ASSERT_CK_DEFINED;
 
-    if ((o->op_flags & OPf_KIDS) && ckWARN2(WARN_DEPRECATED, WARN_SYNTAX)) {
+    if ((o->op_flags & OPf_KIDS)) {
        switch (cUNOPo->op_first->op_type) {
        case OP_RV2AV:
            /* This is needed for
@@ -7242,22 +7295,17 @@ Perl_ck_defined(pTHX_ OP *o)            /* 19990527 MJD */
            break;                      /* Globals via GV can be undef */
        case OP_PADAV:
        case OP_AASSIGN:                /* Is this a good idea? */
-           Perl_warner(aTHX_ packWARN2(WARN_DEPRECATED, WARN_SYNTAX),
-                       "defined(@array) is deprecated");
-           Perl_warner(aTHX_ packWARN2(WARN_DEPRECATED, WARN_SYNTAX),
-                       "\t(Maybe you should just omit the defined()?)\n");
+           Perl_ck_warner_d(aTHX_ packWARN(WARN_DEPRECATED),
+                          "defined(@array) is deprecated");
+           Perl_ck_warner_d(aTHX_ packWARN(WARN_DEPRECATED),
+                          "\t(Maybe you should just omit the defined()?)\n");
        break;
        case OP_RV2HV:
-           /* This is needed for
-              if (defined %stash::)
-              to work.   Do not break Tk.
-              */
-           break;                      /* Globals via GV can be undef */
        case OP_PADHV:
-           Perl_warner(aTHX_ packWARN2(WARN_DEPRECATED, WARN_SYNTAX),
-                       "defined(%%hash) is deprecated");
-           Perl_warner(aTHX_ packWARN2(WARN_DEPRECATED, WARN_SYNTAX),
-                       "\t(Maybe you should just omit the defined()?)\n");
+           Perl_ck_warner_d(aTHX_ packWARN(WARN_DEPRECATED),
+                          "defined(%%hash) is deprecated");
+           Perl_ck_warner_d(aTHX_ packWARN(WARN_DEPRECATED),
+                          "\t(Maybe you should just omit the defined()?)\n");
            break;
        default:
            /* no warning */
@@ -7428,7 +7476,7 @@ Perl_ck_match(pTHX_ OP *o)
     PERL_ARGS_ASSERT_CK_MATCH;
 
     if (o->op_type != OP_QR && PL_compcv) {
-       const PADOFFSET offset = pad_findmy("$_");
+       const PADOFFSET offset = Perl_pad_findmy(aTHX_ STR_WITH_LEN("$_"), 0);
        if (offset != NOT_IN_PAD && !(PAD_COMPNAME_FLAGS_isOUR(offset))) {
            o->op_targ = offset;
            o->op_private |= OPpTARGET_MY;
@@ -7627,7 +7675,7 @@ Perl_ck_require(pTHX_ OP *o)
        return newop;
     }
 
-    return ck_fun(o);
+    return scalar(ck_fun(o));
 }
 
 OP *
@@ -7694,19 +7742,20 @@ Perl_ck_shift(pTHX_ OP *o)
 
     if (!(o->op_flags & OPf_KIDS)) {
        OP *argop;
-       /* FIXME - this can be refactored to reduce code in #ifdefs  */
+
+       if (!CvUNIQUE(PL_compcv)) {
+           o->op_flags |= OPf_SPECIAL;
+           return o;
+       }
+
+       argop = newUNOP(OP_RV2AV, 0, scalar(newGVOP(OP_GV, 0, PL_argvgv)));
 #ifdef PERL_MAD
        OP * const oldo = o;
-#else
-       op_free(o);
-#endif
-       argop = newUNOP(OP_RV2AV, 0,
-           scalar(newGVOP(OP_GV, 0, CvUNIQUE(PL_compcv) ? PL_argvgv : PL_defgv)));
-#ifdef PERL_MAD
        o = newUNOP(type, 0, scalar(argop));
        op_getmad(oldo,o,'O');
        return o;
 #else
+       op_free(o);
        return newUNOP(type, 0, scalar(argop));
 #endif
     }
@@ -7905,9 +7954,9 @@ Perl_ck_split(pTHX_ OP *o)
     kid->op_type = OP_PUSHRE;
     kid->op_ppaddr = PL_ppaddr[OP_PUSHRE];
     scalar(kid);
-    if (((PMOP *)kid)->op_pmflags & PMf_GLOBAL && ckWARN(WARN_REGEXP)) {
-      Perl_warner(aTHX_ packWARN(WARN_REGEXP),
-                  "Use of /g modifier is meaningless in split");
+    if (((PMOP *)kid)->op_pmflags & PMf_GLOBAL) {
+      Perl_ck_warner(aTHX_ packWARN(WARN_REGEXP),
+                    "Use of /g modifier is meaningless in split");
     }
 
     if (!kid->op_sibling)
@@ -7972,22 +8021,29 @@ Perl_ck_subr(pTHX_ OP *o)
     o->op_private |= OPpENTERSUB_HASTARG;
     for (cvop = o2; cvop->op_sibling; cvop = cvop->op_sibling) ;
     if (cvop->op_type == OP_RV2CV) {
-       SVOP* tmpop;
        o->op_private |= (cvop->op_private & OPpENTERSUB_AMPER);
        op_null(cvop);          /* disable rv2cv */
-       tmpop = (SVOP*)((UNOP*)cvop)->op_first;
-       if (tmpop->op_type == OP_GV && !(o->op_private & OPpENTERSUB_AMPER)) {
-           GV *gv = cGVOPx_gv(tmpop);
-           cv = GvCVu(gv);
-           if (!cv)
-               tmpop->op_private |= OPpEARLY_CV;
-           else {
-               if (SvPOK(cv)) {
-                   STRLEN len;
-                   namegv = CvANON(cv) ? gv : CvGV(cv);
-                   proto = SvPV(MUTABLE_SV(cv), len);
-                   proto_end = proto + len;
-               }
+       if (!(o->op_private & OPpENTERSUB_AMPER)) {
+           SVOP *tmpop = (SVOP*)((UNOP*)cvop)->op_first;
+           GV *gv = NULL;
+           switch (tmpop->op_type) {
+               case OP_GV: {
+                   gv = cGVOPx_gv(tmpop);
+                   cv = GvCVu(gv);
+                   if (!cv)
+                       tmpop->op_private |= OPpEARLY_CV;
+               } break;
+               case OP_CONST: {
+                   SV *sv = cSVOPx_sv(tmpop);
+                   if (SvROK(sv) && SvTYPE(SvRV(sv)) == SVt_PVCV)
+                       cv = (CV*)SvRV(sv);
+               } break;
+           }
+           if (cv && SvPOK(cv)) {
+               STRLEN len;
+               namegv = gv && CvANON(cv) ? gv : CvGV(cv);
+               proto = SvPV(MUTABLE_SV(cv), len);
+               proto_end = proto + len;
            }
        }
     }
@@ -8287,25 +8343,127 @@ OP *
 Perl_ck_each(pTHX_ OP *o)
 {
     dVAR;
-    OP *kid = cLISTOPo->op_first;
+    OP *kid = o->op_flags & OPf_KIDS ? cLISTOPo->op_first : NULL;
 
     PERL_ARGS_ASSERT_CK_EACH;
 
-    if (kid->op_type == OP_PADAV || kid->op_type == OP_RV2AV) {
-       const unsigned new_type = o->op_type == OP_EACH ? OP_AEACH
-           : o->op_type == OP_KEYS ? OP_AKEYS : OP_AVALUES;
-       o->op_type = new_type;
-       o->op_ppaddr = PL_ppaddr[new_type];
-    }
-    else if (!(kid->op_type == OP_PADHV || kid->op_type == OP_RV2HV
-              || (kid->op_type == OP_CONST && kid->op_private & OPpCONST_BARE)
-              )) {
-       bad_type(1, "hash or array", PL_op_desc[o->op_type], kid);
-       return o;
+    if (kid) {
+       if (kid->op_type == OP_PADAV || kid->op_type == OP_RV2AV) {
+           const unsigned new_type = o->op_type == OP_EACH ? OP_AEACH
+               : o->op_type == OP_KEYS ? OP_AKEYS : OP_AVALUES;
+           o->op_type = new_type;
+           o->op_ppaddr = PL_ppaddr[new_type];
+       }
+       else if (!(kid->op_type == OP_PADHV || kid->op_type == OP_RV2HV
+                   || (kid->op_type == OP_CONST && kid->op_private & OPpCONST_BARE)
+                 )) {
+           bad_type(1, "hash or array", PL_op_desc[o->op_type], kid);
+           return o;
+       }
     }
     return ck_fun(o);
 }
 
+/* caller is supposed to assign the return to the 
+   container of the rep_op var */
+STATIC OP *
+S_opt_scalarhv(pTHX_ OP *rep_op) {
+    dVAR;
+    UNOP *unop;
+
+    PERL_ARGS_ASSERT_OPT_SCALARHV;
+
+    NewOp(1101, unop, 1, UNOP);
+    unop->op_type = (OPCODE)OP_BOOLKEYS;
+    unop->op_ppaddr = PL_ppaddr[OP_BOOLKEYS];
+    unop->op_flags = (U8)(OPf_WANT_SCALAR | OPf_KIDS );
+    unop->op_private = (U8)(1 | ((OPf_WANT_SCALAR | OPf_KIDS) >> 8));
+    unop->op_first = rep_op;
+    unop->op_next = rep_op->op_next;
+    rep_op->op_next = (OP*)unop;
+    rep_op->op_flags|=(OPf_REF | OPf_MOD);
+    unop->op_sibling = rep_op->op_sibling;
+    rep_op->op_sibling = NULL;
+    /* unop->op_targ = pad_alloc(OP_BOOLKEYS, SVs_PADTMP); */
+    if (rep_op->op_type == OP_PADHV) { 
+        rep_op->op_flags &= ~OPf_WANT_SCALAR;
+        rep_op->op_flags |= OPf_WANT_LIST;
+    }
+    return (OP*)unop;
+}                        
+
+/* Checks if o acts as an in-place operator on an array. oright points to the
+ * beginning of the right-hand side. Returns the left-hand side of the
+ * assignment if o acts in-place, or NULL otherwise. */
+
+STATIC OP *
+S_is_inplace_av(pTHX_ OP *o, OP *oright) {
+    OP *o2;
+    OP *oleft = NULL;
+
+    PERL_ARGS_ASSERT_IS_INPLACE_AV;
+
+    if (!oright ||
+       (oright->op_type != OP_RV2AV && oright->op_type != OP_PADAV)
+       || oright->op_next != o
+       || (oright->op_private & OPpLVAL_INTRO)
+    )
+       return NULL;
+
+    /* o2 follows the chain of op_nexts through the LHS of the
+     * assign (if any) to the aassign op itself */
+    o2 = o->op_next;
+    if (!o2 || o2->op_type != OP_NULL)
+       return NULL;
+    o2 = o2->op_next;
+    if (!o2 || o2->op_type != OP_PUSHMARK)
+       return NULL;
+    o2 = o2->op_next;
+    if (o2 && o2->op_type == OP_GV)
+       o2 = o2->op_next;
+    if (!o2
+       || (o2->op_type != OP_PADAV && o2->op_type != OP_RV2AV)
+       || (o2->op_private & OPpLVAL_INTRO)
+    )
+       return NULL;
+    oleft = o2;
+    o2 = o2->op_next;
+    if (!o2 || o2->op_type != OP_NULL)
+       return NULL;
+    o2 = o2->op_next;
+    if (!o2 || o2->op_type != OP_AASSIGN
+           || (o2->op_flags & OPf_WANT) != OPf_WANT_VOID)
+       return NULL;
+
+    /* check that the sort is the first arg on RHS of assign */
+
+    o2 = cUNOPx(o2)->op_first;
+    if (!o2 || o2->op_type != OP_NULL)
+       return NULL;
+    o2 = cUNOPx(o2)->op_first;
+    if (!o2 || o2->op_type != OP_PUSHMARK)
+       return NULL;
+    if (o2->op_sibling != o)
+       return NULL;
+
+    /* check the array is the same on both sides */
+    if (oleft->op_type == OP_RV2AV) {
+       if (oright->op_type != OP_RV2AV
+           || !cUNOPx(oright)->op_first
+           || cUNOPx(oright)->op_first->op_type != OP_GV
+           || cGVOPx_gv(cUNOPx(oleft)->op_first) !=
+              cGVOPx_gv(cUNOPx(oright)->op_first)
+       )
+           return NULL;
+    }
+    else if (oright->op_type != OP_PADAV
+       || oright->op_targ != oleft->op_targ
+    )
+       return NULL;
+
+    return oleft;
+}
+
 /* A peephole optimizer.  We visit the ops in the order they're to execute.
  * See the comments at the top of this file for more details about when
  * peep() is called */
@@ -8492,12 +8650,67 @@ Perl_peep(pTHX_ register OP *o)
            }
 
            break;
+        
+        {
+            OP *fop;
+            OP *sop;
+            
+        case OP_NOT:
+            fop = cUNOP->op_first;
+            sop = NULL;
+            goto stitch_keys;
+            break;
 
-       case OP_MAPWHILE:
-       case OP_GREPWHILE:
-       case OP_AND:
+        case OP_AND:
        case OP_OR:
        case OP_DOR:
+            fop = cLOGOP->op_first;
+            sop = fop->op_sibling;
+           while (cLOGOP->op_other->op_type == OP_NULL)
+               cLOGOP->op_other = cLOGOP->op_other->op_next;
+           peep(cLOGOP->op_other); /* Recursive calls are not replaced by fptr calls */
+          
+          stitch_keys:     
+           o->op_opt = 1;
+            if ((fop->op_type == OP_PADHV || fop->op_type == OP_RV2HV)
+                || ( sop && 
+                     (sop->op_type == OP_PADHV || sop->op_type == OP_RV2HV)
+                    )
+            ){ 
+                OP * nop = o;
+                OP * lop = o;
+                if (!((nop->op_flags & OPf_WANT) == OPf_WANT_VOID)) {
+                    while (nop && nop->op_next) {
+                        switch (nop->op_next->op_type) {
+                            case OP_NOT:
+                            case OP_AND:
+                            case OP_OR:
+                            case OP_DOR:
+                                lop = nop = nop->op_next;
+                                break;
+                            case OP_NULL:
+                                nop = nop->op_next;
+                                break;
+                            default:
+                                nop = NULL;
+                                break;
+                        }
+                    }            
+                }
+                if ((lop->op_flags & OPf_WANT) == OPf_WANT_VOID) {
+                    if (fop->op_type == OP_PADHV || fop->op_type == OP_RV2HV) 
+                        cLOGOP->op_first = opt_scalarhv(fop);
+                    if (sop && (sop->op_type == OP_PADHV || sop->op_type == OP_RV2HV)) 
+                        cLOGOP->op_first->op_sibling = opt_scalarhv(sop);
+                }                                        
+            }                  
+            
+           
+           break;
+       }    
+       
+       case OP_MAPWHILE:
+       case OP_GREPWHILE:
        case OP_ANDASSIGN:
        case OP_ORASSIGN:
        case OP_DORASSIGN:
@@ -8691,62 +8904,8 @@ Perl_peep(pTHX_ register OP *o)
                oright = cUNOPx(oright)->op_sibling;
            }
 
-           if (!oright ||
-               (oright->op_type != OP_RV2AV && oright->op_type != OP_PADAV)
-               || oright->op_next != o
-               || (oright->op_private & OPpLVAL_INTRO)
-           )
-               break;
-
-           /* o2 follows the chain of op_nexts through the LHS of the
-            * assign (if any) to the aassign op itself */
-           o2 = o->op_next;
-           if (!o2 || o2->op_type != OP_NULL)
-               break;
-           o2 = o2->op_next;
-           if (!o2 || o2->op_type != OP_PUSHMARK)
-               break;
-           o2 = o2->op_next;
-           if (o2 && o2->op_type == OP_GV)
-               o2 = o2->op_next;
-           if (!o2
-               || (o2->op_type != OP_PADAV && o2->op_type != OP_RV2AV)
-               || (o2->op_private & OPpLVAL_INTRO)
-           )
-               break;
-           oleft = o2;
-           o2 = o2->op_next;
-           if (!o2 || o2->op_type != OP_NULL)
-               break;
-           o2 = o2->op_next;
-           if (!o2 || o2->op_type != OP_AASSIGN
-                   || (o2->op_flags & OPf_WANT) != OPf_WANT_VOID)
-               break;
-
-           /* check that the sort is the first arg on RHS of assign */
-
-           o2 = cUNOPx(o2)->op_first;
-           if (!o2 || o2->op_type != OP_NULL)
-               break;
-           o2 = cUNOPx(o2)->op_first;
-           if (!o2 || o2->op_type != OP_PUSHMARK)
-               break;
-           if (o2->op_sibling != o)
-               break;
-
-           /* check the array is the same on both sides */
-           if (oleft->op_type == OP_RV2AV) {
-               if (oright->op_type != OP_RV2AV
-                   || !cUNOPx(oright)->op_first
-                   || cUNOPx(oright)->op_first->op_type != OP_GV
-                   ||  cGVOPx_gv(cUNOPx(oleft)->op_first) !=
-                       cGVOPx_gv(cUNOPx(oright)->op_first)
-               )
-                   break;
-           }
-           else if (oright->op_type != OP_PADAV
-               || oright->op_targ != oleft->op_targ
-           )
+           oleft = is_inplace_av(o, oright);
+           if (!oleft)
                break;
 
            /* transfer MODishness etc from LHS arg to RHS arg */
@@ -8773,8 +8932,36 @@ Perl_peep(pTHX_ register OP *o)
        case OP_REVERSE: {
            OP *ourmark, *theirmark, *ourlast, *iter, *expushmark, *rv2av;
            OP *gvop = NULL;
+           OP *oleft, *oright;
            LISTOP *enter, *exlist;
 
+           /* @a = reverse @a */
+           if ((oright = cLISTOPo->op_first)
+                   && (oright->op_type == OP_PUSHMARK)
+                   && (oright = oright->op_sibling)
+                   && (oleft = is_inplace_av(o, oright))) {
+               OP *o2;
+
+               /* transfer MODishness etc from LHS arg to RHS arg */
+               oright->op_flags = oleft->op_flags;
+               o->op_private |= OPpREVERSE_INPLACE;
+
+               /* excise push->gv->rv2av->null->aassign */
+               o2 = o->op_next->op_next;
+               op_null(o2); /* PUSHMARK */
+               o2 = o2->op_next;
+               if (o2->op_type == OP_GV) {
+                   op_null(o2); /* GV */
+                   o2 = o2->op_next;
+               }
+               op_null(o2); /* RV2AV or PADAV */
+               o2 = o2->op_next->op_next;
+               op_null(o2); /* AASSIGN */
+
+               o->op_next = o2->op_next;
+               break;
+           }
+
            enter = (LISTOP *) o->op_next;
            if (!enter)
                break;
@@ -8972,6 +9159,7 @@ const_sv_xsub(pTHX_ CV* cv)
     if (items != 0) {
        NOOP;
 #if 0
+       /* diag_listed_as: SKIPME */
         Perl_croak(aTHX_ "usage: %s::%s()",
                    HvNAME_get(GvSTASH(CvGV(cv))), GvNAME(CvGV(cv)));
 #endif