This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
perldelta for [perl #75174] (dirp_dup)
[perl5.git] / pp.c
diff --git a/pp.c b/pp.c
index d6e3132..476212e 100644 (file)
--- a/pp.c
+++ b/pp.c
@@ -162,7 +162,7 @@ PP(pp_rv2gv)
                 * NI-S 1999/05/07
                 */
                if (SvREADONLY(sv))
-                   Perl_croak(aTHX_ "%s", PL_no_modify);
+                   Perl_croak_no_modify(aTHX);
                if (PL_op->op_private & OPpDEREF) {
                    GV *gv;
                    if (cUNOP->op_targ) {
@@ -272,7 +272,8 @@ PP(pp_rv2sv)
     dVAR; dSP; dTOPss;
     GV *gv = NULL;
 
-    SvGETMAGIC(sv);
+    if (!(PL_op->op_private & OPpDEREFed))
+       SvGETMAGIC(sv);
     if (SvROK(sv)) {
        tryAMAGICunDEREF(to_sv);
 
@@ -335,26 +336,21 @@ PP(pp_av2arylen)
 
 PP(pp_pos)
 {
-    dVAR; dSP; dTARGET; dPOPss;
+    dVAR; dSP; dPOPss;
 
     if (PL_op->op_flags & OPf_MOD || LVRET) {
-       if (SvTYPE(TARG) < SVt_PVLV) {
-           sv_upgrade(TARG, SVt_PVLV);
-           sv_magic(TARG, NULL, PERL_MAGIC_pos, NULL, 0);
-       }
-
-       LvTYPE(TARG) = '.';
-       if (LvTARG(TARG) != sv) {
-           SvREFCNT_dec(LvTARG(TARG));
-           LvTARG(TARG) = SvREFCNT_inc_simple(sv);
-       }
-       PUSHs(TARG);    /* no SvSETMAGIC */
+       SV * const ret = sv_2mortal(newSV_type(SVt_PVLV));  /* Not TARG RT#67838 */
+       sv_magic(ret, NULL, PERL_MAGIC_pos, NULL, 0);
+       LvTYPE(ret) = '.';
+       LvTARG(ret) = SvREFCNT_inc_simple(sv);
+       PUSHs(ret);    /* no SvSETMAGIC */
        RETURN;
     }
     else {
        if (SvTYPE(sv) >= SVt_PVMG && SvMAGIC(sv)) {
            const MAGIC * const mg = mg_find(sv, PERL_MAGIC_regex_global);
            if (mg && mg->mg_len >= 0) {
+               dTARGET;
                I32 i = mg->mg_len;
                if (DO_UTF8(sv))
                    sv_pos_b2u(sv, &i);
@@ -428,6 +424,14 @@ PP(pp_prototype)
                    ret = newSVpvs_flags("\\[@%]", SVs_TEMP);
                    goto set;
                }
+               if (code == -KEY_tied || code == -KEY_untie) {
+                   ret = newSVpvs_flags("\\[$@%*]", SVs_TEMP);
+                   goto set;
+               }
+               if (code == -KEY_tie) {
+                   ret = newSVpvs_flags("\\[$@%*]$@", SVs_TEMP);
+                   goto set;
+               }
                if (code == -KEY_readpipe) {
                    s = "CORE::backtick";
                }
@@ -829,7 +833,7 @@ PP(pp_undef)
            /* let user-undef'd sub keep its identity */
            GV* const gv = CvGV((const CV *)sv);
            cv_undef(MUTABLE_CV(sv));
-           CvGV((const CV *)sv) = gv;
+           CvGV_set(MUTABLE_CV(sv), gv);
        }
        break;
     case SVt_PVGV:
@@ -876,7 +880,7 @@ PP(pp_predec)
 {
     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_MIN)
     {
@@ -893,7 +897,9 @@ PP(pp_postinc)
 {
     dVAR; dSP; dTARGET;
     if (SvTYPE(TOPs) >= SVt_PVAV || isGV_with_GP(TOPs))
-       DIE(aTHX_ "%s", PL_no_modify);
+       Perl_croak_no_modify(aTHX);
+    if (SvROK(TOPs))
+       TARG = sv_newmortal();
     sv_setsv(TARG, TOPs);
     if (!SvREADONLY(TOPs) && SvIOK_notUV(TOPs) && !SvNOK(TOPs) && !SvPOK(TOPs)
         && SvIVX(TOPs) != IV_MAX)
@@ -915,7 +921,9 @@ PP(pp_postdec)
 {
     dVAR; dSP; dTARGET;
     if (SvTYPE(TOPs) >= SVt_PVAV || isGV_with_GP(TOPs))
-       DIE(aTHX_ "%s", PL_no_modify);
+       Perl_croak_no_modify(aTHX);
+    if (SvROK(TOPs))
+       TARG = sv_newmortal();
     sv_setsv(TARG, TOPs);
     if (!SvREADONLY(TOPs) && SvIOK_notUV(TOPs) && !SvNOK(TOPs) && !SvPOK(TOPs)
         && SvIVX(TOPs) != IV_MIN)
@@ -2328,8 +2336,8 @@ PP(pp_sle)
     {
       dPOPTOPssrl;
       const int cmp = (IN_LOCALE_RUNTIME
-                ? sv_cmp_locale(left, right)
-                : sv_cmp(left, right));
+                ? sv_cmp_locale_flags(left, right, 0)
+                : sv_cmp_flags(left, right, 0));
       SETs(boolSV(cmp * multiplier < rhs));
       RETURN;
     }
@@ -2341,7 +2349,7 @@ PP(pp_seq)
     tryAMAGICbin_MG(seq_amg, AMGf_set);
     {
       dPOPTOPssrl;
-      SETs(boolSV(sv_eq(left, right)));
+      SETs(boolSV(sv_eq_flags(left, right, 0)));
       RETURN;
     }
 }
@@ -2352,7 +2360,7 @@ PP(pp_sne)
     tryAMAGICbin_MG(sne_amg, AMGf_set);
     {
       dPOPTOPssrl;
-      SETs(boolSV(!sv_eq(left, right)));
+      SETs(boolSV(!sv_eq_flags(left, right, 0)));
       RETURN;
     }
 }
@@ -2364,8 +2372,8 @@ PP(pp_scmp)
     {
       dPOPTOPssrl;
       const int cmp = (IN_LOCALE_RUNTIME
-                ? sv_cmp_locale(left, right)
-                : sv_cmp(left, right));
+                ? sv_cmp_locale_flags(left, right, 0)
+                : sv_cmp_flags(left, right, 0));
       SETi( cmp );
       RETURN;
     }
@@ -2499,7 +2507,7 @@ PP(pp_not)
 {
     dVAR; dSP;
     tryAMAGICun_MG(not_amg, AMGf_set);
-    *PL_stack_sp = boolSV(!SvTRUE(*PL_stack_sp));
+    *PL_stack_sp = boolSV(!SvTRUE_nomg(*PL_stack_sp));
     return NORMAL;
 }
 
@@ -2941,12 +2949,19 @@ PP(pp_rand)
 
 PP(pp_srand)
 {
-    dVAR; dSP;
+    dVAR; dSP; dTARGET;
     const UV anum = (MAXARG < 1) ? seed() : POPu;
     (void)seedDrand01((Rand_seed_t)anum);
     PL_srand_called = TRUE;
-    EXTEND(SP, 1);
-    RETPUSHYES;
+    if (anum)
+       XPUSHu(anum);
+    else {
+       /* Historically srand always returned true. We can avoid breaking
+          that like this:  */
+       sv_setpvs(TARG, "0 but true");
+       XPUSHTARG;
+    }
+    RETURN;
 }
 
 PP(pp_int)
@@ -3058,11 +3073,11 @@ PP(pp_oct)
         tmps++, len--;
     if (*tmps == '0')
         tmps++, len--;
-    if (*tmps == 'x') {
+    if (*tmps == 'x' || *tmps == 'X') {
     hex:
         result_uv = grok_hex (tmps, &len, &flags, &result_nv);
     }
-    else if (*tmps == 'b')
+    else if (*tmps == 'b' || *tmps == 'B')
         result_uv = grok_bin (tmps, &len, &flags, &result_nv);
     else
         result_uv = grok_oct (tmps, &len, &flags, &result_nv);
@@ -3094,8 +3109,10 @@ PP(pp_length)
            = sv_2pv_flags(sv, &len,
                           SV_UNDEF_RETURNS_NULL|SV_CONST_RETURN|SV_GMAGIC);
 
-       if (!p)
-           SETs(&PL_sv_undef);
+       if (!p) {
+           sv_setsv(TARG, &PL_sv_undef);
+           SETTARG;
+       }
        else if (DO_UTF8(sv)) {
            SETi(utf8_length((U8*)p, (U8*)p + len));
        }
@@ -3108,7 +3125,8 @@ PP(pp_length)
        else
            SETi(sv_len(sv));
     } else {
-       SETs(&PL_sv_undef);
+       sv_setsv_nomg(TARG, &PL_sv_undef);
+       SETTARG;
     }
     RETURN;
 }
@@ -3137,8 +3155,6 @@ PP(pp_substr)
     bool repl_need_utf8_upgrade = FALSE;
     bool repl_is_utf8 = FALSE;
 
-    SvTAINTED_off(TARG);                       /* decontaminate */
-    SvUTF8_off(TARG);                          /* decontaminate */
     if (num_args > 2) {
        if (num_args > 3) {
            repl_sv = POPs;
@@ -3246,26 +3262,46 @@ PP(pp_substr)
        STRLEN byte_pos = utf8_curlen
            ? sv_pos_u2b_flags(sv, pos, &byte_len, SV_CONST_RETURN) : pos;
 
-       tmps += byte_pos;
-       /* we either return a PV or an LV. If the TARG hasn't been used
-        * before, or is of that type, reuse it; otherwise use a mortal
-        * instead. Note that LVs can have an extended lifetime, so also
-        * dont reuse if refcount > 1 (bug #20933) */
-       if (SvTYPE(TARG) > SVt_NULL) {
-           if ( (SvTYPE(TARG) == SVt_PVLV)
-                   ? (!lvalue || SvREFCNT(TARG) > 1)
-                   : lvalue)
-           {
-               TARG = sv_newmortal();
+       if (lvalue && !repl) {
+           SV * ret;
+
+           if (!SvGMAGICAL(sv)) {
+               if (SvROK(sv)) {
+                   SvPV_force_nolen(sv);
+                   Perl_ck_warner(aTHX_ packWARN(WARN_SUBSTR),
+                                  "Attempt to use reference as lvalue in substr");
+               }
+               if (isGV_with_GP(sv))
+                   SvPV_force_nolen(sv);
+               else if (SvOK(sv))      /* is it defined ? */
+                   (void)SvPOK_only_UTF8(sv);
+               else
+                   sv_setpvs(sv, ""); /* avoid lexical reincarnation */
            }
+
+           ret = sv_2mortal(newSV_type(SVt_PVLV));  /* Not TARG RT#67838 */
+           sv_magic(ret, NULL, PERL_MAGIC_substr, NULL, 0);
+           LvTYPE(ret) = 'x';
+           LvTARG(ret) = SvREFCNT_inc_simple(sv);
+           LvTARGOFF(ret) = pos;
+           LvTARGLEN(ret) = len;
+
+           SPAGAIN;
+           PUSHs(ret);    /* avoid SvSETMAGIC here */
+           RETURN;
        }
 
+       SvTAINTED_off(TARG);                    /* decontaminate */
+       SvUTF8_off(TARG);                       /* decontaminate */
+
+       tmps += byte_pos;
        sv_setpvn(TARG, tmps, byte_len);
 #ifdef USE_LOCALE_COLLATE
        sv_unmagic(TARG, PERL_MAGIC_collxfrm);
 #endif
        if (utf8_curlen)
            SvUTF8_on(TARG);
+
        if (repl) {
            SV* repl_sv_copy = NULL;
 
@@ -3282,34 +3318,6 @@ PP(pp_substr)
                SvUTF8_on(sv);
            SvREFCNT_dec(repl_sv_copy);
        }
-       else if (lvalue) {              /* it's an lvalue! */
-           if (!SvGMAGICAL(sv)) {
-               if (SvROK(sv)) {
-                   SvPV_force_nolen(sv);
-                   Perl_ck_warner(aTHX_ packWARN(WARN_SUBSTR),
-                                  "Attempt to use reference as lvalue in substr");
-               }
-               if (isGV_with_GP(sv))
-                   SvPV_force_nolen(sv);
-               else if (SvOK(sv))      /* is it defined ? */
-                   (void)SvPOK_only_UTF8(sv);
-               else
-                   sv_setpvs(sv, ""); /* avoid lexical reincarnation */
-           }
-
-           if (SvTYPE(TARG) < SVt_PVLV) {
-               sv_upgrade(TARG, SVt_PVLV);
-               sv_magic(TARG, NULL, PERL_MAGIC_substr, NULL, 0);
-           }
-
-           LvTYPE(TARG) = 'x';
-           if (LvTARG(TARG) != sv) {
-               SvREFCNT_dec(LvTARG(TARG));
-               LvTARG(TARG) = SvREFCNT_inc_simple(sv);
-           }
-           LvTARGOFF(TARG) = pos;
-           LvTARGLEN(TARG) = len;
-       }
     }
     SPAGAIN;
     PUSHs(TARG);               /* avoid SvSETMAGIC here */
@@ -3324,31 +3332,29 @@ bound_fail:
 
 PP(pp_vec)
 {
-    dVAR; dSP; dTARGET;
+    dVAR; dSP;
     register const IV size   = POPi;
     register const IV offset = POPi;
     register SV * const src = POPs;
     const I32 lvalue = PL_op->op_flags & OPf_MOD || LVRET;
+    SV * ret;
 
-    SvTAINTED_off(TARG);               /* decontaminate */
     if (lvalue) {                      /* it's an lvalue! */
-       if (SvREFCNT(TARG) > 1) /* don't share the TARG (#20933) */
-           TARG = sv_newmortal();
-       if (SvTYPE(TARG) < SVt_PVLV) {
-           sv_upgrade(TARG, SVt_PVLV);
-           sv_magic(TARG, NULL, PERL_MAGIC_vec, NULL, 0);
-       }
-       LvTYPE(TARG) = 'v';
-       if (LvTARG(TARG) != src) {
-           SvREFCNT_dec(LvTARG(TARG));
-           LvTARG(TARG) = SvREFCNT_inc_simple(src);
-       }
-       LvTARGOFF(TARG) = offset;
-       LvTARGLEN(TARG) = size;
+       ret = sv_2mortal(newSV_type(SVt_PVLV));  /* Not TARG RT#67838 */
+       sv_magic(ret, NULL, PERL_MAGIC_vec, NULL, 0);
+       LvTYPE(ret) = 'v';
+       LvTARG(ret) = SvREFCNT_inc_simple(src);
+       LvTARGOFF(ret) = offset;
+       LvTARGLEN(ret) = size;
+    }
+    else {
+       dTARGET;
+       SvTAINTED_off(TARG);            /* decontaminate */
+       ret = TARG;
     }
 
-    sv_setuv(TARG, do_vecget(src, offset, size));
-    PUSHs(TARG);
+    sv_setuv(ret, do_vecget(src, offset, size));
+    PUSHs(ret);
     RETURN;
 }
 
@@ -3609,7 +3615,6 @@ PP(pp_crypt)
 #else
     DIE(aTHX_
       "The crypt() function is unimplemented due to excessive paranoia.");
-    return NORMAL;
 #endif
 }
 
@@ -4055,18 +4060,19 @@ PP(pp_uc)
        const U8 *const send = s + len;
        U8 tmpbuf[UTF8_MAXBYTES+1];
 
-/* This is ifdefd out because it needs more work and thought.  It isn't clear
- * that we should do it.  These are hard-coded rules from the Unicode standard,
- * and may change.  5.2 gives new guidance on the iota subscript, for example,
- * which has not been checked against this; and secondly it may be that we are
- * passed a subset of the context, via a \U...\E, for example, and its not
- * clear what the best approach is to that */
-#ifdef CONTEXT_DEPENDENT_CASING
+       /* All occurrences of these are to be moved to follow any other marks.
+        * This is context-dependent.  We may not be passed enough context to
+        * move the iota subscript beyond all of them, but we do the best we can
+        * with what we're given.  The result is always better than if we
+        * hadn't done this.  And, the problem would only arise if we are
+        * passed a character without all its combining marks, which would be
+        * the caller's mistake.  The information this is based on comes from a
+        * comment in Unicode SpecialCasing.txt, (and the Standard's text
+        * itself) and so can't be checked properly to see if it ever gets
+        * revised.  But the likelihood of it changing is remote */
        bool in_iota_subscript = FALSE;
-#endif
 
        while (s < send) {
-#ifdef CONTEXT_DEPENDENT_CASING
            if (in_iota_subscript && ! is_utf8_mark(s)) {
                /* A non-mark.  Time to output the iota subscript */
 #define GREEK_CAPITAL_LETTER_IOTA 0x0399
@@ -4075,7 +4081,6 @@ PP(pp_uc)
                CAT_UNI_TO_UTF8_TWO_BYTE(d, GREEK_CAPITAL_LETTER_IOTA);
                in_iota_subscript = FALSE;
            }
-#endif
 
 
 /* See comments at the first instance in this file of this ifdef */
@@ -4107,15 +4112,13 @@ PP(pp_uc)
                const STRLEN u = UTF8SKIP(s);
                STRLEN ulen;
 
-#ifndef CONTEXT_DEPENDENT_CASING
-               toUPPER_utf8(s, tmpbuf, &ulen);
-#else
                const UV uv = toUPPER_utf8(s, tmpbuf, &ulen);
-               if (uv == GREEK_CAPITAL_LETTER_IOTA && utf8_to_uvchr(s, 0) == COMBINING_GREEK_YPOGEGRAMMENI) {
+               if (uv == GREEK_CAPITAL_LETTER_IOTA
+                   && utf8_to_uvchr(s, 0) == COMBINING_GREEK_YPOGEGRAMMENI)
+               {
                    in_iota_subscript = TRUE;
                }
                else {
-#endif
                    if (ulen > u && (SvLEN(dest) < (min += ulen - u))) {
                        /* If the eventually required minimum size outgrows
                         * the available space, we need to grow. */
@@ -4124,26 +4127,25 @@ PP(pp_uc)
                        /* If someone uppercases one million U+03B0s we
                         * SvGROW() one million times.  Or we could try
                         * guessing how much to allocate without allocating too
-                        * much.  Such is life.  See corresponding comment in lc code
-                        * for another option */
+                        * much.  Such is life.  See corresponding comment in
+                        * lc code for another option */
                        SvGROW(dest, min);
                        d = (U8*)SvPVX(dest) + o;
                    }
                    Copy(tmpbuf, d, ulen, U8);
                    d += ulen;
-#ifdef CONTEXT_DEPENDENT_CASING
                }
-#endif
                s += u;
            }
        }
-#ifdef CONTEXT_DEPENDENT_CASING
-       if (in_iota_subscript) CAT_UNI_TO_UTF8_TWO_BYTE(d, GREEK_CAPITAL_LETTER_IOTA);
-#endif
+       if (in_iota_subscript) {
+           CAT_UNI_TO_UTF8_TWO_BYTE(d, GREEK_CAPITAL_LETTER_IOTA);
+       }
        SvUTF8_on(dest);
        *d = '\0';
        SvCUR_set(dest, d - (U8*)SvPVX_const(dest));
-    } else {   /* Not UTF-8 */
+    }
+    else {     /* Not UTF-8 */
        if (len) {
            const U8 *const send = s + len;
 
@@ -4344,12 +4346,23 @@ PP(pp_lc)
                const STRLEN u = UTF8SKIP(s);
                STRLEN ulen;
 
-/* See comments at the first instance in this file of this ifdef */
 #ifndef CONTEXT_DEPENDENT_CASING
                toLOWER_utf8(s, tmpbuf, &ulen);
 #else
-               /* Here is context dependent casing, not compiled in currently;
-                * needs more thought and work */
+/* This is ifdefd out because it needs more work and thought.  It isn't clear
+ * that we should do it.
+ * A minor objection is that this is based on a hard-coded rule from the
+ *  Unicode standard, and may change, but this is not very likely at all.
+ *  mktables should check and warn if it does.
+ * More importantly, if the sigma occurs at the end of the string, we don't
+ * have enough context to know whether it is part of a larger string or going
+ * to be or not.  It may be that we are passed a subset of the context, via
+ * a \U...\E, for example, and we could conceivably know the larger context if
+ * code were changed to pass that in.  But, if the string passed in is an
+ * intermediate result, and the user concatenates two strings together
+ * after we have made a final sigma, that would be wrong.  If the final sigma
+ * occurs in the middle of the string we are working on, then we know that it
+ * should be a final sigma, but otherwise we can't be sure. */
 
                const UV uv = toLOWER_utf8(s, tmpbuf, &ulen);
 
@@ -5348,7 +5361,7 @@ PP(pp_push)
                sv_setsv(sv, *MARK);
            av_store(ary, AvFILLp(ary)+1, sv);
        }
-       if (PL_delaymagic & DM_ARRAY)
+       if (PL_delaymagic & DM_ARRAY_ISA)
            mg_set(MUTABLE_SV(ary));
 
        PL_delaymagic = 0;
@@ -5488,19 +5501,12 @@ PP(pp_reverse)
        register I32 tmp;
        dTARGET;
        STRLEN len;
-       PADOFFSET padoff_du;
 
        SvUTF8_off(TARG);                               /* decontaminate */
        if (SP - MARK > 1)
            do_join(TARG, &PL_sv_no, MARK, SP);
        else {
-           sv_setsv(TARG, (SP > MARK)
-                   ? *SP
-                   : (padoff_du = find_rundefsvoffset(),
-                       (padoff_du == NOT_IN_PAD
-                        || PAD_COMPNAME_FLAGS_isOUR(padoff_du))
-                       ? DEFSV : PAD_SVl(padoff_du)));
-
+           sv_setsv(TARG, SP > MARK ? *SP : find_rundefsv());
            if (! SvOK(TARG) && ckWARN(WARN_UNINITIALIZED))
                report_uninit(TARG);
        }
@@ -6010,7 +6016,6 @@ PP(unimplemented_op)
     dVAR;
     DIE(aTHX_ "panic: unimplemented op %s (#%d) called", OP_NAME(PL_op),
        PL_op->op_type);
-    return NORMAL;
 }
 
 PP(pp_boolkeys)