I32 resetsp;
LOOP * my_op; /* My op, that contains redo, next and last ops. */
union { /* different ways of locating the iteration variable */
- SV **svp;
- GV *gv;
- PAD *oldcomppad; /* only used in ITHREADS */
+ SV **svp; /* for lexicals: address of pad slot */
+ GV *gv; /* for package vars */
} itervar_u;
union {
struct { /* valid if type is LOOP_FOR or LOOP_PLAIN (but {NULL,0})*/
SV * end; /* maxiumum value (or minimum in reverse) */
} lazysv;
} state_u;
-};
-
#ifdef USE_ITHREADS
-# define CxITERVAR_PADSV(c) \
- &CX_CURPAD_SV( (c)->blk_loop.itervar_u, (c)->blk_loop.my_op->op_targ)
-#else
-# define CxITERVAR_PADSV(c) ((c)->blk_loop.itervar_u.svp)
+ PAD *oldcomppad; /* needed to map itervar_u.svp during thread clone */
#endif
+};
#define CxITERVAR(c) \
- ((c)->blk_loop.itervar_u.oldcomppad \
- ? (CxPADLOOP(c) \
- ? CxITERVAR_PADSV(c) \
- : isGV((c)->blk_loop.itervar_u.gv) \
- ? &GvSV((c)->blk_loop.itervar_u.gv) \
- : (SV **)&(c)->blk_loop.itervar_u.gv) \
- : (SV**)NULL)
+ (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 CxLABEL(c) (0 + CopLABEL((c)->blk_oldcop))
#define CxLABEL_len(c,len) (0 + CopLABEL_len((c)->blk_oldcop, len))
cx->blk_loop.state_u.ary.ix = 0; \
cx->blk_loop.itervar_u.svp = NULL;
+#ifdef USE_ITHREADS
+# define PUSHLOOP_FOR_setpad(c) (c)->blk_loop.oldcomppad = PL_comppad
+#else
+# define PUSHLOOP_FOR_setpad(c) NOOP
+#endif
+
#define PUSHLOOP_FOR(cx, ivar, s) \
cx->blk_loop.resetsp = s - PL_stack_base; \
cx->blk_loop.my_op = cLOOP; \
cx->blk_loop.state_u.ary.ary = NULL; \
cx->blk_loop.state_u.ary.ix = 0; \
- cx->blk_loop.itervar_u.svp = (SV**)(ivar);
+ cx->blk_loop.itervar_u.svp = (SV**)(ivar); \
+ PUSHLOOP_FOR_setpad(cx);
#define POPLOOP(cx) \
if (CxTYPE(cx) == CXt_LOOP_LAZYSV) { \
skip_all("clone_with_stack requires threads");
}
-plan(6);
+plan(8);
fresh_perl_is( <<'----', <<'====', undef, "minimal clone_with_stack" );
use XS::APItest;
====
}
+
+{
+ fresh_perl_is( <<'----', <<'====', undef, "inside a loop inside a fn" );
+use XS::APItest;
+my $a = 'aa';
+sub f {
+ my $b = 'bb';
+ my @c;
+ my $d = 'dd';
+ for my $d (0..4) {
+ clone_with_stack() if $d == 2;
+ push @c, $d;
+ }
+ return @c, $d;
+}
+print "X-$a-", join(':', f()), "-Z\n";
+----
+X-aa-0:1:2:3:4:dd-Z
+====
+
+}
+
+{
+ fresh_perl_is( <<'----', <<'====', undef, "inside fn inside a loop inside a fn" );
+use XS::APItest;
+my $a = 'aa';
+
+sub g {
+ my $e = 'ee';
+ my $f = 'ff';
+ clone_with_stack();
+}
+
+sub f {
+ my $b = 'bb';
+ my @c;
+ my $d = 'dd';
+ for my $d (0..4) {
+ g() if $d == 2;
+ push @c, $d;
+ }
+ return @c, $d;
+}
+print "X-$a-", join(':', f()), "-Z\n";
+----
+X-aa-0:1:2:3:4:dd-Z
+====
+
+}
SVs_PADSTALE, SVs_PADSTALE);
}
SAVEPADSVANDMORTALIZE(PL_op->op_targ);
-#ifdef USE_ITHREADS
- itervar = PL_comppad;
-#else
itervar = &PAD_SVl(PL_op->op_targ);
-#endif
}
else if (LIKELY(isGV(TOPs))) { /* symbol table variable */
GV * const gv = MUTABLE_GV(POPs);
case CXt_LOOP_PLAIN:
/* code common to all CXt_LOOP_* types */
if (CxPADLOOP(ncx)) {
- ncx->blk_loop.itervar_u.oldcomppad
- = (PAD*)ptr_table_fetch(PL_ptr_table,
- ncx->blk_loop.itervar_u.oldcomppad);
- } else {
+ PADOFFSET off = ncx->blk_loop.itervar_u.svp
+ - &CX_CURPAD_SV(ncx->blk_loop, 0);
+ ncx->blk_loop.oldcomppad =
+ (PAD*)ptr_table_fetch(PL_ptr_table,
+ ncx->blk_loop.oldcomppad);
+ ncx->blk_loop.itervar_u.svp =
+ &CX_CURPAD_SV(ncx->blk_loop, off);
+
+ }
+ else {
ncx->blk_loop.itervar_u.gv
= gv_dup((const GV *)ncx->blk_loop.itervar_u.gv,
param);
require "./test.pl";
}
-plan(109);
+plan(110);
# A lot of tests to check that reversed for works.
@_ = (1,2,3,scalar do{for(@_){}} + 1, 4, 5, 6);
is "@_", "1 2 3 1 4 5 6",
'[perl #124004] scalar for(@empty_array) stack bug';
+
+# DAPM: while messing with the scope code, I broke some cpan/ code,
+# but surprisingly didn't break any dedicated tests. So test it:
+
+sub fscope {
+ for my $y (1,2) {
+ my $a = $y;
+ return $a;
+ }
+}
+
+is(fscope(), 1, 'return via loop in sub');
desc => '$x--',
setup => 'my $x = 1; my $y',
code => '$y = $x--', # scalar context so not optimised to --$x
+ },
+
+ 'loop::for_my_range' => {
+ desc => 'empty for loop with my var and integer range',
+ setup => '',
+ code => 'for my $x (1..10) {}',
},
];