This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
sv.h: Document SvTHINKFIRST
[perl5.git] / sv.h
diff --git a/sv.h b/sv.h
index c841c3e..056d43b 100644 (file)
--- a/sv.h
+++ b/sv.h
@@ -348,7 +348,7 @@ perform the upgrade if necessary.  See C<svtype>.
 
 
 
-#define SVf_THINKFIRST (SVf_READONLY|SVf_ROK|SVf_FAKE)
+#define SVf_THINKFIRST (SVf_READONLY|SVf_ROK|SVf_FAKE|SVs_RMG)
 
 #define SVf_OK         (SVf_IOK|SVf_NOK|SVf_POK|SVf_ROK| \
                         SVp_IOK|SVp_NOK|SVp_POK|SVpgv_GP)
@@ -924,6 +924,13 @@ in gv.h: */
 #define SvPOK_byte_nog(sv)     ((SvFLAGS(sv) & (SVf_POK|SVf_UTF8|SVs_GMG)) == SVf_POK)
 #define SvPOK_byte_nogthink(sv)        ((SvFLAGS(sv) & (SVf_POK|SVf_UTF8|SVf_THINKFIRST|SVs_GMG)) == SVf_POK)
 
+#define SvPOK_pure_nogthink(sv) \
+    ((SvFLAGS(sv) & (SVf_POK|SVf_IOK|SVf_NOK|SVf_ROK|SVpgv_GP|SVf_THINKFIRST|SVs_GMG)) == SVf_POK)
+#define SvPOK_utf8_pure_nogthink(sv) \
+    ((SvFLAGS(sv) & (SVf_POK|SVf_UTF8|SVf_IOK|SVf_NOK|SVf_ROK|SVpgv_GP|SVf_THINKFIRST|SVs_GMG)) == (SVf_POK|SVf_UTF8))
+#define SvPOK_byte_pure_nogthink(sv) \
+    ((SvFLAGS(sv) & (SVf_POK|SVf_UTF8|SVf_IOK|SVf_NOK|SVf_ROK|SVpgv_GP|SVf_THINKFIRST|SVs_GMG)) == SVf_POK)
+
 /*
 =for apidoc Am|U32|SvGAMAGIC|SV* sv
 
@@ -955,6 +962,30 @@ the scalar's value cannot change unless written to.
 #define SvPCS_IMPORTED_on(sv)  (SvFLAGS(sv) |=  (SVf_ROK|SVprv_PCS_IMPORTED))
 #define SvPCS_IMPORTED_off(sv) (SvFLAGS(sv) &= ~(SVf_ROK|SVprv_PCS_IMPORTED))
 
+/*
+=for apidoc m|U32|SvTHINKFIRST|SV *sv
+
+A quick flag check to see whether an sv should be passed to sv_force_normal
+to be "downgraded" before SvIVX or SvPVX can be modified directly.
+
+For example, if your scalar is a reference and you want to modify the SvIVX
+slot, you can't just do SvROK_off, as that will leak the referent.
+
+This is used internally by various sv-modifying functions, such as
+sv_setsv, sv_setiv and sv_pvn_force.
+
+One case that this does not handle is a gv without SvFAKE set.  After
+
+    if (SvTHINKFIRST(gv)) sv_force_normal(gv);
+
+it will still be a gv.
+
+SvTHINKFIRST sometimes produces false positives.  In those cases
+sv_force_normal does nothing.
+
+=cut
+*/
+
 #define SvTHINKFIRST(sv)       (SvFLAGS(sv) & SVf_THINKFIRST)
 
 #define SvPADMY(sv)            (SvFLAGS(sv) & SVs_PADMY)
@@ -1229,12 +1260,7 @@ the scalar's value cannot change unless written to.
 #define SvIV_please_nomg(sv) \
        (!SvIOKp(sv) && (SvNOK(sv) || SvPOK(sv)) \
            ? (SvIV_nomg(sv), SvIOK(sv))          \
-           : SvGMAGICAL(sv)                       \
-               ? SvIOKp(sv) || (                   \
-                      (SvNOKp(sv) || SvPOKp(sv))    \
-                   && sv_gmagical_2iv_please(sv)     \
-                 )                                    \
-               : SvIOK(sv))
+           : SvIOK(sv))
 #define SvIV_set(sv, val) \
        STMT_START { \
                assert(PL_valid_types_IV_set[SvTYPE(sv) & SVt_MASK]);   \
@@ -1440,14 +1466,14 @@ attention to precisely which outputs are influenced by which inputs.
 
 /*
 =for apidoc Am|char*|SvPV_force|SV* sv|STRLEN len
-Like C<SvPV> but will force the SV into containing just a string
-(C<SvPOK_only>).  You want force if you are going to update the C<SvPVX>
-directly.
+Like C<SvPV> but will force the SV into containing a string (C<SvPOK>), and
+only a (C<SvPOK_only>), by hook or by crook.  You want force if you are
+going to update the C<SvPVX> directly.  Processes get magic.
 
 =for apidoc Am|char*|SvPV_force_nomg|SV* sv|STRLEN len
-Like C<SvPV> but will force the SV into containing just a string
-(C<SvPOK_only>).  You want force if you are going to update the C<SvPVX>
-directly.  Doesn't process magic.
+Like C<SvPV> but will force the SV into containing a string (C<SvPOK>), and
+only a (C<SvPOK_only>), by hook or by crook.  You want force if you are
+going to update the C<SvPVX> directly.  Doesn't process get magic.
 
 =for apidoc Am|char*|SvPV|SV* sv|STRLEN len
 Returns a pointer to the string in the SV, or a stringified form of
@@ -1625,15 +1651,15 @@ Like sv_utf8_upgrade, but doesn't do magic on C<sv>.
 #define SvPV_force_nomg_nolen(sv) SvPV_force_flags_nolen(sv, 0)
 
 #define SvPV_force_flags(sv, lp, flags) \
-    (SvPOK_nogthink(sv) \
+    (SvPOK_pure_nogthink(sv) \
      ? ((lp = SvCUR(sv)), SvPVX(sv)) : sv_pvn_force_flags(sv, &lp, flags))
 
 #define SvPV_force_flags_nolen(sv, flags) \
-    (SvPOK_nogthink(sv) \
+    (SvPOK_pure_nogthink(sv) \
      ? SvPVX(sv) : sv_pvn_force_flags(sv, 0, flags))
 
 #define SvPV_force_flags_mutable(sv, lp, flags) \
-    (SvPOK_nogthink(sv) \
+    (SvPOK_pure_nogthink(sv) \
      ? ((lp = SvCUR(sv)), SvPVX_mutable(sv)) \
      : sv_pvn_force_flags(sv, &lp, flags|SV_MUTABLE_RETURN))
 
@@ -1660,7 +1686,7 @@ Like sv_utf8_upgrade, but doesn't do magic on C<sv>.
      ? ((lp = SvCUR(sv)), SvPVX(sv)) : sv_2pvutf8(sv, &lp))
 
 #define SvPVutf8_force(sv, lp) \
-    (SvPOK_utf8_nogthink(sv) \
+    (SvPOK_utf8_pure_nogthink(sv) \
      ? ((lp = SvCUR(sv)), SvPVX(sv)) : sv_pvutf8n_force(sv, &lp))
 
 #define SvPVutf8_nolen(sv) \
@@ -1674,7 +1700,7 @@ Like sv_utf8_upgrade, but doesn't do magic on C<sv>.
      ? ((lp = SvCUR(sv)), SvPVX(sv)) : sv_2pvbyte(sv, &lp))
 
 #define SvPVbyte_force(sv, lp) \
-    (SvPOK_byte_nogthink(sv) \
+    (SvPOK_byte_pure_nogthink(sv) \
      ? ((lp = SvCUR(sv)), SvPVX(sv)) : sv_pvbyten_force(sv, &lp))
 
 #define SvPVbyte_nolen(sv) \
@@ -2074,23 +2100,23 @@ Evaluates I<sv> more than once.  Sets I<len> to 0 if C<SvOOK(sv)> is false.
 #  define SvOOK_offset(sv, offset) STMT_START {                                \
        assert(sizeof(offset) == sizeof(STRLEN));                       \
        if (SvOOK(sv)) {                                                \
-           const U8 *crash = (U8*)SvPVX_const(sv);                     \
-           offset = *--crash;                                          \
-           if (!offset) {                                              \
-               crash -= sizeof(STRLEN);                                \
-               Copy(crash, (U8 *)&offset, sizeof(STRLEN), U8);         \
+           const U8 *_crash = (U8*)SvPVX_const(sv);                    \
+           (offset) = *--_crash;                                       \
+           if (!(offset)) {                                            \
+               _crash -= sizeof(STRLEN);                               \
+               Copy(_crash, (U8 *)&(offset), sizeof(STRLEN), U8);      \
            }                                                           \
            {                                                           \
                /* Validate the preceding buffer's sentinels to         \
                   verify that no-one is using it.  */                  \
-               const U8 *const bonk = (U8 *) SvPVX_const(sv) - offset; \
-               while (crash > bonk) {                                  \
-                   --crash;                                            \
-                   assert (*crash == (U8)PTR2UV(crash));               \
+               const U8 *const _bonk = (U8*)SvPVX_const(sv) - (offset);\
+               while (_crash > _bonk) {                                \
+                   --_crash;                                           \
+                   assert (*_crash == (U8)PTR2UV(_crash));             \
                }                                                       \
            }                                                           \
        } else {                                                        \
-           offset = 0;                                                 \
+           (offset) = 0;                                               \
        }                                                               \
     } STMT_END
 #else
@@ -2098,13 +2124,13 @@ Evaluates I<sv> more than once.  Sets I<len> to 0 if C<SvOOK(sv)> is false.
 #  define SvOOK_offset(sv, offset) STMT_START {                                \
        assert(sizeof(offset) == sizeof(STRLEN));                       \
        if (SvOOK(sv)) {                                                \
-           offset = ((U8*)SvPVX_const(sv))[-1];                        \
-           if (!offset) {                                              \
+           (offset) = ((U8*)SvPVX_const(sv))[-1];                      \
+           if (!(offset)) {                                            \
                Copy(SvPVX_const(sv) - 1 - sizeof(STRLEN),              \
-                    (U8 *)&offset, sizeof(STRLEN), U8);                \
+                    (U8*)&(offset), sizeof(STRLEN), U8);               \
            }                                                           \
        } else {                                                        \
-           offset = 0;                                                 \
+           (offset) = 0;                                               \
        }                                                               \
     } STMT_END
 #endif