Fix an error, spotted by Tim Bunce.
[p5sagit/p5-mst-13.2.git] / pp.c
diff --git a/pp.c b/pp.c
index f9f9e7b..7a70e15 100644 (file)
--- a/pp.c
+++ b/pp.c
@@ -138,7 +138,7 @@ PP(pp_rv2gv)
            GV * const gv = (GV*) sv_newmortal();
            gv_init(gv, 0, "", 0, 0);
            GvIOp(gv) = (IO *)sv;
-           (void)SvREFCNT_inc(sv);
+           SvREFCNT_inc_void_NN(sv);
            sv = (SV*) gv;
        }
        else if (SvTYPE(sv) != SVt_PVGV)
@@ -172,7 +172,7 @@ PP(pp_rv2gv)
                    }
                    if (SvTYPE(sv) < SVt_RV)
                        sv_upgrade(sv, SVt_RV);
-                   if (SvPVX_const(sv)) {
+                   else if (SvPVX_const(sv)) {
                        SvPV_free(sv);
                        SvLEN_set(sv, 0);
                         SvCUR_set(sv, 0);
@@ -322,7 +322,7 @@ PP(pp_pos)
        if (LvTARG(TARG) != sv) {
            if (LvTARG(TARG))
                SvREFCNT_dec(LvTARG(TARG));
-           LvTARG(TARG) = SvREFCNT_inc(sv);
+           LvTARG(TARG) = SvREFCNT_inc_simple(sv);
        }
        PUSHs(TARG);    /* no SvSETMAGIC */
        RETURN;
@@ -334,7 +334,7 @@ PP(pp_pos)
                I32 i = mg->mg_len;
                if (DO_UTF8(sv))
                    sv_pos_b2u(sv, &i);
-               PUSHi(i + PL_curcop->cop_arybase);
+               PUSHi(i + CopARYBASE_get(PL_curcop));
                RETURN;
            }
        }
@@ -489,19 +489,19 @@ S_refto(pTHX_ SV *sv)
        if (!(sv = LvTARG(sv)))
            sv = &PL_sv_undef;
        else
-           (void)SvREFCNT_inc(sv);
+           SvREFCNT_inc_void_NN(sv);
     }
     else if (SvTYPE(sv) == SVt_PVAV) {
        if (!AvREAL((AV*)sv) && AvREIFY((AV*)sv))
            av_reify((AV*)sv);
        SvTEMP_off(sv);
-       (void)SvREFCNT_inc(sv);
+       SvREFCNT_inc_void_NN(sv);
     }
     else if (SvPADTMP(sv) && !IS_PADGV(sv))
         sv = newSVsv(sv);
     else {
        SvTEMP_off(sv);
-       (void)SvREFCNT_inc(sv);
+       SvREFCNT_inc_void_NN(sv);
     }
     rv = sv_newmortal();
     sv_upgrade(rv, SVt_RV);
@@ -639,13 +639,22 @@ PP(pp_study)
        if (SvSCREAM(sv))
            RETPUSHYES;
     }
-    else {
-       if (PL_lastscream) {
-           SvSCREAM_off(PL_lastscream);
-           SvREFCNT_dec(PL_lastscream);
-       }
-       PL_lastscream = SvREFCNT_inc(sv);
+    s = (unsigned char*)(SvPV(sv, len));
+    pos = len;
+    if (pos <= 0 || !SvPOK(sv)) {
+       /* No point in studying a zero length string, and not safe to study
+          anything that doesn't appear to be a simple scalar (and hence might
+          change between now and when the regexp engine runs without our set
+          magic ever running) such as a reference to an object with overloaded
+          stringification.  */
+       RETPUSHNO;
+    }
+
+    if (PL_lastscream) {
+       SvSCREAM_off(PL_lastscream);
+       SvREFCNT_dec(PL_lastscream);
     }
+    PL_lastscream = SvREFCNT_inc_simple(sv);
 
     s = (unsigned char*)(SvPV(sv, len));
     pos = len;
@@ -989,7 +998,47 @@ PP(pp_pow)
 #endif    
     {
        dPOPTOPnnrl;
+
+#if defined(USE_LONG_DOUBLE) && defined(HAS_AIX_POWL_NEG_BASE_BUG)
+    /*
+    We are building perl with long double support and are on an AIX OS
+    afflicted with a powl() function that wrongly returns NaNQ for any
+    negative base.  This was reported to IBM as PMR #23047-379 on
+    03/06/2006.  The problem exists in at least the following versions
+    of AIX and the libm fileset, and no doubt others as well:
+
+       AIX 4.3.3-ML10      bos.adt.libm 4.3.3.50
+       AIX 5.1.0-ML04      bos.adt.libm 5.1.0.29
+       AIX 5.2.0           bos.adt.libm 5.2.0.85
+
+    So, until IBM fixes powl(), we provide the following workaround to
+    handle the problem ourselves.  Our logic is as follows: for
+    negative bases (left), we use fmod(right, 2) to check if the
+    exponent is an odd or even integer:
+
+       - if odd,  powl(left, right) == -powl(-left, right)
+       - if even, powl(left, right) ==  powl(-left, right)
+
+    If the exponent is not an integer, the result is rightly NaNQ, so
+    we just return that (as NV_NAN).
+    */
+
+       if (left < 0.0) {
+           NV mod2 = Perl_fmod( right, 2.0 );
+           if (mod2 == 1.0 || mod2 == -1.0) {  /* odd integer */
+               SETn( -Perl_pow( -left, right) );
+           } else if (mod2 == 0.0) {           /* even integer */
+               SETn( Perl_pow( -left, right) );
+           } else {                            /* fractional power */
+               SETn( NV_NAN );
+           }
+       } else {
+           SETn( Perl_pow( left, right) );
+       }
+#else
        SETn( Perl_pow( left, right) );
+#endif  /* HAS_AIX_POWL_NEG_BASE_BUG */
+
 #ifdef PERL_PRESERVE_IVUV
        if (is_int)
            SvIV_please(TOPs);
@@ -1705,8 +1754,15 @@ PP(pp_lt)
     }
 #endif
     {
+#if defined(NAN_COMPARE_BROKEN) && defined(Perl_isnan)
+      dPOPTOPnnrl;
+      if (Perl_isnan(left) || Perl_isnan(right))
+         RETSETNO;
+      SETs(boolSV(left < right));
+#else
       dPOPnv;
       SETs(boolSV(TOPn < value));
+#endif
       RETURN;
     }
 }
@@ -1781,8 +1837,15 @@ PP(pp_gt)
     }
 #endif
     {
+#if defined(NAN_COMPARE_BROKEN) && defined(Perl_isnan)
+      dPOPTOPnnrl;
+      if (Perl_isnan(left) || Perl_isnan(right))
+         RETSETNO;
+      SETs(boolSV(left > right));
+#else
       dPOPnv;
       SETs(boolSV(TOPn > value));
+#endif
       RETURN;
     }
 }
@@ -1857,8 +1920,15 @@ PP(pp_le)
     }
 #endif
     {
+#if defined(NAN_COMPARE_BROKEN) && defined(Perl_isnan)
+      dPOPTOPnnrl;
+      if (Perl_isnan(left) || Perl_isnan(right))
+         RETSETNO;
+      SETs(boolSV(left <= right));
+#else
       dPOPnv;
       SETs(boolSV(TOPn <= value));
+#endif
       RETURN;
     }
 }
@@ -1933,8 +2003,15 @@ PP(pp_ge)
     }
 #endif
     {
+#if defined(NAN_COMPARE_BROKEN) && defined(Perl_isnan)
+      dPOPTOPnnrl;
+      if (Perl_isnan(left) || Perl_isnan(right))
+         RETSETNO;
+      SETs(boolSV(left >= right));
+#else
       dPOPnv;
       SETs(boolSV(TOPn >= value));
+#endif
       RETURN;
     }
 }
@@ -2002,8 +2079,15 @@ PP(pp_ne)
     }
 #endif
     {
+#if defined(NAN_COMPARE_BROKEN) && defined(Perl_isnan)
+      dPOPTOPnnrl;
+      if (Perl_isnan(left) || Perl_isnan(right))
+         RETSETYES;
+      SETs(boolSV(left != right));
+#else
       dPOPnv;
       SETs(boolSV(TOPn != value));
+#endif
       RETURN;
     }
 }
