Re: trying to fix #20154, #20357
Adrian M. Enache [Sat, 8 Feb 2003 21:05:14 +0000 (23:05 +0200)]
Message-ID: <20030208190514.GA866@ratsnest.hole>
(fixes #19061 as well)

p4raw-id: //depot/perl@18703

pp_ctl.c
t/op/goto.t

index 73d1365..5699b7c 100644 (file)
--- a/pp_ctl.c
+++ b/pp_ctl.c
@@ -2015,6 +2015,7 @@ S_dofindlabel(pTHX_ OP *o, char *label, OP **opstack, OP **oplimit)
     if (o->op_type == OP_LEAVE ||
        o->op_type == OP_SCOPE ||
        o->op_type == OP_LEAVELOOP ||
+       o->op_type == OP_LEAVESUB ||
        o->op_type == OP_LEAVETRY)
     {
        *ops++ = cUNOPo->op_first;
@@ -2273,6 +2274,7 @@ PP(pp_goto)
     if (label && *label) {
        OP *gotoprobe = 0;
        bool leaving_eval = FALSE;
+       bool in_block = FALSE;
         PERL_CONTEXT *last_eval_cx = 0;
 
        /* find label */
@@ -2298,9 +2300,10 @@ PP(pp_goto)
            case CXt_SUBST:
                continue;
            case CXt_BLOCK:
-               if (ix)
+               if (ix) {
                    gotoprobe = cx->blk_oldcop->op_sibling;
-               else
+                   in_block = TRUE;
+               } else
                    gotoprobe = PL_main_root;
                break;
            case CXt_SUB:
@@ -2357,7 +2360,8 @@ PP(pp_goto)
 
        if (*enterops && enterops[1]) {
            OP *oldop = PL_op;
-           for (ix = 1; enterops[ix]; ix++) {
+           ix = enterops[1]->op_type == OP_ENTER && in_block ? 2 : 1;
+           for (; enterops[ix]; ix++) {
                PL_op = enterops[ix];
                /* Eventually we may want to stack the needed arguments
                 * for each op.  For now, we punt on the hard ones. */
index a0b4d55..122c624 100755 (executable)
@@ -2,7 +2,7 @@
 
 # "This IS structured code.  It's just randomly structured."
 
-print "1..22\n";
+print "1..27\n";
 
 while ($?) {
     $foo = 1;
@@ -144,6 +144,39 @@ $ok = 0 if $@;
 }
 print ($ok ? "ok 22\n" : "not ok 22\n");
 
+{
+    my $false = 0;
+
+    $ok = 0;
+    { goto A; A: $ok = 1 } continue { }
+    print "not " unless $ok;
+    print "ok 23 - #20357 goto inside /{ } continue { }/ loop\n";
+
+    $ok = 0;
+    { do { goto A; A: $ok = 1 } while $false }
+    print "not " unless $ok;
+    print "ok 24 - #20154 goto inside /do { } while ()/ loop\n";
+
+    $ok = 0;
+    foreach(1) { goto A; A: $ok = 1 } continue { };
+    print "not " unless $ok;
+    print "ok 25 - goto inside /foreach () { } continue { }/ loop\n";
+
+    $ok = 0;
+    sub a {
+       A: { if ($false) { redo A; B: $ok = 1; redo A; } }
+       goto B unless $r++
+    }
+    a();
+    print "not " unless $ok;
+    print "ok 26 - #19061 loop label wiped away by goto\n";
+
+    $ok = 0;
+    for ($p=1;$p && goto A;$p=0) { A: $ok = 1 }
+    print "not " unless $ok;
+    print "ok 27 - weird case of goto and for(;;) loop\n";
+}
+
 exit;
 
 bypass: