[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index][Thread Index][Top&Search][Original]

Re: [ID 20000119.002] 'next' undefines variables in 'continue' block



On Wed, 19 Jan 2000 09:48:19 MST, oracle@tauceti.pcr.com wrote:
>File test_next:
>$^W = 1;
>my $x = 3;
>while(my $i = $x--) {
>   print "while block: \$i = $i\n";
>   next if $i == 2;
>} continue {
>   print "cont. block: \$i = $i\n";
>}
>Output:
>
>while block: $i = 3
>cont. block: $i = 3
>while block: $i = 2
>Use of uninitialized value at test_next line 5.
>cont. block: $i = 
>while block: $i = 1
>cont. block: $i = 1
>
>Also, when 'next' is used to jump to a labelled outer loop with a
>continue block, the same thing happens for variables declared in
>the outer block's control expression.
>
>After digging around in the perl source code, it seems that a 
>compiled while statement has an unstack op at the end.  Without
>a continue block, a next op jumps directly to the beginning of
>the while block, skipping the unstack op, and so has to do the
>unstacking itself.  With a continue block, the next op jumps right 
>into the continue block, but still does the unstacking.

Thanks for that accurate diagnosis of the problem.

I noticed another longstanding bug: local-ized values inside a while block
are visible in the continue block!

These two changes fix both problems.

There is one remaining problem with local-ized values still being visible
in the continue block after a next, but that will have to wait for another
day.


Sarathy
gsar@ActiveState.com
-----------------------------------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.


Follow-Ups from:
Tim Bunce <Tim.Bunce@ig.co.uk>
Larry Wall <larry@wall.org>
References to:
oracle@tauceti.pcr.com

[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index][Thread Index][Top&Search][Original]