New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
'next' undefines variables in 'continue' block #1050
Comments
From oracle@tauceti.pcr.comA friend of mine ran into this problem, but I never saw it come up When 'next' exits a while block and enters a following continue File test_next: while block: $i = 3 Also, when 'next' is used to jump to a labelled outer loop with a After digging around in the perl source code, it seems that a Perl Info
|
From @gsarOn Wed, 19 Jan 2000 09:48:19 MST, oracle@tauceti.pcr.com wrote:
Thanks for that accurate diagnosis of the problem. I noticed another longstanding bug: local-ized values inside a while block These two changes fix both problems. There is one remaining problem with local-ized values still being visible Sarathy Inline Patch-----------------------------------8<-----------------------------------
Change 4848 by gsar@auger on 2000/01/23 06:43:51
fix scope cleanup when next jumps to a continue block; this is rather
in the nature of a kludge; it doesn't fix the longstanding bug that
makes C<while (!$x++) { local $x = 7 } continue { print $x }> print "7"
instead of "1")
Affected files ...
... //depot/perl/pp_ctl.c#174 edit
... //depot/perl/t/cmd/while.t#8 edit
Differences ...
==== //depot/perl/pp_ctl.c#174 (text) ====
Index: perl/pp_ctl.c
--- perl/pp_ctl.c.~1~ Sat Jan 22 22:43:56 2000
+++ perl/pp_ctl.c Sat Jan 22 22:43:56 2000
@@ -1960,9 +1960,15 @@
dounwind(cxix);
TOPBLOCK(cx);
- oldsave = PL_scopestack[PL_scopestack_ix - 1];
- LEAVE_SCOPE(oldsave);
- return cx->blk_loop.next_op;
+ {
+ OP *nextop = cx->blk_loop.next_op;
+ /* clean scope, but only if there's no continue block */
+ if (nextop == cUNOPx(cx->blk_loop.last_op)->op_first->op_next) {
+ oldsave = PL_scopestack[PL_scopestack_ix - 1];
+ LEAVE_SCOPE(oldsave);
+ }
+ return nextop;
+ }
}
PP(pp_redo)
==== //depot/perl/t/cmd/while.t#8 (xtext) ====
Index: perl/t/cmd/while.t
--- perl/t/cmd/while.t.~1~ Sat Jan 22 22:43:56 2000
+++ perl/t/cmd/while.t Sat Jan 22 22:43:56 2000
@@ -2,7 +2,7 @@
# $RCSfile: while.t,v $$Revision: 4.1 $$Date: 92/08/07 18:27:15 $
-print "1..15\n";
+print "1..17\n";
open (tmp,'>Cmd_while.tmp') || die "Can't create Cmd_while.tmp.";
print tmp "tvi925\n";
@@ -128,3 +128,16 @@
$i++;
print "not " unless $` . $& . $' eq "abc";
print "ok $i\n";
+
+# check that scope cleanup happens right when there's a continue block
+{
+ my $var = 16;
+ while (my $i = ++$var) {
+ next if $i == 17;
+ last if $i > 17;
+ my $i = 0;
+ }
+ continue {
+ print "ok ", $var-1, "\nok $i\n";
+ }
+}
End of Patch.
Change 4849 by gsar@auger on 2000/01/23 08:17:30
fix localization in while BLOCK when there is a continue BLOCK
by introducing an explicit scope (c.f. change#4848)
Affected files ...
... //depot/perl/op.c#242 edit
... //depot/perl/pp_ctl.c#175 edit
... //depot/perl/t/cmd/while.t#9 edit
Differences ...
==== //depot/perl/op.c#242 (text) ====
Index: perl/op.c
--- perl/op.c.~1~ Sun Jan 23 00:17:34 2000
+++ perl/op.c Sun Jan 23 00:17:34 2000
@@ -3753,6 +3753,9 @@
if (!block)
block = newOP(OP_NULL, 0);
+ else if (cont) {
+ block = scope(block);
+ }
if (cont)
next = LINKLIST(cont);
==== //depot/perl/pp_ctl.c#175 (text) ====
Index: perl/pp_ctl.c
--- perl/pp_ctl.c.~1~ Sun Jan 23 00:17:34 2000
+++ perl/pp_ctl.c Sun Jan 23 00:17:34 2000
@@ -1959,11 +1959,12 @@
if (cxix < cxstack_ix)
dounwind(cxix);
- TOPBLOCK(cx);
+ cx = &cxstack[cxstack_ix];
{
OP *nextop = cx->blk_loop.next_op;
/* clean scope, but only if there's no continue block */
if (nextop == cUNOPx(cx->blk_loop.last_op)->op_first->op_next) {
+ TOPBLOCK(cx);
oldsave = PL_scopestack[PL_scopestack_ix - 1];
LEAVE_SCOPE(oldsave);
}
==== //depot/perl/t/cmd/while.t#9 (xtext) ====
Index: perl/t/cmd/while.t
--- perl/t/cmd/while.t.~1~ Sun Jan 23 00:17:34 2000
+++ perl/t/cmd/while.t Sun Jan 23 00:17:34 2000
@@ -1,8 +1,6 @@
#!./perl
-# $RCSfile: while.t,v $$Revision: 4.1 $$Date: 92/08/07 18:27:15 $
-
-print "1..17\n";
+print "1..19\n";
open (tmp,'>Cmd_while.tmp') || die "Can't create Cmd_while.tmp.";
print tmp "tvi925\n";
@@ -141,3 +139,24 @@
print "ok ", $var-1, "\nok $i\n";
}
}
+
+{
+ local $l = 18;
+ {
+ local $l = 0
+ }
+ continue {
+ print "ok $l\n"
+ }
+}
+
+{
+ local $l = 19;
+ my $x = 0;
+ while (!$x++) {
+ local $l = 0
+ }
+ continue {
+ print "ok $l\n"
+ }
+}
End of Patch. |
From @timbunceOn Sun, Jan 23, 2000 at 12:28:33AM -0800, Gurusamy Sarathy wrote:
That sounds like a borderline feature. Some people may be using it. Tim. |
From [Unknown Contact. See original ticket]Hi, Tim Bunce:
Either a block is a block, no matter how you get there, or the continue At the moment, we have some sort of pseudo block around a while(){} anyway, Personally, I'd favor the second solution. -- |
From @gsarOn Sun, 23 Jan 2000 14:17:25 +0100, "Matthias Urlichs" wrote:
Looks like there's some misunderstanding here--the case I was referring while (!$x++) { will print "7" instead of "1". After the patches I showed, removing the Sarathy |
From @TimToadyGurusamy Sarathy writes: Tim is worried about backward compatibility. I'm worried about performance. Larry |
From @gsarOn Tue, 25 Jan 2000 09:00:36 PST, Larry Wall wrote:
We ought to do some tests to see how bad it is, but I should point out Sarathy |
From [Unknown Contact. See original ticket]
GSar> On Wed, 19 Jan 2000 09:48:19 MST, oracle@tauceti.pcr.com wrote: O> After digging around in the perl source code, it seems that a GSar> Thanks for that accurate diagnosis of the problem. GSar> I noticed another longstanding bug: local-ized values inside a GSar> These two changes fix both problems. GSar> There is one remaining problem with local-ized values still GSar> Change 4848 by gsar@auger on 2000/01/23 06:43:51 GSar> fix scope cleanup when next jumps to a continue block; this is rather GSar> Affected files ... GSar> ... //depot/perl/pp_ctl.c#174 edit GSar> Differences ... GSar> ==== //depot/perl/pp_ctl.c#174 (text) ==== GSar> TOPBLOCK(cx); Um, I think you still need to do some save-stack popping even if there sub f { my $a = 1; my $b = 2; my $c = 3; my $d = 4; next } Will print `1', and then if you add more my declarations before `my (The reason I just noticed this is that I think it's the proximate No, I don't have a patch, but I found the following message in my From: Stephen McCamant <alias@mcs.com>
MJTG> joshua.pritikin@db.com wrote MJTG> I'd call it a bug. Note that it's been like that ever since the MJTG> If it's not a bug, it's certainly anomalous and needs I agree it's a bug, though it's a pretty deep one. If you don't mind, +-----------+ Fig. 1 A loop. The above picture shows what a `while(){}' or `until(){}' loop looks In theory, the body of a loop is its own block, so perl should The `lastop', `redoop', and `nextop' show where the corresponding loop `next' is the most complicated. In the current implementation, it Note that the visibility and the lifetime of lexicals are subtly Compiletime visibility while (condition) { body } continue { another block } | | Fig. 2 Scopes in a while To the compiler, the loop has three different scopes (one each for the So, how should this be fixed? I think the best thing to do would be to Here's a patch (against 4_76, sorry) that does just that: Inline Patch--- op.c.old Sun Jul 26 20:16:44 1998
+++ op.c Mon Jul 27 14:30:55 1998
@@ -2972,7 +2972,10 @@
if (cont)
next = LINKLIST(cont);
if (expr) {
- cont = append_elem(OP_LINESEQ, cont, newOP(OP_UNSTACK, 0));
+ OP *unstack = newOP(OP_UNSTACK, 0);
+ if (!next)
+ next = unstack;
+ cont = append_elem(OP_LINESEQ, cont, unstack);
if ((line_t)whileline != NOLINE) {
PL_copline = whileline;
cont = append_elem(OP_LINESEQ, cont,
@@ -2995,8 +2998,6 @@
if (listop)
((LISTOP*)listop)->op_last->op_next = condop =
(o == listop ? redo : LINKLIST(o));
- if (!next)
- next = condop;
}
else
o = listop;
--- pp_ctl.c.old Mon Jul 27 12:28:01 1998
+++ pp_ctl.c Wed Jul 29 15:10:05 1998
@@ -1663,7 +1663,7 @@
{
I32 cxix;
register PERL_CONTEXT *cx;
- I32 oldsave;
+ I32 inner;
if (PL_op->op_flags & OPf_SPECIAL) {
cxix = dopoptoloop(cxstack_ix);
@@ -1678,9 +1678,12 @@
if (cxix < cxstack_ix)
dounwind(cxix);
+ /* Clear off anything above the scope we're re-entering, but
+ save the rest until after a possible continue block */
+ inner = PL_scopestack_ix;
TOPBLOCK(cx);
- oldsave = PL_scopestack[PL_scopestack_ix - 1];
- LEAVE_SCOPE(oldsave);
+ if (PL_scopestack_ix < inner)
+ leave_scope(PL_scopestack[PL_scopestack_ix]);
return cx->blk_loop.next_op;
}
@@ -1703,6 +1706,7 @@
if (cxix < cxstack_ix)
dounwind(cxix);
+ /* Restart the loop scope with a clean slate */
TOPBLOCK(cx);
oldsave = PL_scopestack[PL_scopestack_ix - 1];
LEAVE_SCOPE(oldsave);
[end of archive message] -- |
From @gsarOn Tue, 28 Mar 2000 21:06:27 CST, Stephen McCamant wrote:
I probably didn't realize it until well after change#4848, but this And come to think of it, POPSUB() could be diddling the wrong PL_curpad I think the most robust fix here would involve making dounwind() restore
Indeed, thanks for the catch.
Don't know how that one slipped through the cracks, but this adaptation Sarathy Inline Patch-----------------------------------8<-----------------------------------
Index: perl/op.c
--- perl/op.c.~1~ Tue Mar 28 20:17:04 2000
+++ perl/op.c Tue Mar 28 20:17:04 2000
@@ -3848,7 +3848,10 @@
loopflags |= OPpLOOP_CONTINUE;
}
if (expr) {
- cont = append_elem(OP_LINESEQ, cont, newOP(OP_UNSTACK, 0));
+ OP *unstack = newOP(OP_UNSTACK, 0);
+ if (!next)
+ next = unstack;
+ cont = append_elem(OP_LINESEQ, cont, unstack);
if ((line_t)whileline != NOLINE) {
PL_copline = whileline;
cont = append_elem(OP_LINESEQ, cont,
@@ -3871,8 +3874,6 @@
if (listop)
((LISTOP*)listop)->op_last->op_next = condop =
(o == listop ? redo : LINKLIST(o));
- if (!next)
- next = condop;
}
else
o = listop;
Index: perl/pp_ctl.c
--- perl/pp_ctl.c.~1~ Tue Mar 28 20:17:04 2000
+++ perl/pp_ctl.c Tue Mar 28 20:17:04 2000
@@ -1979,7 +1979,7 @@
{
I32 cxix;
register PERL_CONTEXT *cx;
- I32 oldsave;
+ I32 inner;
if (PL_op->op_flags & OPf_SPECIAL) {
cxix = dopoptoloop(cxstack_ix);
@@ -1994,13 +1994,12 @@
if (cxix < cxstack_ix)
dounwind(cxix);
+ /* clear off anything above the scope we're re-entering, but
+ * save the rest until after a possible continue block */
+ inner = PL_scopestack_ix;
TOPBLOCK(cx);
-
- /* clean scope, but only if there's no continue block */
- if (!(cx->blk_loop.last_op->op_private & OPpLOOP_CONTINUE)) {
- oldsave = PL_scopestack[PL_scopestack_ix - 1];
- LEAVE_SCOPE(oldsave);
- }
+ if (PL_scopestack_ix < inner)
+ leave_scope(PL_scopestack[PL_scopestack_ix]);
return cx->blk_loop.next_op;
}
End of Patch. |
Migrated from rt.perl.org#2001 (status was 'resolved')
Searchable as RT2001$
The text was updated successfully, but these errors were encountered: