This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
add CXp_FOR_PAD, CXp_FOR_GV flags
authorDavid Mitchell <davem@iabyn.com>
Thu, 27 Aug 2015 15:03:42 +0000 (16:03 +0100)
committerDavid Mitchell <davem@iabyn.com>
Wed, 3 Feb 2016 08:59:39 +0000 (08:59 +0000)
These indicate that the loop is a for loop, with a lexical or package
iterator variable.

These flags make various tests simpler and more efficient.

This commit also fixes a bug introduced a couple of commits ago;
I was assuming that in POPLOOP, itersave being non-NULL indicated a
'for $lex' or 'for $pkg', but something like

    local *x;
    for $x (..) {}

leaves the loop with itersave set to NULL. Instead we can use the new
flags to indicate that itersave is valid.

cop.h
pp_ctl.c
t/op/for.t

diff --git a/cop.h b/cop.h
index 08b52f2..c708cb7 100644 (file)
--- a/cop.h
+++ b/cop.h
@@ -781,14 +781,12 @@ struct block_loop {
 #endif
 };
 
-#define CxITERVAR(c)                                                   \
-        (CxPADLOOP(c)                                                  \
-            ? (c)->blk_loop.itervar_u.svp                              \
-            : (c)->blk_loop.itervar_u.svp                              \
-                ? isGV((c)->blk_loop.itervar_u.gv)                     \
-                    ? &GvSV((c)->blk_loop.itervar_u.gv)                        \
-                    : (SV **)&(c)->blk_loop.itervar_u.gv               \
-                : (SV**)NULL)
+#define CxITERVAR(c)                                    \
+        (CxPADLOOP(c)                                   \
+            ? (c)->blk_loop.itervar_u.svp               \
+            : ((c)->cx_type & CXp_FOR_GV)               \
+                ? &GvSV((c)->blk_loop.itervar_u.gv)     \
+                : (SV **)&(c)->blk_loop.itervar_u.gv)
 
 #define CxLABEL(c)     (0 + CopLABEL((c)->blk_oldcop))
 #define CxLABEL_len(c,len)     (0 + CopLABEL_len((c)->blk_oldcop, len))
@@ -832,10 +830,10 @@ struct block_loop {
        }                                                               \
        else if (CxTYPE(cx) == CXt_LOOP_FOR)                            \
            SvREFCNT_dec(cx->blk_loop.state_u.ary.ary);                 \
-        if (cx->blk_loop.itersave) {                                    \
+        if (cx->cx_type & (CXp_FOR_PAD|CXp_FOR_GV)) {                   \
             SV **svp = (cx)->blk_loop.itervar_u.svp;                    \
             SV *cursv;                                                  \
-            if (isGV((GV*)svp)) {                                       \
+            if ((cx->cx_type & CXp_FOR_GV)) {                           \
                 svp = &GvSV((GV*)svp);                                  \
                 cursv = *svp;                                           \
                 *svp = cx->blk_loop.itersave;                           \
@@ -845,7 +843,7 @@ struct block_loop {
                 *svp = cx->blk_loop.itersave;                           \
             }                                                           \
             SvREFCNT_dec(cursv);                                        \
-        }                                                               \
+        }
 
 /* given/when context */
 struct block_givwhen {
@@ -1038,7 +1036,9 @@ struct context {
 /* private flags for CXt_LOOP */
 #define CXp_FOR_DEF    0x10    /* foreach using $_ */
 #define CXp_FOR_LVREF  0x20    /* foreach using \$var */
-#define CxPADLOOP(c)   ((c)->blk_loop.my_op->op_targ)
+#define CXp_FOR_GV     0x40    /* foreach using package var */
+#define CXp_FOR_PAD    0x80    /* foreach using lexical var */
+#define CxPADLOOP(c)   ((c)->cx_type & CXp_FOR_PAD)
 
 /* private flags for CXt_SUBST */
 #define CXp_ONCE       0x10    /* What was sbu_once in struct subst */
index 89aaf3a..7b3589d 100644 (file)
--- a/pp_ctl.c
+++ b/pp_ctl.c
@@ -2135,6 +2135,7 @@ PP(pp_enteriter)
            SvPADSTALE_on(itersave);
        }
         SvREFCNT_inc_simple_void_NN(itersave);
+       cxtype |= CXp_FOR_PAD;
     }
     else if (LIKELY(isGV(TOPs))) {             /* symbol table variable */
        GV * const gv = MUTABLE_GV(POPs);
@@ -2142,6 +2143,7 @@ PP(pp_enteriter)
        itervarp = (void *)gv;
         itersave = *svp;
        *svp = newSV(0);
+       cxtype |= CXp_FOR_GV;
     }
     else {
        SV * const sv = POPs;
index 922e3da..65a7464 100644 (file)
@@ -5,7 +5,7 @@ BEGIN {
     require "./test.pl";
 }
 
-plan(110);
+plan(111);
 
 # A lot of tests to check that reversed for works.
 
@@ -609,3 +609,14 @@ sub fscope {
 }
 
 is(fscope(), 1, 'return via loop in sub');
+
+# make sure a NULL GvSV is restored at the end of the loop
+
+{
+    local $foo = "boo";
+    {
+        local *foo;
+        for $foo (1,2) {}
+        ok(!defined $foo, "NULL GvSV");
+    }
+}