PageRenderTime 54ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/perl-5.16.0/t/op/goto.t

#
Perl | 638 lines | 530 code | 79 blank | 29 comment | 47 complexity | 231a70a913e0a988b3c6d53726de1e0e MD5 | raw file
Possible License(s): AGPL-1.0
  1. #!./perl
  2. # "This IS structured code. It's just randomly structured."
  3. BEGIN {
  4. chdir 't' if -d 't';
  5. @INC = qw(. ../lib);
  6. require "test.pl";
  7. }
  8. use warnings;
  9. use strict;
  10. plan tests => 80;
  11. our $TODO;
  12. my $deprecated = 0;
  13. local $SIG{__WARN__} = sub { if ($_[0] =~ m/jump into a construct/) { $deprecated++; } else { warn $_[0] } };
  14. our $foo;
  15. while ($?) {
  16. $foo = 1;
  17. label1:
  18. is($deprecated, 1);
  19. $deprecated = 0;
  20. $foo = 2;
  21. goto label2;
  22. } continue {
  23. $foo = 0;
  24. goto label4;
  25. label3:
  26. is($deprecated, 1);
  27. $deprecated = 0;
  28. $foo = 4;
  29. goto label4;
  30. }
  31. is($deprecated, 0);
  32. goto label1;
  33. $foo = 3;
  34. label2:
  35. is($foo, 2, 'escape while loop');
  36. is($deprecated, 0);
  37. goto label3;
  38. label4:
  39. is($foo, 4, 'second escape while loop');
  40. my $r = run_perl(prog => 'goto foo;', stderr => 1);
  41. like($r, qr/label/, 'cant find label');
  42. my $ok = 0;
  43. sub foo {
  44. goto bar;
  45. return;
  46. bar:
  47. $ok = 1;
  48. }
  49. &foo;
  50. ok($ok, 'goto in sub');
  51. sub bar {
  52. my $x = 'bypass';
  53. eval "goto $x";
  54. }
  55. &bar;
  56. exit;
  57. FINALE:
  58. is(curr_test(), 20, 'FINALE');
  59. # does goto LABEL handle block contexts correctly?
  60. # note that this scope-hopping differs from last & next,
  61. # which always go up-scope strictly.
  62. my $count = 0;
  63. my $cond = 1;
  64. for (1) {
  65. if ($cond == 1) {
  66. $cond = 0;
  67. goto OTHER;
  68. }
  69. elsif ($cond == 0) {
  70. OTHER:
  71. $cond = 2;
  72. is($count, 0, 'OTHER');
  73. $count++;
  74. goto THIRD;
  75. }
  76. else {
  77. THIRD:
  78. is($count, 1, 'THIRD');
  79. $count++;
  80. }
  81. }
  82. is($count, 2, 'end of loop');
  83. # Does goto work correctly within a for(;;) loop?
  84. # (BUG ID 20010309.004)
  85. for(my $i=0;!$i++;) {
  86. my $x=1;
  87. goto label;
  88. label: is($x, 1, 'goto inside a for(;;) loop body from inside the body');
  89. }
  90. # Does goto work correctly going *to* a for(;;) loop?
  91. # (make sure it doesn't skip the initializer)
  92. my ($z, $y) = (0);
  93. FORL1: for ($y=1; $z;) {
  94. ok($y, 'goto a for(;;) loop, from outside (does initializer)');
  95. goto TEST19}
  96. ($y,$z) = (0, 1);
  97. goto FORL1;
  98. # Even from within the loop?
  99. TEST19: $z = 0;
  100. FORL2: for($y=1; 1;) {
  101. if ($z) {
  102. ok($y, 'goto a for(;;) loop, from inside (does initializer)');
  103. last;
  104. }
  105. ($y, $z) = (0, 1);
  106. goto FORL2;
  107. }
  108. # Does goto work correctly within a try block?
  109. # (BUG ID 20000313.004) - [perl #2359]
  110. $ok = 0;
  111. eval {
  112. my $variable = 1;
  113. goto LABEL20;
  114. LABEL20: $ok = 1 if $variable;
  115. };
  116. ok($ok, 'works correctly within a try block');
  117. is($@, "", '...and $@ not set');
  118. # And within an eval-string?
  119. $ok = 0;
  120. eval q{
  121. my $variable = 1;
  122. goto LABEL21;
  123. LABEL21: $ok = 1 if $variable;
  124. };
  125. ok($ok, 'works correctly within an eval string');
  126. is($@, "", '...and $@ still not set');
  127. # Test that goto works in nested eval-string
  128. $ok = 0;
  129. {eval q{
  130. eval q{
  131. goto LABEL22;
  132. };
  133. $ok = 0;
  134. last;
  135. LABEL22: $ok = 1;
  136. };
  137. $ok = 0 if $@;
  138. }
  139. ok($ok, 'works correctly in a nested eval string');
  140. {
  141. my $false = 0;
  142. my $count;
  143. $ok = 0;
  144. { goto A; A: $ok = 1 } continue { }
  145. ok($ok, '#20357 goto inside /{ } continue { }/ loop');
  146. $ok = 0;
  147. { do { goto A; A: $ok = 1 } while $false }
  148. ok($ok, '#20154 goto inside /do { } while ()/ loop');
  149. $ok = 0;
  150. foreach(1) { goto A; A: $ok = 1 } continue { };
  151. ok($ok, 'goto inside /foreach () { } continue { }/ loop');
  152. $ok = 0;
  153. sub a {
  154. A: { if ($false) { redo A; B: $ok = 1; redo A; } }
  155. goto B unless $count++;
  156. }
  157. is($deprecated, 0);
  158. a();
  159. ok($ok, '#19061 loop label wiped away by goto');
  160. is($deprecated, 1);
  161. $deprecated = 0;
  162. $ok = 0;
  163. my $p;
  164. for ($p=1;$p && goto A;$p=0) { A: $ok = 1 }
  165. ok($ok, 'weird case of goto and for(;;) loop');
  166. is($deprecated, 1);
  167. $deprecated = 0;
  168. }
  169. # bug #9990 - don't prematurely free the CV we're &going to.
  170. sub f1 {
  171. my $x;
  172. goto sub { $x=0; ok(1,"don't prematurely free CV\n") }
  173. }
  174. f1();
  175. # bug #99850, which is similar - freeing the subroutine we are about to
  176. # go(in)to during a FREETMPS call should not crash perl.
  177. package _99850 {
  178. sub reftype{}
  179. DESTROY { undef &reftype }
  180. eval { sub { my $guard = bless []; goto &reftype }->() };
  181. }
  182. like $@, qr/^Goto undefined subroutine &_99850::reftype at /,
  183. 'goto &foo undefining &foo on sub cleanup';
  184. # bug #22181 - this used to coredump or make $x undefined, due to
  185. # erroneous popping of the inner BLOCK context
  186. undef $ok;
  187. for ($count=0; $count<2; $count++) {
  188. my $x = 1;
  189. goto LABEL29;
  190. LABEL29:
  191. $ok = $x;
  192. }
  193. is($ok, 1, 'goto in for(;;) with continuation');
  194. # bug #22299 - goto in require doesn't find label
  195. open my $f, ">Op_goto01.pm" or die;
  196. print $f <<'EOT';
  197. package goto01;
  198. goto YYY;
  199. die;
  200. YYY: print "OK\n";
  201. 1;
  202. EOT
  203. close $f;
  204. $r = runperl(prog => 'use Op_goto01; print qq[DONE\n]');
  205. is($r, "OK\nDONE\n", "goto within use-d file");
  206. unlink_all "Op_goto01.pm";
  207. # test for [perl #24108]
  208. $ok = 1;
  209. $count = 0;
  210. sub i_return_a_label {
  211. $count++;
  212. return "returned_label";
  213. }
  214. eval { goto +i_return_a_label; };
  215. $ok = 0;
  216. returned_label:
  217. is($count, 1, 'called i_return_a_label');
  218. ok($ok, 'skipped to returned_label');
  219. # [perl #29708] - goto &foo could leave foo() at depth two with
  220. # @_ == PL_sv_undef, causing a coredump
  221. $r = runperl(
  222. prog =>
  223. 'sub f { return if $d; $d=1; my $a=sub {goto &f}; &$a; f() } f(); print qq(ok\n)',
  224. stderr => 1
  225. );
  226. is($r, "ok\n", 'avoid pad without an @_');
  227. goto moretests;
  228. fail('goto moretests');
  229. exit;
  230. bypass:
  231. is(curr_test(), 9, 'eval "goto $x"');
  232. # Test autoloading mechanism.
  233. sub two {
  234. my ($pack, $file, $line) = caller; # Should indicate original call stats.
  235. is("@_ $pack $file $line", "1 2 3 main $::FILE $::LINE",
  236. 'autoloading mechanism.');
  237. }
  238. sub one {
  239. eval <<'END';
  240. no warnings 'redefine';
  241. sub one { pass('sub one'); goto &two; fail('sub one tail'); }
  242. END
  243. goto &one;
  244. }
  245. $::FILE = __FILE__;
  246. $::LINE = __LINE__ + 1;
  247. &one(1,2,3);
  248. {
  249. my $wherever = 'NOWHERE';
  250. eval { goto $wherever };
  251. like($@, qr/Can't find label NOWHERE/, 'goto NOWHERE sets $@');
  252. }
  253. # see if a modified @_ propagates
  254. {
  255. my $i;
  256. package Foo;
  257. sub DESTROY { my $s = shift; ::is($s->[0], $i, "destroy $i"); }
  258. sub show { ::is(+@_, 5, "show $i",); }
  259. sub start { push @_, 1, "foo", {}; goto &show; }
  260. for (1..3) { $i = $_; start(bless([$_]), 'bar'); }
  261. }
  262. sub auto {
  263. goto &loadit;
  264. }
  265. sub AUTOLOAD { $ok = 1 if "@_" eq "foo" }
  266. $ok = 0;
  267. auto("foo");
  268. ok($ok, 'autoload');
  269. {
  270. my $wherever = 'FINALE';
  271. goto $wherever;
  272. }
  273. fail('goto $wherever');
  274. moretests:
  275. # test goto duplicated labels.
  276. {
  277. my $z = 0;
  278. eval {
  279. $z = 0;
  280. for (0..1) {
  281. L4: # not outer scope
  282. $z += 10;
  283. last;
  284. }
  285. goto L4 if $z == 10;
  286. last;
  287. };
  288. like($@, qr/Can't "goto" into the middle of a foreach loop/,
  289. 'catch goto middle of foreach');
  290. $z = 0;
  291. # ambiguous label resolution (outer scope means endless loop!)
  292. L1:
  293. for my $x (0..1) {
  294. $z += 10;
  295. is($z, 10, 'prefer same scope (loop body) to outer scope (loop entry)');
  296. goto L1 unless $x;
  297. $z += 10;
  298. L1:
  299. is($z, 10, 'prefer same scope: second');
  300. last;
  301. }
  302. $z = 0;
  303. L2:
  304. {
  305. $z += 10;
  306. is($z, 10, 'prefer this scope (block body) to outer scope (block entry)');
  307. goto L2 if $z == 10;
  308. $z += 10;
  309. L2:
  310. is($z, 10, 'prefer this scope: second');
  311. }
  312. {
  313. $z = 0;
  314. while (1) {
  315. L3: # not inner scope
  316. $z += 10;
  317. last;
  318. }
  319. is($z, 10, 'prefer this scope to inner scope');
  320. goto L3 if $z == 10;
  321. $z += 10;
  322. L3: # this scope !
  323. is($z, 10, 'prefer this scope to inner scope: second');
  324. }
  325. L4: # not outer scope
  326. {
  327. $z = 0;
  328. while (1) {
  329. L4: # not inner scope
  330. $z += 1;
  331. last;
  332. }
  333. is($z, 1, 'prefer this scope to inner,outer scopes');
  334. goto L4 if $z == 1;
  335. $z += 10;
  336. L4: # this scope !
  337. is($z, 1, 'prefer this scope to inner,outer scopes: second');
  338. }
  339. {
  340. my $loop = 0;
  341. for my $x (0..1) {
  342. L2: # without this, fails 1 (middle) out of 3 iterations
  343. $z = 0;
  344. L2:
  345. $z += 10;
  346. is($z, 10,
  347. "same label, multiple times in same scope (choose 1st) $loop");
  348. goto L2 if $z == 10 and not $loop++;
  349. }
  350. }
  351. }
  352. # deep recursion with gotos eventually caused a stack reallocation
  353. # which messed up buggy internals that didn't expect the stack to move
  354. sub recurse1 {
  355. unshift @_, "x";
  356. no warnings 'recursion';
  357. goto &recurse2;
  358. }
  359. sub recurse2 {
  360. my $x = shift;
  361. $_[0] ? +1 + recurse1($_[0] - 1) : 0
  362. }
  363. my $w = 0;
  364. $SIG{__WARN__} = sub { ++$w };
  365. is(recurse1(500), 500, 'recursive goto &foo');
  366. is $w, 0, 'no recursion warnings for "no warnings; goto &sub"';
  367. delete $SIG{__WARN__};
  368. # [perl #32039] Chained goto &sub drops data too early.
  369. sub a32039 { @_=("foo"); goto &b32039; }
  370. sub b32039 { goto &c32039; }
  371. sub c32039 { is($_[0], 'foo', 'chained &goto') }
  372. a32039();
  373. # [perl #35214] next and redo re-entered the loop with the wrong cop,
  374. # causing a subsequent goto to crash
  375. {
  376. my $r = runperl(
  377. stderr => 1,
  378. prog =>
  379. 'for ($_=0;$_<3;$_++){A: if($_==1){next} if($_==2){$_++;goto A}}print qq(ok\n)'
  380. );
  381. is($r, "ok\n", 'next and goto');
  382. $r = runperl(
  383. stderr => 1,
  384. prog =>
  385. 'for ($_=0;$_<3;$_++){A: if($_==1){$_++;redo} if($_==2){$_++;goto A}}print qq(ok\n)'
  386. );
  387. is($r, "ok\n", 'redo and goto');
  388. }
  389. # goto &foo not allowed in evals
  390. sub null { 1 };
  391. eval 'goto &null';
  392. like($@, qr/Can't goto subroutine from an eval-string/, 'eval string');
  393. eval { goto &null };
  394. like($@, qr/Can't goto subroutine from an eval-block/, 'eval block');
  395. # [perl #36521] goto &foo in warn handler could defeat recursion avoider
  396. {
  397. my $r = runperl(
  398. stderr => 1,
  399. prog => 'my $d; my $w = sub { return if $d++; warn q(bar)}; local $SIG{__WARN__} = sub { goto &$w; }; warn q(foo);'
  400. );
  401. like($r, qr/bar/, "goto &foo in warn");
  402. }
  403. TODO: {
  404. local $TODO = "[perl #43403] goto() from an if to an else doesn't undo local () changes";
  405. our $global = "unmodified";
  406. if ($global) { # true but not constant-folded
  407. local $global = "modified";
  408. goto ELSE;
  409. } else {
  410. ELSE: is($global, "unmodified");
  411. }
  412. }
  413. is($deprecated, 0);
  414. #74290
  415. {
  416. my $x;
  417. my $y;
  418. F1:++$x and eval 'return if ++$y == 10; goto F1;';
  419. is($x, 10,
  420. 'labels outside evals can be distinguished from the start of the eval');
  421. }
  422. goto wham_eth;
  423. die "You can't get here";
  424. wham_eth: 1 if 0;
  425. ouch_eth: pass('labels persist even if their statement is optimised away');
  426. $foo = "(0)";
  427. if($foo eq $foo) {
  428. goto bungo;
  429. }
  430. $foo .= "(9)";
  431. bungo:
  432. format CHOLET =
  433. wellington
  434. .
  435. $foo .= "(1)";
  436. SKIP: {
  437. skip_if_miniperl("no dynamic loading on miniperl, so can't load PerlIO::scalar", 1);
  438. my $cholet;
  439. open(CHOLET, ">", \$cholet);
  440. write CHOLET;
  441. close CHOLET;
  442. $foo .= "(".$cholet.")";
  443. is($foo, "(0)(1)(wellington\n)", "label before format decl");
  444. }
  445. $foo = "(A)";
  446. if($foo eq $foo) {
  447. goto orinoco;
  448. }
  449. $foo .= "(X)";
  450. orinoco:
  451. sub alderney { return "tobermory"; }
  452. $foo .= "(B)";
  453. $foo .= "(".alderney().")";
  454. is($foo, "(A)(B)(tobermory)", "label before sub decl");
  455. $foo = "[0:".__PACKAGE__."]";
  456. if($foo eq $foo) {
  457. goto bulgaria;
  458. }
  459. $foo .= "[9]";
  460. bulgaria:
  461. package Tomsk;
  462. $foo .= "[1:".__PACKAGE__."]";
  463. $foo .= "[2:".__PACKAGE__."]";
  464. package main;
  465. $foo .= "[3:".__PACKAGE__."]";
  466. is($foo, "[0:main][1:Tomsk][2:Tomsk][3:main]", "label before package decl");
  467. $foo = "[A:".__PACKAGE__."]";
  468. if($foo eq $foo) {
  469. goto adelaide;
  470. }
  471. $foo .= "[Z]";
  472. adelaide:
  473. package Cairngorm {
  474. $foo .= "[B:".__PACKAGE__."]";
  475. }
  476. $foo .= "[C:".__PACKAGE__."]";
  477. is($foo, "[A:main][B:Cairngorm][C:main]", "label before package block");
  478. our $obidos;
  479. $foo = "{0}";
  480. if($foo eq $foo) {
  481. goto shansi;
  482. }
  483. $foo .= "{9}";
  484. shansi:
  485. BEGIN { $obidos = "x"; }
  486. $foo .= "{1$obidos}";
  487. is($foo, "{0}{1x}", "label before BEGIN block");
  488. $foo = "{A:".(1.5+1.5)."}";
  489. if($foo eq $foo) {
  490. goto stepney;
  491. }
  492. $foo .= "{Z}";
  493. stepney:
  494. use integer;
  495. $foo .= "{B:".(1.5+1.5)."}";
  496. is($foo, "{A:3}{B:2}", "label before use decl");
  497. $foo = "<0>";
  498. if($foo eq $foo) {
  499. goto tom;
  500. }
  501. $foo .= "<9>";
  502. tom: dick: harry:
  503. $foo .= "<1>";
  504. $foo .= "<2>";
  505. is($foo, "<0><1><2>", "first of three stacked labels");
  506. $foo = "<A>";
  507. if($foo eq $foo) {
  508. goto beta;
  509. }
  510. $foo .= "<Z>";
  511. alpha: beta: gamma:
  512. $foo .= "<B>";
  513. $foo .= "<C>";
  514. is($foo, "<A><B><C>", "second of three stacked labels");
  515. $foo = ",0.";
  516. if($foo eq $foo) {
  517. goto gimel;
  518. }
  519. $foo .= ",9.";
  520. alef: bet: gimel:
  521. $foo .= ",1.";
  522. $foo .= ",2.";
  523. is($foo, ",0.,1.,2.", "third of three stacked labels");
  524. # [perl #112316] Wrong behavior regarding labels with same prefix
  525. sub same_prefix_labels {
  526. my $pass;
  527. my $first_time = 1;
  528. CATCH: {
  529. if ( $first_time ) {
  530. CATCHLOOP: {
  531. if ( !$first_time ) {
  532. return 0;
  533. }
  534. $first_time--;
  535. goto CATCH;
  536. }
  537. }
  538. else {
  539. return 1;
  540. }
  541. }
  542. }
  543. ok(
  544. same_prefix_labels(),
  545. "perl 112316: goto and labels with the same prefix doesn't get mixed up"
  546. );