source: trunk/essentials/dev-lang/perl/t/op/goto.t

Last change on this file was 3181, checked in by bird, 18 years ago

perl 5.8.8

File size: 8.5 KB
Line 
1#!./perl
2
3# "This IS structured code. It's just randomly structured."
4
5BEGIN {
6 chdir 't' if -d 't';
7 @INC = qw(. ../lib);
8 require "test.pl";
9}
10
11use warnings;
12use strict;
13plan tests => 57;
14
15our $foo;
16while ($?) {
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}
28goto label1;
29
30$foo = 3;
31
32label2:
33is($foo, 2, 'escape while loop');
34goto label3;
35
36label4:
37is($foo, 4, 'second escape while loop');
38
39my $r = run_perl(prog => 'goto foo;', stderr => 1);
40like($r, qr/label/, 'cant find label');
41
42my $ok = 0;
43sub foo {
44 goto bar;
45 return;
46bar:
47 $ok = 1;
48}
49
50&foo;
51ok($ok, 'goto in sub');
52
53sub bar {
54 my $x = 'bypass';
55 eval "goto $x";
56}
57
58&bar;
59exit;
60
61FINALE:
62is(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.
67my $count = 0;
68my $cond = 1;
69for (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}
87is($count, 2, 'end of loop');
88
89# Does goto work correctly within a for(;;) loop?
90# (BUG ID 20010309.004)
91
92for(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
101my ($z, $y) = (0);
102FORL1: for ($y=1; $z;) {
103 ok($y, 'goto a for(;;) loop, from outside (does initializer)');
104 goto TEST19}
105($y,$z) = (0, 1);
106goto FORL1;
107
108# Even from within the loop?
109TEST19: $z = 0;
110FORL2: 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;
122eval {
123 my $variable = 1;
124 goto LABEL20;
125 LABEL20: $ok = 1 if $variable;
126};
127ok($ok, 'works correctly within a try block');
128is($@, "", '...and $@ not set');
129
130# And within an eval-string?
131$ok = 0;
132eval q{
133 my $variable = 1;
134 goto LABEL21;
135 LABEL21: $ok = 1 if $variable;
136};
137ok($ok, 'works correctly within an eval string');
138is($@, "", '...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}
154ok($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
187sub f1 {
188 my $x;
189 goto sub { $x=0; ok(1,"don't prematurely free CV\n") }
190}
191f1();
192
193# bug #22181 - this used to coredump or make $x undefined, due to
194# erroneous popping of the inner BLOCK context
195
196undef $ok;
197for ($count=0; $count<2; $count++) {
198 my $x = 1;
199 goto LABEL29;
200 LABEL29:
201 $ok = $x;
202}
203is($ok, 1, 'goto in for(;;) with continuation');
204
205# bug #22299 - goto in require doesn't find label
206
207open my $f, ">goto01.pm" or die;
208print $f <<'EOT';
209package goto01;
210goto YYY;
211die;
212YYY: print "OK\n";
2131;
214EOT
215close $f;
216
217$r = runperl(prog => 'use goto01; print qq[DONE\n]');
218is($r, "OK\nDONE\n", "goto within use-d file");
219unlink "goto01.pm";
220
221# test for [perl #24108]
222$ok = 1;
223$count = 0;
224sub i_return_a_label {
225 $count++;
226 return "returned_label";
227}
228eval { goto +i_return_a_label; };
229$ok = 0;
230
231returned_label:
232is($count, 1, 'called i_return_a_label');
233ok($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 );
244is($r, "ok\n", 'avoid pad without an @_');
245
246goto moretests;
247fail('goto moretests');
248exit;
249
250bypass:
251
252is(curr_test(), 5, 'eval "goto $x"');
253
254# Test autoloading mechanism.
255
256sub 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
262sub one {
263 eval <<'END';
264 no warnings 'redefine';
265 sub one { pass('sub one'); goto &two; fail('sub one tail'); }
266END
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
290sub auto {
291 goto &loadit;
292}
293
294sub AUTOLOAD { $ok = 1 if "@_" eq "foo" }
295
296$ok = 0;
297auto("foo");
298ok($ok, 'autoload');
299
300{
301 my $wherever = 'FINALE';
302 goto $wherever;
303}
304fail('goto $wherever');
305
306moretests:
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
394sub recurse1 {
395 unshift @_, "x";
396 no warnings 'recursion';
397 goto &recurse2;
398}
399sub recurse2 {
400 my $x = shift;
401 $_[0] ? +1 + recurse1($_[0] - 1) : 0
402}
403is(recurse1(500), 500, 'recursive goto &foo');
404
405# [perl #32039] Chained goto &sub drops data too early.
406
407sub a32039 { @_=("foo"); goto &b32039; }
408sub b32039 { goto &c32039; }
409sub c32039 { is($_[0], 'foo', 'chained &goto') }
410a32039();
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
434sub null { 1 };
435eval 'goto &null';
436like($@, qr/Can't goto subroutine from an eval-string/, 'eval string');
437eval { goto &null };
438like($@, 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}
Note: See TracBrowser for help on using the repository browser.