This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Re: Change 29723 breaks t/op/inccode-tie.t on Win32
[perl5.git] / t / op / goto.t
1 #!./perl
2
3 # "This IS structured code.  It's just randomly structured."
4
5 BEGIN {
6     chdir 't' if -d 't';
7     @INC = qw(. ../lib);
8     require "test.pl";
9 }
10
11 use warnings;
12 use strict;
13 plan tests => 57;
14
15 our $foo;
16 while ($?) {
17     $foo = 1;
18   label1:
19     $foo = 2;
20     goto label2;
21 } continue {
22     $foo = 0;
23     goto label4;
24   label3:
25     $foo = 4;
26     goto label4;
27 }
28 goto label1;
29
30 $foo = 3;
31
32 label2:
33 is($foo, 2, 'escape while loop');
34 goto label3;
35
36 label4:
37 is($foo, 4, 'second escape while loop');
38
39 my $r = run_perl(prog => 'goto foo;', stderr => 1);
40 like($r, qr/label/, 'cant find label');
41
42 my $ok = 0;
43 sub foo {
44     goto bar;
45     return;
46 bar:
47     $ok = 1;
48 }
49
50 &foo;
51 ok($ok, 'goto in sub');
52
53 sub bar {
54     my $x = 'bypass';
55     eval "goto $x";
56 }
57
58 &bar;
59 exit;
60
61 FINALE:
62 is(curr_test(), 16, 'FINALE');
63
64 # does goto LABEL handle block contexts correctly?
65 # note that this scope-hopping differs from last & next,
66 # which always go up-scope strictly.
67 my $count = 0;
68 my $cond = 1;
69 for (1) {
70     if ($cond == 1) {
71         $cond = 0;
72         goto OTHER;
73     }
74     elsif ($cond == 0) {
75       OTHER:
76         $cond = 2;
77         is($count, 0, 'OTHER');
78         $count++;
79         goto THIRD;
80     }
81     else {
82       THIRD:
83         is($count, 1, 'THIRD');
84         $count++;
85     }
86 }
87 is($count, 2, 'end of loop');
88
89 # Does goto work correctly within a for(;;) loop?
90 #  (BUG ID 20010309.004)
91
92 for(my $i=0;!$i++;) {
93   my $x=1;
94   goto label;
95   label: is($x, 1, 'goto inside a for(;;) loop body from inside the body');
96 }
97
98 # Does goto work correctly going *to* a for(;;) loop?
99 #  (make sure it doesn't skip the initializer)
100
101 my ($z, $y) = (0);
102 FORL1: for ($y=1; $z;) {
103     ok($y, 'goto a for(;;) loop, from outside (does initializer)');
104     goto TEST19}
105 ($y,$z) = (0, 1);
106 goto FORL1;
107
108 # Even from within the loop?
109 TEST19: $z = 0;
110 FORL2: for($y=1; 1;) {
111   if ($z) {
112     ok($y, 'goto a for(;;) loop, from inside (does initializer)');
113     last;
114   }
115   ($y, $z) = (0, 1);
116   goto FORL2;
117 }
118
119 # Does goto work correctly within a try block?
120 #  (BUG ID 20000313.004) - [perl #2359]
121 $ok = 0;
122 eval {
123   my $variable = 1;
124   goto LABEL20;
125   LABEL20: $ok = 1 if $variable;
126 };
127 ok($ok, 'works correctly within a try block');
128 is($@, "", '...and $@ not set');
129
130 # And within an eval-string?
131 $ok = 0;
132 eval q{
133   my $variable = 1;
134   goto LABEL21;
135   LABEL21: $ok = 1 if $variable;
136 };
137 ok($ok, 'works correctly within an eval string');
138 is($@, "", '...and $@ still not set');
139
140
141 # Test that goto works in nested eval-string
142 $ok = 0;
143 {eval q{
144   eval q{
145     goto LABEL22;
146   };
147   $ok = 0;
148   last;
149
150   LABEL22: $ok = 1;
151 };
152 $ok = 0 if $@;
153 }
154 ok($ok, 'works correctly in a nested eval string');
155
156 {
157     my $false = 0;
158     my $count;
159
160     $ok = 0;
161     { goto A; A: $ok = 1 } continue { }
162     ok($ok, '#20357 goto inside /{ } continue { }/ loop');
163
164     $ok = 0;
165     { do { goto A; A: $ok = 1 } while $false }
166     ok($ok, '#20154 goto inside /do { } while ()/ loop');
167     $ok = 0;
168     foreach(1) { goto A; A: $ok = 1 } continue { };
169     ok($ok, 'goto inside /foreach () { } continue { }/ loop');
170
171     $ok = 0;
172     sub a {
173         A: { if ($false) { redo A; B: $ok = 1; redo A; } }
174         goto B unless $count++;
175     }
176     a();
177     ok($ok, '#19061 loop label wiped away by goto');
178
179     $ok = 0;
180     my $p;
181     for ($p=1;$p && goto A;$p=0) { A: $ok = 1 }
182     ok($ok, 'weird case of goto and for(;;) loop');
183 }
184
185 # bug #9990 - don't prematurely free the CV we're &going to.
186
187 sub f1 {
188     my $x;
189     goto sub { $x=0; ok(1,"don't prematurely free CV\n") }
190 }
191 f1();
192
193 # bug #22181 - this used to coredump or make $x undefined, due to
194 # erroneous popping of the inner BLOCK context
195
196 undef $ok;
197 for ($count=0; $count<2; $count++) {
198     my $x = 1;
199     goto LABEL29;
200     LABEL29:
201     $ok = $x;
202 }
203 is($ok, 1, 'goto in for(;;) with continuation');
204
205 # bug #22299 - goto in require doesn't find label
206
207 open my $f, ">goto01.pm" or die;
208 print $f <<'EOT';
209 package goto01;
210 goto YYY;
211 die;
212 YYY: print "OK\n";
213 1;
214 EOT
215 close $f;
216
217 $r = runperl(prog => 'use goto01; print qq[DONE\n]');
218 is($r, "OK\nDONE\n", "goto within use-d file"); 
219 unlink "goto01.pm";
220
221 # test for [perl #24108]
222 $ok = 1;
223 $count = 0;
224 sub i_return_a_label {
225     $count++;
226     return "returned_label";
227 }
228 eval { goto +i_return_a_label; };
229 $ok = 0;
230
231 returned_label:
232 is($count, 1, 'called i_return_a_label');
233 ok($ok, 'skipped to returned_label');
234
235 # [perl #29708] - goto &foo could leave foo() at depth two with
236 # @_ == PL_sv_undef, causing a coredump
237
238
239 $r = runperl(
240     prog =>
241         'sub f { return if $d; $d=1; my $a=sub {goto &f}; &$a; f() } f(); print qq(ok\n)',
242     stderr => 1
243     );
244 is($r, "ok\n", 'avoid pad without an @_');
245
246 goto moretests;
247 fail('goto moretests');
248 exit;
249
250 bypass:
251
252 is(curr_test(), 5, 'eval "goto $x"');
253
254 # Test autoloading mechanism.
255
256 sub two {
257     my ($pack, $file, $line) = caller;  # Should indicate original call stats.
258     is("@_ $pack $file $line", "1 2 3 main $::FILE $::LINE",
259         'autoloading mechanism.');
260 }
261
262 sub one {
263     eval <<'END';
264     no warnings 'redefine';
265     sub one { pass('sub one'); goto &two; fail('sub one tail'); }
266 END
267     goto &one;
268 }
269
270 $::FILE = __FILE__;
271 $::LINE = __LINE__ + 1;
272 &one(1,2,3);
273
274 {
275     my $wherever = 'NOWHERE';
276     eval { goto $wherever };
277     like($@, qr/Can't find label NOWHERE/, 'goto NOWHERE sets $@');
278 }
279
280 # see if a modified @_ propagates
281 {
282   my $i;
283   package Foo;
284   sub DESTROY   { my $s = shift; ::is($s->[0], $i, "destroy $i"); }
285   sub show      { ::is(+@_, 5, "show $i",); }
286   sub start     { push @_, 1, "foo", {}; goto &show; }
287   for (1..3)    { $i = $_; start(bless([$_]), 'bar'); }
288 }
289
290 sub auto {
291     goto &loadit;
292 }
293
294 sub AUTOLOAD { $ok = 1 if "@_" eq "foo" }
295
296 $ok = 0;
297 auto("foo");
298 ok($ok, 'autoload');
299
300 {
301     my $wherever = 'FINALE';
302     goto $wherever;
303 }
304 fail('goto $wherever');
305
306 moretests:
307 # test goto duplicated labels.
308 {
309     my $z = 0;
310     eval {
311         $z = 0;
312         for (0..1) {
313           L4: # not outer scope
314             $z += 10;
315             last;
316         }
317         goto L4 if $z == 10;
318         last;
319     };
320     like($@, qr/Can't "goto" into the middle of a foreach loop/,
321             'catch goto middle of foreach');
322
323     $z = 0;
324     # ambiguous label resolution (outer scope means endless loop!)
325   L1:
326     for my $x (0..1) {
327         $z += 10;
328         is($z, 10, 'prefer same scope (loop body) to outer scope (loop entry)');
329         goto L1 unless $x;
330         $z += 10;
331       L1:
332         is($z, 10, 'prefer same scope: second');
333         last;
334     }
335
336     $z = 0;
337   L2: 
338     { 
339         $z += 10;
340         is($z, 10, 'prefer this scope (block body) to outer scope (block entry)');
341         goto L2 if $z == 10;
342         $z += 10;
343       L2:
344         is($z, 10, 'prefer this scope: second');
345     }
346
347
348     { 
349         $z = 0;
350         while (1) {
351           L3: # not inner scope
352             $z += 10;
353             last;
354         }
355         is($z, 10, 'prefer this scope to inner scope');
356         goto L3 if $z == 10;
357         $z += 10;
358       L3: # this scope !
359         is($z, 10, 'prefer this scope to inner scope: second');
360     }
361
362   L4: # not outer scope
363     { 
364         $z = 0;
365         while (1) {
366           L4: # not inner scope
367             $z += 1;
368             last;
369         }
370         is($z, 1, 'prefer this scope to inner,outer scopes');
371         goto L4 if $z == 1;
372         $z += 10;
373       L4: # this scope !
374         is($z, 1, 'prefer this scope to inner,outer scopes: second');
375     }
376
377     {
378         my $loop = 0;
379         for my $x (0..1) { 
380           L2: # without this, fails 1 (middle) out of 3 iterations
381             $z = 0;
382           L2: 
383             $z += 10;
384             is($z, 10,
385                 "same label, multiple times in same scope (choose 1st) $loop");
386             goto L2 if $z == 10 and not $loop++;
387         }
388     }
389 }
390
391 # deep recursion with gotos eventually caused a stack reallocation
392 # which messed up buggy internals that didn't expect the stack to move
393
394 sub recurse1 {
395     unshift @_, "x";
396     no warnings 'recursion';
397     goto &recurse2;
398 }
399 sub recurse2 {
400     my $x = shift;
401     $_[0] ? +1 + recurse1($_[0] - 1) : 0
402 }
403 is(recurse1(500), 500, 'recursive goto &foo');
404
405 # [perl #32039] Chained goto &sub drops data too early. 
406
407 sub a32039 { @_=("foo"); goto &b32039; }
408 sub b32039 { goto &c32039; }
409 sub c32039 { is($_[0], 'foo', 'chained &goto') }
410 a32039();
411
412 # [perl #35214] next and redo re-entered the loop with the wrong cop,
413 # causing a subsequent goto to crash
414
415 {
416     my $r = runperl(
417                 stderr => 1,
418                 prog =>
419 'for ($_=0;$_<3;$_++){A: if($_==1){next} if($_==2){$_++;goto A}}print qq(ok\n)'
420     );
421     is($r, "ok\n", 'next and goto');
422
423     $r = runperl(
424                 stderr => 1,
425                 prog =>
426 'for ($_=0;$_<3;$_++){A: if($_==1){$_++;redo} if($_==2){$_++;goto A}}print qq(ok\n)'
427     );
428     is($r, "ok\n", 'redo and goto');
429 }
430
431 # goto &foo not allowed in evals
432
433
434 sub null { 1 };
435 eval 'goto &null';
436 like($@, qr/Can't goto subroutine from an eval-string/, 'eval string');
437 eval { goto &null };
438 like($@, qr/Can't goto subroutine from an eval-block/, 'eval block');
439
440 # [perl #36521] goto &foo in warn handler could defeat recursion avoider
441
442 {
443     my $r = runperl(
444                 stderr => 1,
445                 prog => 'my $d; my $w = sub { return if $d++; warn q(bar)}; local $SIG{__WARN__} = sub { goto &$w; }; warn q(foo);'
446     );
447     like($r, qr/bar/, "goto &foo in warn");
448 }