1256a93a4Safresh1#!./perl 2256a93a4Safresh1 3256a93a4Safresh1BEGIN { 4256a93a4Safresh1 chdir 't' if -d 't'; 5256a93a4Safresh1 require './test.pl'; 6256a93a4Safresh1 set_up_inc('../lib'); 7256a93a4Safresh1} 8256a93a4Safresh1 9*f2a19305Safresh1plan 28; 10256a93a4Safresh1 11256a93a4Safresh1use feature 'defer'; 12256a93a4Safresh1no warnings 'experimental::defer'; 13256a93a4Safresh1 14256a93a4Safresh1{ 15256a93a4Safresh1 my $x = ""; 16256a93a4Safresh1 { 17256a93a4Safresh1 defer { $x = "a" } 18256a93a4Safresh1 } 19256a93a4Safresh1 is($x, "a", 'defer block is invoked'); 20256a93a4Safresh1 21256a93a4Safresh1 { 22256a93a4Safresh1 defer { 23256a93a4Safresh1 $x = ""; 24256a93a4Safresh1 $x .= "abc"; 25256a93a4Safresh1 $x .= "123"; 26256a93a4Safresh1 } 27256a93a4Safresh1 } 28256a93a4Safresh1 is($x, "abc123", 'defer block can contain multiple statements'); 29256a93a4Safresh1 30256a93a4Safresh1 { 31256a93a4Safresh1 defer {} 32256a93a4Safresh1 } 33256a93a4Safresh1 ok(1, 'Empty defer block parses OK'); 34256a93a4Safresh1} 35256a93a4Safresh1 36256a93a4Safresh1{ 37256a93a4Safresh1 my $x = ""; 38256a93a4Safresh1 { 39256a93a4Safresh1 defer { $x .= "a" } 40256a93a4Safresh1 defer { $x .= "b" } 41256a93a4Safresh1 defer { $x .= "c" } 42256a93a4Safresh1 } 43256a93a4Safresh1 is($x, "cba", 'defer blocks happen in LIFO order'); 44256a93a4Safresh1} 45256a93a4Safresh1 46256a93a4Safresh1{ 47256a93a4Safresh1 my $x = ""; 48256a93a4Safresh1 49256a93a4Safresh1 { 50256a93a4Safresh1 defer { $x .= "a" } 51256a93a4Safresh1 $x .= "A"; 52256a93a4Safresh1 } 53256a93a4Safresh1 54256a93a4Safresh1 is($x, "Aa", 'defer blocks happen after the main body'); 55256a93a4Safresh1} 56256a93a4Safresh1 57256a93a4Safresh1{ 58256a93a4Safresh1 my $x = ""; 59256a93a4Safresh1 60256a93a4Safresh1 foreach my $i (qw( a b c )) { 61256a93a4Safresh1 defer { $x .= $i } 62256a93a4Safresh1 } 63256a93a4Safresh1 64256a93a4Safresh1 is($x, "abc", 'defer block happens for every iteration of foreach'); 65256a93a4Safresh1} 66256a93a4Safresh1 67256a93a4Safresh1{ 68256a93a4Safresh1 my $x = ""; 69256a93a4Safresh1 70256a93a4Safresh1 my $cond = 0; 71256a93a4Safresh1 if( $cond ) { 72256a93a4Safresh1 defer { $x .= "XXX" } 73256a93a4Safresh1 } 74256a93a4Safresh1 75256a93a4Safresh1 is($x, "", 'defer block does not happen inside non-taken conditional branch'); 76256a93a4Safresh1} 77256a93a4Safresh1 78256a93a4Safresh1{ 79256a93a4Safresh1 my $x = ""; 80256a93a4Safresh1 81256a93a4Safresh1 while(1) { 82256a93a4Safresh1 last; 83256a93a4Safresh1 defer { $x .= "a" } 84256a93a4Safresh1 } 85256a93a4Safresh1 86256a93a4Safresh1 is($x, "", 'defer block does not happen if entered but unencountered'); 87256a93a4Safresh1} 88256a93a4Safresh1 89256a93a4Safresh1{ 90256a93a4Safresh1 my $x = ""; 91256a93a4Safresh1 92256a93a4Safresh1 my $counter = 1; 93256a93a4Safresh1 { 94256a93a4Safresh1 defer { $x .= "A" } 95256a93a4Safresh1 redo if $counter++ < 5; 96256a93a4Safresh1 } 97256a93a4Safresh1 98256a93a4Safresh1 is($x, "AAAAA", 'defer block can happen multiple times'); 99256a93a4Safresh1} 100256a93a4Safresh1 101256a93a4Safresh1{ 102256a93a4Safresh1 my $x = ""; 103256a93a4Safresh1 104256a93a4Safresh1 { 105256a93a4Safresh1 defer { 106256a93a4Safresh1 $x .= "a"; 107256a93a4Safresh1 defer { 108256a93a4Safresh1 $x .= "b"; 109256a93a4Safresh1 } 110256a93a4Safresh1 } 111256a93a4Safresh1 } 112256a93a4Safresh1 113256a93a4Safresh1 is($x, "ab", 'defer block can contain another defer'); 114256a93a4Safresh1} 115256a93a4Safresh1 116256a93a4Safresh1{ 117256a93a4Safresh1 my $x = ""; 118256a93a4Safresh1 my $value = do { 119256a93a4Safresh1 defer { $x .= "before" } 120256a93a4Safresh1 "value"; 121256a93a4Safresh1 }; 122256a93a4Safresh1 123256a93a4Safresh1 is($x, "before", 'defer blocks run inside do { }'); 124256a93a4Safresh1 is($value, "value", 'defer block does not disturb do { } value'); 125256a93a4Safresh1} 126256a93a4Safresh1 127256a93a4Safresh1{ 128256a93a4Safresh1 my $x = ""; 129256a93a4Safresh1 my $sub = sub { 130256a93a4Safresh1 defer { $x .= "a" } 131256a93a4Safresh1 }; 132256a93a4Safresh1 133256a93a4Safresh1 $sub->(); 134256a93a4Safresh1 $sub->(); 135256a93a4Safresh1 $sub->(); 136256a93a4Safresh1 137256a93a4Safresh1 is($x, "aaa", 'defer block inside sub'); 138256a93a4Safresh1} 139256a93a4Safresh1 140256a93a4Safresh1{ 141256a93a4Safresh1 my $x = ""; 142256a93a4Safresh1 my $sub = sub { 143256a93a4Safresh1 return; 144256a93a4Safresh1 defer { $x .= "a" } 145256a93a4Safresh1 }; 146256a93a4Safresh1 147256a93a4Safresh1 $sub->(); 148256a93a4Safresh1 149256a93a4Safresh1 is($x, "", 'defer block inside sub does not happen if entered but returned early'); 150256a93a4Safresh1} 151256a93a4Safresh1 152256a93a4Safresh1{ 153256a93a4Safresh1 my $x = ""; 154256a93a4Safresh1 155256a93a4Safresh1 my sub after { 156256a93a4Safresh1 $x .= "c"; 157256a93a4Safresh1 } 158256a93a4Safresh1 159256a93a4Safresh1 my sub before { 160256a93a4Safresh1 $x .= "a"; 161256a93a4Safresh1 defer { $x .= "b" } 162256a93a4Safresh1 goto \&after; 163256a93a4Safresh1 } 164256a93a4Safresh1 165256a93a4Safresh1 before(); 166256a93a4Safresh1 167256a93a4Safresh1 is($x, "abc", 'defer block invoked before tail-call'); 168256a93a4Safresh1} 169256a93a4Safresh1 170256a93a4Safresh1# Sequencing with respect to variable cleanup 171256a93a4Safresh1 172256a93a4Safresh1{ 173256a93a4Safresh1 my $var = "outer"; 174256a93a4Safresh1 my $x; 175256a93a4Safresh1 { 176256a93a4Safresh1 my $var = "inner"; 177256a93a4Safresh1 defer { $x = $var } 178256a93a4Safresh1 } 179256a93a4Safresh1 180256a93a4Safresh1 is($x, "inner", 'defer block captures live value of same-scope lexicals'); 181256a93a4Safresh1} 182256a93a4Safresh1 183256a93a4Safresh1{ 184256a93a4Safresh1 my $var = "outer"; 185256a93a4Safresh1 my $x; 186256a93a4Safresh1 { 187256a93a4Safresh1 defer { $x = $var } 188256a93a4Safresh1 my $var = "inner"; 189256a93a4Safresh1 } 190256a93a4Safresh1 191256a93a4Safresh1 is ($x, "outer", 'defer block correctly captures outer lexical when only shadowed afterwards'); 192256a93a4Safresh1} 193256a93a4Safresh1 194256a93a4Safresh1{ 195256a93a4Safresh1 our $var = "outer"; 196256a93a4Safresh1 { 197256a93a4Safresh1 local $var = "inner"; 198256a93a4Safresh1 defer { $var = "finally" } 199256a93a4Safresh1 } 200256a93a4Safresh1 201256a93a4Safresh1 is($var, "outer", 'defer after localization still unlocalizes'); 202256a93a4Safresh1} 203256a93a4Safresh1 204256a93a4Safresh1{ 205256a93a4Safresh1 our $var = "outer"; 206256a93a4Safresh1 { 207256a93a4Safresh1 defer { $var = "finally" } 208256a93a4Safresh1 local $var = "inner"; 209256a93a4Safresh1 } 210256a93a4Safresh1 211256a93a4Safresh1 is($var, "finally", 'defer before localization overwrites'); 212256a93a4Safresh1} 213256a93a4Safresh1 214256a93a4Safresh1# Interactions with exceptions 215256a93a4Safresh1 216256a93a4Safresh1{ 217256a93a4Safresh1 my $x = ""; 218256a93a4Safresh1 my $sub = sub { 219256a93a4Safresh1 defer { $x .= "a" } 220256a93a4Safresh1 die "Oopsie\n"; 221256a93a4Safresh1 }; 222256a93a4Safresh1 223256a93a4Safresh1 my $e = defined eval { $sub->(); 1 } ? undef : $@; 224256a93a4Safresh1 225256a93a4Safresh1 is($x, "a", 'defer block still runs during exception unwind'); 226256a93a4Safresh1 is($e, "Oopsie\n", 'Thrown exception still occurs after defer'); 227256a93a4Safresh1} 228256a93a4Safresh1 229256a93a4Safresh1{ 230256a93a4Safresh1 my $sub = sub { 231256a93a4Safresh1 defer { die "Oopsie\n"; } 232256a93a4Safresh1 return "retval"; 233256a93a4Safresh1 }; 234256a93a4Safresh1 235256a93a4Safresh1 my $e = defined eval { $sub->(); 1 } ? undef : $@; 236256a93a4Safresh1 237256a93a4Safresh1 is($e, "Oopsie\n", 'defer block can throw exception'); 238256a93a4Safresh1} 239256a93a4Safresh1 240256a93a4Safresh1{ 241256a93a4Safresh1 my $sub = sub { 242256a93a4Safresh1 defer { die "Oopsie 1\n"; } 243256a93a4Safresh1 die "Oopsie 2\n"; 244256a93a4Safresh1 }; 245256a93a4Safresh1 246256a93a4Safresh1 my $e = defined eval { $sub->(); 1 } ? undef : $@; 247256a93a4Safresh1 248256a93a4Safresh1 # TODO: Currently the first exception gets lost without even a warning 249256a93a4Safresh1 # We should consider what the behaviour ought to be here 250256a93a4Safresh1 # This test is happy for either exception to be seen, does not care which 251256a93a4Safresh1 like($e, qr/^Oopsie \d\n/, 'defer block can throw exception during exception unwind'); 252256a93a4Safresh1} 253256a93a4Safresh1 254*f2a19305Safresh1# goto 255256a93a4Safresh1{ 256*f2a19305Safresh1 ok(defined eval 'sub { defer { goto HERE; HERE: 1; } }', 257*f2a19305Safresh1 'goto forwards within defer {} is permitted') or 258*f2a19305Safresh1 diag("Failure was $@"); 259256a93a4Safresh1 260*f2a19305Safresh1 ok(defined eval 'sub { defer { HERE: 1; goto HERE; } }', 261*f2a19305Safresh1 'goto backwards within defer {} is permitted') or 262*f2a19305Safresh1 diag("Failure was $@"); 263256a93a4Safresh1} 264256a93a4Safresh1 265256a93a4Safresh1{ 266256a93a4Safresh1 my $sub = sub { 267256a93a4Safresh1 while(1) { 268256a93a4Safresh1 goto HERE; 269256a93a4Safresh1 defer { HERE: 1; } 270256a93a4Safresh1 } 271256a93a4Safresh1 }; 272256a93a4Safresh1 273256a93a4Safresh1 my $e = defined eval { $sub->(); 1 } ? undef : $@; 274256a93a4Safresh1 like($e, qr/^Can't "goto" into a "defer" block /, 275256a93a4Safresh1 'Cannot goto into defer block'); 276256a93a4Safresh1} 277256a93a4Safresh1 278256a93a4Safresh1{ 279256a93a4Safresh1 # strictness failures are only checked at optree finalization time. This 280256a93a4Safresh1 # is a good way to test if that happens. 281256a93a4Safresh1 my $ok = eval 'defer { use strict; foo }'; 282256a93a4Safresh1 my $e = $@; 283256a93a4Safresh1 284256a93a4Safresh1 ok(!$ok, 'defer BLOCK finalizes optree'); 285256a93a4Safresh1 like($e, qr/^Bareword "foo" not allowed while "strict subs" in use at /, 286256a93a4Safresh1 'Error from finalization'); 287256a93a4Safresh1} 288