@@ -2345,16 +2429,16 @@ PP(pp_complement)
        if (SvUTF8(TARG)) {
          /* Calculate exact length, let's not estimate. */
          STRLEN targlen = 0;
-         U8 *result;
-         U8 *send;
          STRLEN l;
          UV nchar = 0;
          UV nwide = 0;
+         U8 * const send = tmps + len;
+         U8 * const origtmps = tmps;
+         const UV utf8flags = UTF8_ALLOW_ANYUV;
 
-         send = tmps + len;
          while (tmps < send) {
-           const UV c = utf8n_to_uvchr(tmps, send-tmps, &l, UTF8_ALLOW_ANYUV);
-           tmps += UTF8SKIP(tmps);
+           const UV c = utf8n_to_uvchr(tmps, send-tmps, &l, utf8flags);
+           tmps += l;
            targlen += UNISKIP(~c);
            nchar++;
            if (c > 0xff)
@@ -2362,33 +2446,39 @@ PP(pp_complement)
          }
 
          /* Now rewind strings and write them. */
-         tmps -= len;
+         tmps = origtmps;
 
          if (nwide) {
-             Newxz(result, targlen + 1, U8);
+             U8 *result;
+             U8 *p;
+
+             Newx(result, targlen + 1, U8);
+             p = result;
              while (tmps < send) {
-                 const UV c = utf8n_to_uvchr(tmps, send-tmps, &l, UTF8_ALLOW_ANYUV);
-                 tmps += UTF8SKIP(tmps);
-                 result = uvchr_to_utf8_flags(result, ~c, UNICODE_ALLOW_ANY);
+                 const UV c = utf8n_to_uvchr(tmps, send-tmps, &l, utf8flags);
+                 tmps += l;
+                 p = uvchr_to_utf8_flags(p, ~c, UNICODE_ALLOW_ANY);
              }
-             *result = '\0';
-             result -= targlen;
-             sv_setpvn(TARG, (char*)result, targlen);
+             *p = '\0';
+             sv_usepvn_flags(TARG, (char*)result, targlen,
+                             SV_HAS_TRAILING_NUL);
              SvUTF8_on(TARG);
          }
          else {
-             Newxz(result, nchar + 1, U8);
+             U8 *result;
+             U8 *p;
+
+             Newx(result, nchar + 1, U8);
+             p = result;
              while (tmps < send) {
-                 const U8 c = (U8)utf8n_to_uvchr(tmps, 0, &l, UTF8_ALLOW_ANY);
-                 tmps += UTF8SKIP(tmps);
-                 *result++ = ~c;
+                 const U8 c = (U8)utf8n_to_uvchr(tmps, send-tmps, &l, utf8flags);
+                 tmps += l;
+                 *p++ = ~c;
              }
-             *result = '\0';
-             result -= nchar;
-             sv_setpvn(TARG, (char*)result, nchar);
+             *p = '\0';
+             sv_usepvn_flags(TARG, (char*)result, nchar, SV_HAS_TRAILING_NUL);
              SvUTF8_off(TARG);
          }
-         Safefree(result);
          SETs(TARG);
          RETURN;
        }
@@ -2879,7 +2969,7 @@ PP(pp_substr)
     I32 fail;
     const I32 lvalue = PL_op->op_flags & OPf_MOD || LVRET;
     const char *tmps;
-    const I32 arybase = PL_curcop->cop_arybase;
+    const I32 arybase = CopARYBASE_get(PL_curcop);
     SV *repl_sv = NULL;
     const char *repl = NULL;
     STRLEN repl_len;
@@ -3007,7 +3097,9 @@ PP(pp_substr)
                        Perl_warner(aTHX_ packWARN(WARN_SUBSTR),
                                "Attempt to use reference as lvalue in substr");
                }
-               if (SvOK(sv))           /* is it defined ? */
+               if (isGV_with_GP(sv))
+                   SvPV_force_nolen(sv);
+               else if (SvOK(sv))      /* is it defined ? */
                    (void)SvPOK_only_UTF8(sv);
                else
                    sv_setpvn(sv,"",0); /* avoid lexical reincarnation */
@@ -3024,7 +3116,7 @@ PP(pp_substr)
            if (LvTARG(TARG) != sv) {
                if (LvTARG(TARG))
                    SvREFCNT_dec(LvTARG(TARG));
-               LvTARG(TARG) = SvREFCNT_inc(sv);
+               LvTARG(TARG) = SvREFCNT_inc_simple(sv);
            }
            LvTARGOFF(TARG) = upos;
            LvTARGLEN(TARG) = urem;
@@ -3055,7 +3147,7 @@ PP(pp_vec)
        if (LvTARG(TARG) != src) {
            if (LvTARG(TARG))
                SvREFCNT_dec(LvTARG(TARG));
-           LvTARG(TARG) = SvREFCNT_inc(src);
+           LvTARG(TARG) = SvREFCNT_inc_simple(src);
        }
        LvTARGOFF(TARG) = offset;
        LvTARGLEN(TARG) = size;
@@ -3078,7 +3170,7 @@ PP(pp_index)
     I32 retval;
     const char *tmps;
     const char *tmps2;
-    const I32 arybase = PL_curcop->cop_arybase;
+    const I32 arybase = CopARYBASE_get(PL_curcop);
     bool big_utf8;
     bool little_utf8;
     const bool is_index = PL_op->op_type == OP_INDEX;
@@ -3339,7 +3431,8 @@ PP(pp_ucfirst)
            if (slen > ulen)
                sv_catpvn(TARG, (char*)(s + ulen), slen - ulen);
            SvUTF8_on(TARG);
-           SETs(TARG);
+           sv = TARG;
+           SETs(sv);
        }
        else {
            s = (U8*)SvPV_force_nomg(sv, slen);
@@ -3391,7 +3484,8 @@ PP(pp_uc)
        if (!len) {
            SvUTF8_off(TARG);                           /* decontaminate */
            sv_setpvn(TARG, "", 0);
-           SETs(TARG);
+           sv = TARG;
+           SETs(sv);
        }
        else {
            STRLEN min = len + 1;
@@ -3424,7 +3518,8 @@ PP(pp_uc)
            *d = '\0';
            SvUTF8_on(TARG);
            SvCUR_set(TARG, d - (U8*)SvPVX_const(TARG));
-           SETs(TARG);
+           sv = TARG;
+           SETs(sv);
        }
     }
     else {
@@ -3476,7 +3571,8 @@ PP(pp_lc)
        if (!len) {
            SvUTF8_off(TARG);                           /* decontaminate */
            sv_setpvn(TARG, "", 0);
-           SETs(TARG);
+           sv = TARG;
+           SETs(sv);
        }
        else {
            STRLEN min = len + 1;
@@ -3529,7 +3625,8 @@ PP(pp_lc)
            *d = '\0';
            SvUTF8_on(TARG);
            SvCUR_set(TARG, d - (U8*)SvPVX_const(TARG));
-           SETs(TARG);
+           sv = TARG;
+           SETs(sv);
        }
     }
     else {
@@ -3622,7 +3719,7 @@ PP(pp_aslice)
     register const I32 lval = (PL_op->op_flags & OPf_MOD || LVRET);
 
     if (SvTYPE(av) == SVt_PVAV) {
-       const I32 arybase = PL_curcop->cop_arybase;
+       const I32 arybase = CopARYBASE_get(PL_curcop);
        if (lval && PL_op->op_private & OPpLVAL_INTRO) {
            register SV **svp;
            I32 max = -1;
@@ -3828,13 +3925,18 @@ PP(pp_hslice)
                 DIE(aTHX_ PL_no_helem_sv, keysv);
             }
             if (localizing) {
-                if (preeminent)
-                    save_helem(hv, keysv, svp);
-                else {
-                    STRLEN keylen;
-                    const char *key = SvPV_const(keysv, keylen);
-                    SAVEDELETE(hv, savepvn(key,keylen), keylen);
-                }
+               if (HvNAME_get(hv) && isGV(*svp))
+                   save_gp((GV*)*svp, !(PL_op->op_flags & OPf_SPECIAL));
+               else {
+                   if (preeminent)
+                       save_helem(hv, keysv, svp);
+                   else {
+                       STRLEN keylen;
+                       const char * const key = SvPV_const(keysv, keylen);
+                       SAVEDELETE(hv, savepvn(key,keylen),
+                                  SvUTF8(keysv) ? -keylen : keylen);
+                   }
+               }
             }
         }
         *MARK = svp ? *svp : &PL_sv_undef;
@@ -3870,7 +3972,7 @@ PP(pp_lslice)
     SV ** const lastlelem = PL_stack_base + POPMARK;
     SV ** const firstlelem = PL_stack_base + POPMARK + 1;
     register SV ** const firstrelem = lastlelem + 1;
-    const I32 arybase = PL_curcop->cop_arybase;
+    const I32 arybase = CopARYBASE_get(PL_curcop);
     I32 is_something_there = PL_op->op_flags & OPf_MOD;
 
     register const I32 max = lastrelem - lastlelem;
@@ -3957,7 +4059,6 @@ PP(pp_splice)
     I32 newlen;
     I32 after;
     I32 diff;
-    SV **tmparyval = NULL;
     const MAGIC * const mg = SvTIED_mg((SV*)ary, PERL_MAGIC_tied);
 
     if (mg) {
@@ -3978,7 +4079,7 @@ PP(pp_splice)
        if (offset < 0)
            offset += AvFILLp(ary) + 1;
        else
-           offset -= PL_curcop->cop_arybase;
+           offset -= CopARYBASE_get(PL_curcop);
        if (offset < 0)
            DIE(aTHX_ PL_no_aelem, i);
        if (++MARK < SP) {
@@ -4023,6 +4124,7 @@ PP(pp_splice)
     }
 
     if (diff < 0) {                            /* shrinking the area */
+       SV **tmparyval;
        if (newlen) {
            Newx(tmparyval, newlen, SV*);       /* so remember insertion */
            Copy(MARK, tmparyval, newlen, SV*);
@@ -4083,15 +4185,14 @@ PP(pp_splice)
        }
     }
     else {                                     /* no, expanding (or same) */
+       SV** tmparyval = NULL;
        if (length) {
            Newx(tmparyval, length, SV*);       /* so remember deletion */
            Copy(AvARRAY(ary)+offset, tmparyval, length, SV*);
        }
 
        if (diff > 0) {                         /* expanding */
-
            /* push up or down? */
-
            if (offset < after && diff <= AvARRAY(ary) - AvALLOC(ary)) {
                if (offset) {
                    src = AvARRAY(ary);
@@ -4132,7 +4233,6 @@ PP(pp_splice)
                        dst++;
                    }
                }
-               Safefree(tmparyval);
            }
            MARK += length - 1;
        }
@@ -4143,10 +4243,10 @@ PP(pp_splice)
                while (length-- > 0)
                    SvREFCNT_dec(tmparyval[length]);
            }
-           Safefree(tmparyval);
        }
        else
            *MARK = &PL_sv_undef;
+       Safefree(tmparyval);
     }
     SP = MARK;
     RETURN;
@@ -4254,7 +4354,8 @@ PP(pp_reverse)
            sv_setsv(TARG, (SP > MARK)
                    ? *SP
                    : (padoff_du = find_rundefsvoffset(),
-                       (padoff_du == NOT_IN_PAD || PAD_COMPNAME_FLAGS(padoff_du) & SVpad_OUR)
+                       (padoff_du == NOT_IN_PAD
+                        || PAD_COMPNAME_FLAGS_isOUR(padoff_du))
                        ? DEFSV : PAD_SVl(padoff_du)));
        up = SvPV_force(TARG, len);
        if (len > 1) {
@@ -4321,7 +4422,7 @@ PP(pp_split)
     const I32 oldsave = PL_savestack_ix;
     I32 make_mortal = 1;
     bool multiline = 0;
-    MAGIC *mg = (MAGIC *) NULL;
+    MAGIC *mg = NULL;
 
 #ifdef DEBUGGING
     Copy(&LvTARGOFF(POPs), &pm, 1, PMOP*);