Suppress a few compilation warnings in pp_hot.c.
[p5sagit/p5-mst-13.2.git] / t / op / closure.t
CommitLineData
0a753a76 1#!./perl
2# -*- Mode: Perl -*-
3# closure.t:
4# Original written by Ulrich Pfeifer on 2 Jan 1997.
5# Greatly extended by Tom Phoenix <rootbeer@teleport.com> on 28 Jan 1997.
6#
a16a9fa3 7# Run with -debug for debugging output.
0a753a76 8
f86702cc 9BEGIN {
10 chdir 't' if -d 't';
20822f61 11 @INC = '../lib';
f86702cc 12}
13
14use Config;
15
7dafbf52 16print "1..181\n";
0a753a76 17
18my $test = 1;
19sub test (&) {
a16a9fa3 20 my $ok = &{$_[0]};
21 print $ok ? "ok $test\n" : "not ok $test\n";
22 printf "# Failed at line %d\n", (caller)[2] unless $ok;
0a753a76 23 $test++;
24}
25
26my $i = 1;
27sub foo { $i = shift if @_; $i }
28
29# no closure
30test { foo == 1 };
31foo(2);
32test { foo == 2 };
33
34# closure: lexical outside sub
35my $foo = sub {$i = shift if @_; $i };
36my $bar = sub {$i = shift if @_; $i };
37test {&$foo() == 2 };
38&$foo(3);
39test {&$foo() == 3 };
40# did the lexical change?
41test { foo == 3 and $i == 3};
42# did the second closure notice?
43test {&$bar() == 3 };
44
45# closure: lexical inside sub
46sub bar {
47 my $i = shift;
48 sub { $i = shift if @_; $i }
49}
50
51$foo = bar(4);
52$bar = bar(5);
53test {&$foo() == 4 };
54&$foo(6);
55test {&$foo() == 6 };
56test {&$bar() == 5 };
57
58# nested closures
59sub bizz {
60 my $i = 7;
61 if (@_) {
62 my $i = shift;
63 sub {$i = shift if @_; $i };
64 } else {
65 my $i = $i;
66 sub {$i = shift if @_; $i };
67 }
68}
69$foo = bizz();
70$bar = bizz();
71test {&$foo() == 7 };
72&$foo(8);
73test {&$foo() == 8 };
74test {&$bar() == 7 };
75
76$foo = bizz(9);
77$bar = bizz(10);
78test {&$foo(11)-1 == &$bar()};
79
80my @foo;
81for (qw(0 1 2 3 4)) {
82 my $i = $_;
83 $foo[$_] = sub {$i = shift if @_; $i };
84}
85
86test {
87 &{$foo[0]}() == 0 and
88 &{$foo[1]}() == 1 and
89 &{$foo[2]}() == 2 and
90 &{$foo[3]}() == 3 and
91 &{$foo[4]}() == 4
92 };
93
94for (0 .. 4) {
95 &{$foo[$_]}(4-$_);
96}
97
98test {
99 &{$foo[0]}() == 4 and
100 &{$foo[1]}() == 3 and
101 &{$foo[2]}() == 2 and
102 &{$foo[3]}() == 1 and
103 &{$foo[4]}() == 0
104 };
105
106sub barf {
107 my @foo;
108 for (qw(0 1 2 3 4)) {
109 my $i = $_;
110 $foo[$_] = sub {$i = shift if @_; $i };
111 }
112 @foo;
113}
114
115@foo = barf();
116test {
117 &{$foo[0]}() == 0 and
118 &{$foo[1]}() == 1 and
119 &{$foo[2]}() == 2 and
120 &{$foo[3]}() == 3 and
121 &{$foo[4]}() == 4
122 };
123
124for (0 .. 4) {
125 &{$foo[$_]}(4-$_);
126}
127
128test {
129 &{$foo[0]}() == 4 and
130 &{$foo[1]}() == 3 and
131 &{$foo[2]}() == 2 and
132 &{$foo[3]}() == 1 and
133 &{$foo[4]}() == 0
134 };
135
3c1f3fdf 136# test if closures get created in optimized for loops
137
138my %foo;
139for my $n ('A'..'E') {
140 $foo{$n} = sub { $n eq $_[0] };
141}
142
143test {
144 &{$foo{A}}('A') and
145 &{$foo{B}}('B') and
146 &{$foo{C}}('C') and
147 &{$foo{D}}('D') and
148 &{$foo{E}}('E')
149};
150
151for my $n (0..4) {
152 $foo[$n] = sub { $n == $_[0] };
153}
154
155test {
156 &{$foo[0]}(0) and
157 &{$foo[1]}(1) and
158 &{$foo[2]}(2) and
159 &{$foo[3]}(3) and
160 &{$foo[4]}(4)
161};
162
94f23f41 163for my $n (0..4) {
164 $foo[$n] = sub {
165 # no intervening reference to $n here
166 sub { $n == $_[0] }
167 };
168}
169
170test {
171 $foo[0]->()->(0) and
172 $foo[1]->()->(1) and
173 $foo[2]->()->(2) and
174 $foo[3]->()->(3) and
175 $foo[4]->()->(4)
176};
177
354992b1 178{
179 my $w;
180 $w = sub {
181 my ($i) = @_;
182 test { $i == 10 };
183 sub { $w };
184 };
185 $w->(10);
186}
94f23f41 187
0a753a76 188# Additional tests by Tom Phoenix <rootbeer@teleport.com>.
189
190{
0a753a76 191 use strict;
192
193 use vars qw!$test!;
194 my($debugging, %expected, $inner_type, $where_declared, $within);
195 my($nc_attempt, $call_outer, $call_inner, $undef_outer);
196 my($code, $inner_sub_test, $expected, $line, $errors, $output);
197 my(@inners, $sub_test, $pid);
198 $debugging = 1 if defined($ARGV[0]) and $ARGV[0] eq '-debug';
199
200 # The expected values for these tests
201 %expected = (
202 'global_scalar' => 1001,
203 'global_array' => 2101,
204 'global_hash' => 3004,
205 'fs_scalar' => 4001,
206 'fs_array' => 5101,
207 'fs_hash' => 6004,
208 'sub_scalar' => 7001,
209 'sub_array' => 8101,
210 'sub_hash' => 9004,
211 'foreach' => 10011,
212 );
213
214 # Our innermost sub is either named or anonymous
215 for $inner_type (qw!named anon!) {
216 # And it may be declared at filescope, within a named
217 # sub, or within an anon sub
218 for $where_declared (qw!filescope in_named in_anon!) {
219 # And that, in turn, may be within a foreach loop,
220 # a naked block, or another named sub
221 for $within (qw!foreach naked other_sub!) {
222
223 # Here are a number of variables which show what's
224 # going on, in a way.
225 $nc_attempt = 0+ # Named closure attempted
226 ( ($inner_type eq 'named') ||
227 ($within eq 'other_sub') ) ;
228 $call_inner = 0+ # Need to call &inner
229 ( ($inner_type eq 'anon') &&
230 ($within eq 'other_sub') ) ;
231 $call_outer = 0+ # Need to call &outer or &$outer
232 ( ($inner_type eq 'anon') &&
233 ($within ne 'other_sub') ) ;
234 $undef_outer = 0+ # $outer is created but unused
235 ( ($where_declared eq 'in_anon') &&
236 (not $call_outer) ) ;
237
238 $code = "# This is a test script built by t/op/closure.t\n\n";
239
a16a9fa3 240 print <<"DEBUG_INFO" if $debugging;
241# inner_type: $inner_type
0a753a76 242# where_declared: $where_declared
a16a9fa3 243# within: $within
244# nc_attempt: $nc_attempt
245# call_inner: $call_inner
246# call_outer: $call_outer
247# undef_outer: $undef_outer
0a753a76 248DEBUG_INFO
249
250 $code .= <<"END_MARK_ONE";
251
252BEGIN { \$SIG{__WARN__} = sub {
253 my \$msg = \$_[0];
254END_MARK_ONE
255
256 $code .= <<"END_MARK_TWO" if $nc_attempt;
257 return if index(\$msg, 'will not stay shared') != -1;
258 return if index(\$msg, 'may be unavailable') != -1;
259END_MARK_TWO
260
261 $code .= <<"END_MARK_THREE"; # Backwhack a lot!
262 print "not ok: got unexpected warning \$msg\\n";
263} }
264
265{
266 my \$test = $test;
267 sub test (&) {
a16a9fa3 268 my \$ok = &{\$_[0]};
269 print \$ok ? "ok \$test\n" : "not ok \$test\n";
270 printf "# Failed at line %d\n", (caller)[2] unless \$ok;
0a753a76 271 \$test++;
272 }
273}
274
275# some of the variables which the closure will access
276\$global_scalar = 1000;
277\@global_array = (2000, 2100, 2200, 2300);
278%global_hash = 3000..3009;
279
280my \$fs_scalar = 4000;
281my \@fs_array = (5000, 5100, 5200, 5300);
282my %fs_hash = 6000..6009;
283
284END_MARK_THREE
285
286 if ($where_declared eq 'filescope') {
287 # Nothing here
288 } elsif ($where_declared eq 'in_named') {
289 $code .= <<'END';
290sub outer {
291 my $sub_scalar = 7000;
292 my @sub_array = (8000, 8100, 8200, 8300);
293 my %sub_hash = 9000..9009;
294END
295 # }
296 } elsif ($where_declared eq 'in_anon') {
297 $code .= <<'END';
298$outer = sub {
299 my $sub_scalar = 7000;
300 my @sub_array = (8000, 8100, 8200, 8300);
301 my %sub_hash = 9000..9009;
302END
303 # }
304 } else {
305 die "What was $where_declared?"
306 }
307
308 if ($within eq 'foreach') {
309 $code .= "
310 my \$foreach = 12000;
311 my \@list = (10000, 10010);
312 foreach \$foreach (\@list) {
313 " # }
314 } elsif ($within eq 'naked') {
315 $code .= " { # naked block\n" # }
316 } elsif ($within eq 'other_sub') {
317 $code .= " sub inner_sub {\n" # }
318 } else {
319 die "What was $within?"
320 }
321
322 $sub_test = $test;
323 @inners = ( qw!global_scalar global_array global_hash! ,
324 qw!fs_scalar fs_array fs_hash! );
325 push @inners, 'foreach' if $within eq 'foreach';
326 if ($where_declared ne 'filescope') {
327 push @inners, qw!sub_scalar sub_array sub_hash!;
328 }
329 for $inner_sub_test (@inners) {
330
331 if ($inner_type eq 'named') {
332 $code .= " sub named_$sub_test "
333 } elsif ($inner_type eq 'anon') {
334 $code .= " \$anon_$sub_test = sub "
335 } else {
336 die "What was $inner_type?"
337 }
338
339 # Now to write the body of the test sub
340 if ($inner_sub_test eq 'global_scalar') {
341 $code .= '{ ++$global_scalar }'
342 } elsif ($inner_sub_test eq 'fs_scalar') {
343 $code .= '{ ++$fs_scalar }'
344 } elsif ($inner_sub_test eq 'sub_scalar') {
345 $code .= '{ ++$sub_scalar }'
346 } elsif ($inner_sub_test eq 'global_array') {
347 $code .= '{ ++$global_array[1] }'
348 } elsif ($inner_sub_test eq 'fs_array') {
349 $code .= '{ ++$fs_array[1] }'
350 } elsif ($inner_sub_test eq 'sub_array') {
351 $code .= '{ ++$sub_array[1] }'
352 } elsif ($inner_sub_test eq 'global_hash') {
353 $code .= '{ ++$global_hash{3002} }'
354 } elsif ($inner_sub_test eq 'fs_hash') {
355 $code .= '{ ++$fs_hash{6002} }'
356 } elsif ($inner_sub_test eq 'sub_hash') {
357 $code .= '{ ++$sub_hash{9002} }'
358 } elsif ($inner_sub_test eq 'foreach') {
359 $code .= '{ ++$foreach }'
360 } else {
361 die "What was $inner_sub_test?"
362 }
363
364 # Close up
365 if ($inner_type eq 'anon') {
366 $code .= ';'
367 }
368 $code .= "\n";
369 $sub_test++; # sub name sequence number
370
371 } # End of foreach $inner_sub_test
372
373 # Close up $within block # {
374 $code .= " }\n\n";
375
376 # Close up $where_declared block
377 if ($where_declared eq 'in_named') { # {
378 $code .= "}\n\n";
379 } elsif ($where_declared eq 'in_anon') { # {
380 $code .= "};\n\n";
381 }
382
383 # We may need to do something with the sub we just made...
384 $code .= "undef \$outer;\n" if $undef_outer;
385 $code .= "&inner_sub;\n" if $call_inner;
386 if ($call_outer) {
387 if ($where_declared eq 'in_named') {
388 $code .= "&outer;\n\n";
389 } elsif ($where_declared eq 'in_anon') {
390 $code .= "&\$outer;\n\n"
391 }
392 }
393
394 # Now, we can actually prep to run the tests.
395 for $inner_sub_test (@inners) {
396 $expected = $expected{$inner_sub_test} or
397 die "expected $inner_sub_test missing";
398
399 # Named closures won't access the expected vars
400 if ( $nc_attempt and
401 substr($inner_sub_test, 0, 4) eq "sub_" ) {
402 $expected = 1;
403 }
404
405 # If you make a sub within a foreach loop,
406 # what happens if it tries to access the
407 # foreach index variable? If it's a named
408 # sub, it gets the var from "outside" the loop,
409 # but if it's anon, it gets the value to which
410 # the index variable is aliased.
411 #
412 # Of course, if the value was set only
413 # within another sub which was never called,
414 # the value has not been set yet.
415 #
416 if ($inner_sub_test eq 'foreach') {
417 if ($inner_type eq 'named') {
418 if ($call_outer || ($where_declared eq 'filescope')) {
419 $expected = 12001
420 } else {
421 $expected = 1
422 }
423 }
424 }
425
426 # Here's the test:
427 if ($inner_type eq 'anon') {
428 $code .= "test { &\$anon_$test == $expected };\n"
429 } else {
430 $code .= "test { &named_$test == $expected };\n"
431 }
432 $test++;
433 }
434
2986a63f 435 if ($Config{d_fork} and $^O ne 'VMS' and $^O ne 'MSWin32' and $^O ne 'NetWare') {
f86702cc 436 # Fork off a new perl to run the tests.
437 # (This is so we can catch spurious warnings.)
438 $| = 1; print ""; $| = 0; # flush output before forking
439 pipe READ, WRITE or die "Can't make pipe: $!";
440 pipe READ2, WRITE2 or die "Can't make second pipe: $!";
441 die "Can't fork: $!" unless defined($pid = open PERL, "|-");
442 unless ($pid) {
443 # Child process here. We're going to send errors back
444 # through the extra pipe.
445 close READ;
446 close READ2;
447 open STDOUT, ">&WRITE" or die "Can't redirect STDOUT: $!";
448 open STDERR, ">&WRITE2" or die "Can't redirect STDERR: $!";
449 exec './perl', '-w', '-'
0a753a76 450 or die "Can't exec ./perl: $!";
f86702cc 451 } else {
452 # Parent process here.
453 close WRITE;
454 close WRITE2;
455 print PERL $code;
456 close PERL;
457 { local $/;
458 $output = join '', <READ>;
459 $errors = join '', <READ2>; }
460 close READ;
461 close READ2;
462 }
463 } else {
464 # No fork(). Do it the hard way.
465 my $cmdfile = "tcmd$$"; $cmdfile++ while -e $cmdfile;
f86702cc 466 my $errfile = "terr$$"; $errfile++ while -e $errfile;
aa689395 467 my @tmpfiles = ($cmdfile, $errfile);
f86702cc 468 open CMD, ">$cmdfile"; print CMD $code; close CMD;
68dc0745 469 my $cmd = (($^O eq 'VMS') ? "MCR $^X"
470 : ($^O eq 'MSWin32') ? '.\perl'
95e8664e 471 : ($^O eq 'MacOS') ? $^X
2986a63f 472 : ($^O eq 'NetWare') ? 'perl'
68dc0745 473 : './perl');
aa689395 474 $cmd .= " -w $cmdfile 2>$errfile";
2986a63f 475 if ($^O eq 'VMS' or $^O eq 'MSWin32' or $^O eq 'NetWare') {
aa689395 476 # Use pipe instead of system so we don't inherit STD* from
477 # this process, and then foul our pipe back to parent by
478 # redirecting output in the child.
479 open PERL,"$cmd |" or die "Can't open pipe: $!\n";
480 { local $/; $output = join '', <PERL> }
481 close PERL;
482 } else {
483 my $outfile = "tout$$"; $outfile++ while -e $outfile;
484 push @tmpfiles, $outfile;
485 system "$cmd >$outfile";
486 { local $/; open IN, $outfile; $output = <IN>; close IN }
487 }
f86702cc 488 if ($?) {
489 printf "not ok: exited with error code %04X\n", $?;
aa689395 490 $debugging or do { 1 while unlink @tmpfiles };
f86702cc 491 exit;
492 }
aa689395 493 { local $/; open IN, $errfile; $errors = <IN>; close IN }
494 1 while unlink @tmpfiles;
0a753a76 495 }
f86702cc 496 print $output;
497 print STDERR $errors;
0a753a76 498 if ($debugging && ($errors || $? || ($output =~ /not ok/))) {
499 my $lnum = 0;
500 for $line (split '\n', $code) {
501 printf "%3d: %s\n", ++$lnum, $line;
502 }
503 }
f86702cc 504 printf "not ok: exited with error code %04X\n", $? if $?;
a16a9fa3 505 print '#', "-" x 30, "\n" if $debugging;
0a753a76 506
507 } # End of foreach $within
508 } # End of foreach $where_declared
509 } # End of foreach $inner_type
510
511}
3c1f3fdf 512
7dafbf52 513# The following dumps core with perl <= 5.8.0 (bugid 9535) ...
2f647fb2 514BEGIN { $vanishing_pad = sub { eval $_[0] } }
515$some_var = 123;
516test { $vanishing_pad->( '$some_var' ) == 123 };
f3548bdc 517
7dafbf52 518# ... and here's another coredump variant - this time we explicitly
519# delete the sub rather than using a BEGIN ...
520
521sub deleteme { $a = sub { eval '$newvar' } }
522deleteme();
523*deleteme = sub {}; # delete the sub
524$newvar = 123; # realloc the SV of the freed CV
525test { $a->() == 123 };
526
527# ... and a further coredump variant - the fixup of the anon sub's
528# CvOUTSIDE pointer when the middle eval is freed, wasn't good enough to
529# survive the outer eval also being freed.
530
531$x = 123;
532$a = eval q(
533 eval q[
534 sub { eval '$x' }
535 ]
536);
537@a = ('\1\1\1\1\1\1\1') x 100; # realloc recently-freed CVs
538test { $a->() == 123 };
539
f3548bdc 540# this coredumped on <= 5.8.0 because evaling the closure caused
541# an SvFAKE to be added to the outer anon's pad, which was then grown.
542my $outer;
543sub {
544 my $x;
545 $x = eval 'sub { $outer }';
546 $x->();
547 $a = [ 99 ];
548 $x->();
549}->();
550test {1};
551
e9f19e3c 552# [perl #17605] found that an empty block called in scalar context
553# can lead to stack corruption
554{
555 my $x = "foooobar";
556 $x =~ s/o//eg;
557 test { $x eq 'fbar' }
558}
ee6cee0c 559
560# DAPM 24-Nov-02
561# SvFAKE lexicals should be visible thoughout a function.
562# On <= 5.8.0, the third test failed, eg bugid #18286
563
564{
565 my $x = 1;
566 sub fake {
567 test { sub {eval'$x'}->() == 1 };
568 { $x; test { sub {eval'$x'}->() == 1 } }
569 test { sub {eval'$x'}->() == 1 };
570 }
571}
572fake();
573
7dafbf52 574# undefining a sub shouldn't alter visibility of outer lexicals
575
576{
577 $x = 1;
578 my $x = 2;
579 sub tmp { sub { eval '$x' } }
580 my $a = tmp();
581 undef &tmp;
582 test { $a->() == 2 };
583}
584
585# handy class: $x = Watch->new(\$foo,'bar')
586# causes 'bar' to be appended to $foo when $x is destroyed
587sub Watch::new { bless [ $_[1], $_[2] ], $_[0] }
588sub Watch::DESTROY { ${$_[0][0]} .= $_[0][1] }
589
590
591# bugid 1028:
592# nested anon subs (and associated lexicals) not freed early enough
593
594sub linger {
595 my $x = Watch->new($_[0], '2');
596 sub {
597 $x;
598 my $y;
599 sub { $y; };
600 };
601}
602{
603 my $watch = '1';
604 linger(\$watch);
605 test { $watch eq '12' }
606}