This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
fix a couple of -Dmad compiler warnings
[perl5.git] / pp_hot.c
index ab36593..031c2cf 100644 (file)
--- a/pp_hot.c
+++ b/pp_hot.c
@@ -112,6 +112,7 @@ PP(pp_and)
 PP(pp_sassign)
 {
     dVAR; dSP; dPOPTOPssrl;
+    U32 wasfake = 0;
 
     if (PL_op->op_private & OPpASSIGN_BACKWARDS) {
        SV * const temp = left;
@@ -197,7 +198,14 @@ PP(pp_sassign)
        }
 
     }
+    /* Allow glob assignments like *$x = ..., which, when the glob has a
+       SVf_FAKE flag, cannot be distinguished from $x = ... without looking
+       at the op tree. */
+    if( SvTYPE(right) == SVt_PVGV && cBINOP->op_last->op_type == OP_RV2GV
+     && (wasfake = SvFLAGS(right) & SVf_FAKE) )
+       SvFLAGS(right) &= ~SVf_FAKE;
     SvSetMagicSV(right, left);
+    if(wasfake) SvFLAGS(right) |= SVf_FAKE;
     SETs(right);
     RETURN;
 }
@@ -227,7 +235,7 @@ PP(pp_unstack)
 
 PP(pp_concat)
 {
-  dVAR; dSP; dATARGET; tryAMAGICbin(concat,opASSIGN);
+  dVAR; dSP; dATARGET; tryAMAGICbin_MG(concat_amg, AMGf_assign);
   {
     dPOPTOPssrl;
     bool lbyte;
@@ -236,18 +244,17 @@ PP(pp_concat)
     bool rbyte = FALSE;
     bool rcopied = FALSE;
 
-    if (TARG == right && right != left) {
-       /* mg_get(right) may happen here ... */
-       rpv = SvPV_const(right, rlen);
+    if (TARG == right && right != left) { /* $r = $l.$r */
+       rpv = SvPV_nomg_const(right, rlen);
        rbyte = !DO_UTF8(right);
        right = newSVpvn_flags(rpv, rlen, SVs_TEMP);
        rpv = SvPV_const(right, rlen);  /* no point setting UTF-8 here */
        rcopied = TRUE;
     }
 
-    if (TARG != left) {
+    if (TARG != left) { /* not $l .= $r */
         STRLEN llen;
-        const char* const lpv = SvPV_const(left, llen);        /* mg_get(left) may happen here */
+        const char* const lpv = SvPV_nomg_const(left, llen);
        lbyte = !DO_UTF8(left);
        sv_setpvn(TARG, lpv, llen);
        if (!lbyte)
@@ -255,23 +262,23 @@ PP(pp_concat)
        else
            SvUTF8_off(TARG);
     }
-    else { /* TARG == left */
-        STRLEN llen;
-       SvGETMAGIC(left);               /* or mg_get(left) may happen here */
+    else { /* $l .= $r */
        if (!SvOK(TARG)) {
-           if (left == right && ckWARN(WARN_UNINITIALIZED))
+           if (left == right && ckWARN(WARN_UNINITIALIZED)) /* $l .= $l */
                report_uninit(right);
            sv_setpvs(left, "");
        }
-       (void)SvPV_nomg_const(left, llen);    /* Needed to set UTF8 flag */
-       lbyte = !DO_UTF8(left);
+       lbyte = (SvROK(left) && SvTYPE(SvRV(left)) == SVt_REGEXP)
+                   ?  !DO_UTF8(SvRV(left)) : !DO_UTF8(left);
        if (IN_BYTES)
            SvUTF8_off(TARG);
     }
 
-    /* or mg_get(right) may happen here */
     if (!rcopied) {
-       rpv = SvPV_const(right, rlen);
+       if (left == right)
+           /* $r.$r: do magic twice: tied might return different 2nd time */
+           SvGETMAGIC(right);
+       rpv = SvPV_nomg_const(right, rlen);
        rbyte = !DO_UTF8(right);
     }
     if (lbyte != rbyte) {
@@ -281,7 +288,7 @@ PP(pp_concat)
            if (!rcopied)
                right = newSVpvn_flags(rpv, rlen, SVs_TEMP);
            sv_utf8_upgrade_nomg(right);
-           rpv = SvPV_const(right, rlen);
+           rpv = SvPV_nomg_const(right, rlen);
        }
     }
     sv_catpvn_nomg(TARG, rpv, rlen);
@@ -311,6 +318,7 @@ PP(pp_padsv)
 PP(pp_readline)
 {
     dVAR;
+    dSP; SvGETMAGIC(TOPs);
     tryAMAGICunTARGET(iter, 0);
     PL_last_in_gv = MUTABLE_GV(*PL_stack_sp--);
     if (!isGV_with_GP(PL_last_in_gv)) {
@@ -329,7 +337,8 @@ PP(pp_readline)
 
 PP(pp_eq)
 {
-    dVAR; dSP; tryAMAGICbinSET(eq,0);
+    dVAR; dSP;
+    tryAMAGICbin_MG(eq_amg, AMGf_set);
 #ifndef NV_PRESERVES_UV
     if (SvROK(TOPs) && !SvAMAGIC(TOPs) && SvROK(TOPm1s) && !SvAMAGIC(TOPm1s)) {
         SP--;
@@ -338,12 +347,12 @@ PP(pp_eq)
     }
 #endif
 #ifdef PERL_PRESERVE_IVUV
-    SvIV_please(TOPs);
+    SvIV_please_nomg(TOPs);
     if (SvIOK(TOPs)) {
        /* Unless the left argument is integer in range we are going
           to have to use NV maths. Hence only attempt to coerce the
           right argument if we know the left is integer.  */
-      SvIV_please(TOPm1s);
+      SvIV_please_nomg(TOPm1s);
        if (SvIOK(TOPm1s)) {
            const bool auvok = SvUOK(TOPm1s);
            const bool buvok = SvUOK(TOPs);
@@ -388,13 +397,13 @@ PP(pp_eq)
 #endif
     {
 #if defined(NAN_COMPARE_BROKEN) && defined(Perl_isnan)
-      dPOPTOPnnrl;
+      dPOPTOPnnrl_nomg;
       if (Perl_isnan(left) || Perl_isnan(right))
          RETSETNO;
       SETs(boolSV(left == right));
 #else
-      dPOPnv;
-      SETs(boolSV(TOPn == value));
+      dPOPnv_nomg;
+      SETs(boolSV(SvNV_nomg(TOPs) == value));
 #endif
       RETURN;
     }
@@ -404,7 +413,7 @@ PP(pp_preinc)
 {
     dVAR; dSP;
     if (SvTYPE(TOPs) >= SVt_PVAV || isGV_with_GP(TOPs))
-       DIE(aTHX_ "%s", PL_no_modify);
+       Perl_croak_no_modify(aTHX);
     if (!SvREADONLY(TOPs) && SvIOK_notUV(TOPs) && !SvNOK(TOPs) && !SvPOK(TOPs)
         && SvIVX(TOPs) != IV_MAX)
     {
@@ -491,9 +500,10 @@ PP(pp_defined)
 PP(pp_add)
 {
     dVAR; dSP; dATARGET; bool useleft; SV *svl, *svr;
-    tryAMAGICbin(add,opASSIGN);
-    svl = sv_2num(TOPm1s);
-    svr = sv_2num(TOPs);
+    tryAMAGICbin_MG(add_amg, AMGf_assign|AMGf_numeric);
+    svr = TOPs;
+    svl = TOPm1s;
+
     useleft = USE_LEFT(svl);
 #ifdef PERL_PRESERVE_IVUV
     /* We must see if we can perform the addition with integers if possible,
@@ -542,7 +552,8 @@ PP(pp_add)
        unsigned code below is actually shorter than the old code. :-)
     */
 
-    SvIV_please(svr);
+    SvIV_please_nomg(svr);
+
     if (SvIOK(svr)) {
        /* Unless the left argument is integer in range we are going to have to
           use NV maths. Hence only attempt to coerce the right argument if
@@ -559,7 +570,7 @@ PP(pp_add)
               lots of code to speed up what is probably a rarish case.  */
        } else {
            /* Left operand is defined, so is it IV? */
-           SvIV_please(svl);
+           SvIV_please_nomg(svl);
            if (SvIOK(svl)) {
                if ((auvok = SvUOK(svl)))
                    auv = SvUVX(svl);
@@ -642,14 +653,14 @@ PP(pp_add)
     }
 #endif
     {
-       NV value = SvNV(svr);
+       NV value = SvNV_nomg(svr);
        (void)POPs;
        if (!useleft) {
            /* left operand is undef, treat as zero. + 0.0 is identity. */
            SETn(value);
            RETURN;
        }
-       SETn( value + SvNV(svl) );
+       SETn( value + SvNV_nomg(svl) );
        RETURN;
     }
 }
@@ -817,8 +828,9 @@ PP(pp_rv2av)
     const bool is_pp_rv2av = PL_op->op_type == OP_RV2AV;
     const svtype type = is_pp_rv2av ? SVt_PVAV : SVt_PVHV;
 
+    if (!(PL_op->op_private & OPpDEREFed))
+       SvGETMAGIC(sv);
     if (SvROK(sv)) {
-      wasref:
        tryAMAGICunDEREF_var(is_pp_rv2av ? to_av_amg : to_hv_amg);
 
        sv = SvRV(sv);
@@ -855,11 +867,6 @@ PP(pp_rv2av)
            GV *gv;
        
            if (!isGV_with_GP(sv)) {
-               if (SvGMAGICAL(sv)) {
-                   mg_get(sv);
-                   if (SvROK(sv))
-                       goto wasref;
-               }
                gv = Perl_softref2xv(aTHX_ sv, is_pp_rv2av ? an_array : a_hash,
                                     type, &sp);
                if (!gv)
@@ -1042,24 +1049,19 @@ PP(pp_aassign)
                *(relem++) = sv;
                didstore = av_store(ary,i++,sv);
                if (magic) {
-                   if (SvSMAGICAL(sv)) {
-                       /* More magic can happen in the mg_set callback, so we
-                        * backup the delaymagic for now. */
-                       U16 dmbak = PL_delaymagic;
-                       PL_delaymagic = 0;
+                   if (SvSMAGICAL(sv))
                        mg_set(sv);
-                       PL_delaymagic = dmbak;
-                   }
                    if (!didstore)
                        sv_2mortal(sv);
                }
                TAINT_NOT;
            }
-           if (PL_delaymagic & DM_ARRAY)
+           if (PL_delaymagic & DM_ARRAY_ISA)
                SvSETMAGIC(MUTABLE_SV(ary));
            break;
        case SVt_PVHV: {                                /* normal hash */
                SV *tmpstr;
+               SV** topelem = relem;
 
                hash = MUTABLE_HV(sv);
                magic = SvMAGICAL(hash) != 0;
@@ -1073,18 +1075,23 @@ PP(pp_aassign)
                    tmpstr = newSV(0);
                    if (*relem)
                        sv_setsv(tmpstr,*relem);        /* value */
-                   *(relem++) = tmpstr;
-                   if (gimme != G_VOID && hv_exists_ent(hash, sv, 0))
-                       /* key overwrites an existing entry */
-                       duplicates += 2;
+                   relem++;
+                   if (gimme != G_VOID) {
+                       if (hv_exists_ent(hash, sv, 0))
+                           /* key overwrites an existing entry */
+                           duplicates += 2;
+                       else
+                       if (gimme == G_ARRAY) {
+                           /* copy element back: possibly to an earlier
+                            * stack location if we encountered dups earlier */
+                           *topelem++ = sv;
+                           *topelem++ = tmpstr;
+                       }
+                   }
                    didstore = hv_store_ent(hash,sv,tmpstr,0);
                    if (magic) {
-                       if (SvSMAGICAL(tmpstr)) {
-                           U16 dmbak = PL_delaymagic;
-                           PL_delaymagic = 0;
+                       if (SvSMAGICAL(tmpstr))
                            mg_set(tmpstr);
-                           PL_delaymagic = dmbak;
-                       }
                        if (!didstore)
                            sv_2mortal(tmpstr);
                    }
@@ -1108,13 +1115,7 @@ PP(pp_aassign)
            }
            else
                sv_setsv(sv, &PL_sv_undef);
-
-           if (SvSMAGICAL(sv)) {
-               U16 dmbak = PL_delaymagic;
-               PL_delaymagic = 0;
-               mg_set(sv);
-               PL_delaymagic = dmbak;
-           }
+           SvSETMAGIC(sv);
            break;
        }
     }
@@ -1199,11 +1200,20 @@ PP(pp_aassign)
            SP = lastrelem;
        else if (hash) {
            if (duplicates) {
-               /* Removes from the stack the entries which ended up as
-                * duplicated keys in the hash (fix for [perl #24380]) */
-               Move(firsthashrelem + duplicates,
-                       firsthashrelem, duplicates, SV**);
+               /* at this point we have removed the duplicate key/value
+                * pairs from the stack, but the remaining values may be
+                * wrong; i.e. with (a 1 a 2 b 3) on the stack we've removed
+                * the (a 2), but the stack now probably contains
+                * (a <freed> b 3), because { hv_save(a,1); hv_save(a,2) }
+                * obliterates the earlier key. So refresh all values. */
                lastrelem -= duplicates;
+               relem = firsthashrelem;
+               while (relem < lastrelem) {
+                   HE *he;
+                   sv = *relem++;
+                   he = hv_fetch_ent(hash, sv, 0, 0);
+                   *relem++ = (he ? HeVAL(he) : &PL_sv_undef);
+               }
            }
            SP = lastrelem;
        }
@@ -1236,7 +1246,7 @@ PP(pp_qr)
     SvROK_on(rv);
 
     if (pkg) {
-       HV* const stash = gv_stashpv(SvPV_nolen(pkg), GV_ADD);
+       HV *const stash = gv_stashsv(pkg, GV_ADD);
        SvREFCNT_dec(pkg);
        (void)sv_bless(rv, stash);
     }
@@ -1344,9 +1354,9 @@ PP(pp_match)
        /g matches against large strings.  So far a solution to this problem
        appears to be quite tricky.
        Test for the unsafe vars are TODO for now. */
-    if ((  !global && RX_NPARENS(rx)) 
-           || SvTEMP(TARG) || PL_sawampersand ||
-           (RX_EXTFLAGS(rx) & (RXf_EVAL_SEEN|RXf_PMf_KEEPCOPY)))
+    if (       (!global && RX_NPARENS(rx))
+           || SvTEMP(TARG) || SvAMAGIC(TARG) || PL_sawampersand
+           || (RX_EXTFLAGS(rx) & (RXf_EVAL_SEEN|RXf_PMf_KEEPCOPY)))
        r_flags |= REXEC_COPY_STR;
     if (SvSCREAM(TARG))
        r_flags |= REXEC_SCREAM;
@@ -1657,8 +1667,12 @@ Perl_do_readline(pTHX)
        }
        SvUPGRADE(sv, SVt_PV);
        tmplen = SvLEN(sv);     /* remember if already alloced */
-       if (!tmplen && !SvREADONLY(sv))
-           Sv_Grow(sv, 80);    /* try short-buffering it */
+       if (!tmplen && !SvREADONLY(sv)) {
+            /* try short-buffering it. Please update t/op/readline.t
+            * if you change the growth length.
+            */
+           Sv_Grow(sv, 80);
+        }
        offset = 0;
        if (type == OP_RCATLINE && SvOK(sv)) {
            if (!SvPOK(sv)) {
@@ -2107,6 +2121,11 @@ PP(pp_subst)
        EXTEND(SP,1);
     }
 
+    /* In non-destructive replacement mode, duplicate target scalar so it
+     * remains unchanged. */
+    if (rpm->op_pmflags & PMf_NONDESTRUCT)
+       TARG = newSVsv(TARG);
+
 #ifdef PERL_OLD_COPY_ON_WRITE
     /* Awooga. Awooga. "bool" types that are actually char are dangerous,
        because they make integers such as 256 "false".  */
@@ -2123,7 +2142,7 @@ PP(pp_subst)
         || ( ((SvTYPE(TARG) == SVt_PVGV && isGV_with_GP(TARG))
               || SvTYPE(TARG) > SVt_PVLV)
             && !(SvTYPE(TARG) == SVt_PVGV && SvFAKE(TARG)))))
-       DIE(aTHX_ "%s", PL_no_modify);
+       Perl_croak_no_modify(aTHX);
     PUTBACK;
 
   setup_match:
@@ -2230,7 +2249,10 @@ PP(pp_subst)
        if (!matched)
        {
            SPAGAIN;
-           PUSHs(&PL_sv_no);
+           if (rpm->op_pmflags & PMf_NONDESTRUCT)
+               PUSHs(TARG);
+           else
+               PUSHs(&PL_sv_no);
            LEAVE_SCOPE(oldsave);
            RETURN;
        }
@@ -2284,7 +2306,10 @@ PP(pp_subst)
            }
            TAINT_IF(rxtainted & 1);
            SPAGAIN;
-           PUSHs(&PL_sv_yes);
+           if (rpm->op_pmflags & PMf_NONDESTRUCT)
+               PUSHs(TARG);
+           else
+               PUSHs(&PL_sv_yes);
        }
        else {
            do {
@@ -2313,7 +2338,10 @@ PP(pp_subst)
            }
            TAINT_IF(rxtainted & 1);
            SPAGAIN;
-           mPUSHi((I32)iters);
+           if (rpm->op_pmflags & PMf_NONDESTRUCT)
+               PUSHs(TARG);
+           else
+               mPUSHi((I32)iters);
        }
        (void)SvPOK_only_UTF8(TARG);
        TAINT_IF(rxtainted);
@@ -2399,7 +2427,10 @@ PP(pp_subst)
 
        TAINT_IF(rxtainted & 1);
        SPAGAIN;
-       mPUSHi((I32)iters);
+       if (rpm->op_pmflags & PMf_NONDESTRUCT)
+           PUSHs(TARG);
+       else
+           mPUSHi((I32)iters);
 
        (void)SvPOK_only(TARG);
        if (doutf8)
@@ -2415,7 +2446,10 @@ PP(pp_subst)
 nope:
 ret_no:
     SPAGAIN;
-    PUSHs(&PL_sv_no);
+    if (rpm->op_pmflags & PMf_NONDESTRUCT)
+       PUSHs(TARG);
+    else
+       PUSHs(&PL_sv_no);
     LEAVE_SCOPE(oldsave);
     RETURN;
 }
@@ -2595,10 +2629,13 @@ PP(pp_leavesublv)
            MARK = newsp + 1;
            EXTEND_MORTAL(1);
            if (MARK == SP) {
-               /* Temporaries are bad unless they happen to be elements
-                * of a tied hash or array */
-               if (SvFLAGS(TOPs) & (SVs_TEMP | SVs_PADTMP | SVf_READONLY) &&
-                   !(SvRMAGICAL(TOPs) && mg_find(TOPs, PERL_MAGIC_tiedelem))) {
+               /* Temporaries are bad unless they happen to have set magic
+                * attached, such as the elements of a tied hash or array */
+               if ((SvFLAGS(TOPs) & (SVs_TEMP | SVs_PADTMP) ||
+                    (SvFLAGS(TOPs) & (SVf_READONLY | SVf_FAKE))
+                      == SVf_READONLY
+                   ) &&
+                   !SvSMAGICAL(TOPs)) {
                    LEAVE;
                    cxstack_ix--;
                    POPSUB(cx,sv);
@@ -2723,29 +2760,20 @@ PP(pp_entersub)
        }
        break;
     default:
-       if (!SvROK(sv)) {
+       if (sv == &PL_sv_yes) {         /* unfound import, ignore */
+           if (hasargs)
+               SP = PL_stack_base + POPMARK;
+           RETURN;
+       }
+       SvGETMAGIC(sv);
+       if (SvROK(sv)) {
+           SV * const * sp = &sv;      /* Used in tryAMAGICunDEREF macro. */
+           tryAMAGICunDEREF(to_cv);
+       }
+       else {
            const char *sym;
            STRLEN len;
-           if (sv == &PL_sv_yes) {             /* unfound import, ignore */
-               if (hasargs)
-                   SP = PL_stack_base + POPMARK;
-               RETURN;
-           }
-           if (SvGMAGICAL(sv)) {
-               mg_get(sv);
-               if (SvROK(sv))
-                   goto got_rv;
-               if (SvPOKp(sv)) {
-                   sym = SvPVX_const(sv);
-                   len = SvCUR(sv);
-               } else {
-                   sym = NULL;
-                   len = 0;
-               }
-           }
-           else {
-               sym = SvPV_const(sv, len);
-            }
+           sym = SvPV_nomg_const(sv, len);
            if (!sym)
                DIE(aTHX_ PL_no_usym, "a subroutine");
            if (PL_op->op_private & HINT_STRICT_REFS)
@@ -2753,11 +2781,6 @@ PP(pp_entersub)
            cv = get_cvn_flags(sym, len, GV_ADD|SvUTF8(sv));
            break;
        }
-  got_rv:
-       {
-           SV * const * sp = &sv;              /* Used in tryAMAGICunDEREF macro. */
-           tryAMAGICunDEREF(to_cv);
-       }       
        cv = MUTABLE_CV(SvRV(sv));
        if (SvTYPE(cv) == SVt_PVCV)
            break;
@@ -2921,7 +2944,7 @@ try_autoload:
 
        /* CvXSUB(cv) must not be NULL because newXS() refuses NULL xsub address */
        assert(CvXSUB(cv));
-       CALL_FPTR(CvXSUB(cv))(aTHX_ cv);
+       CvXSUB(cv)(aTHX_ cv);
 
        /* Enforce some sanity in scalar context. */
        if (gimme == G_SCALAR && ++markix != PL_stack_sp - PL_stack_base ) {
@@ -3038,7 +3061,7 @@ Perl_vivify_ref(pTHX_ SV *sv, U32 to_what)
     SvGETMAGIC(sv);
     if (!SvOK(sv)) {
        if (SvREADONLY(sv))
-           Perl_croak(aTHX_ "%s", PL_no_modify);
+           Perl_croak_no_modify(aTHX);
        prepare_SV_for_RV(sv);
        switch (to_what) {
        case OPpDEREF_SV: