1#!./perl 2 3BEGIN { 4 chdir 't' if -d 't'; 5 require './test.pl'; 6 set_up_inc('../lib'); 7 require Config; 8} 9 10use strict; 11use warnings; 12use feature 'try'; 13 14{ 15 my $x; 16 try { 17 $x .= "try"; 18 } 19 catch ($e) { 20 $x .= "catch"; 21 } 22 is($x, "try", 'successful try/catch runs try but not catch'); 23} 24 25{ 26 my $x; 27 my $caught; 28 try { 29 $x .= "try"; 30 die "Oopsie\n"; 31 } 32 catch ($e) { 33 $x .= "catch"; 34 $caught = $e; 35 is($@, "", '$@ is empty within catch block'); 36 } 37 is($x, "trycatch", 'die in try runs catch block'); 38 is($caught, "Oopsie\n", 'catch block saw exception value'); 39} 40 41# return inside try {} makes containing function return 42{ 43 sub f 44 { 45 try { 46 return "return inside try"; 47 } 48 catch ($e) { } 49 return "return from func"; 50 } 51 is(f(), "return inside try", 'return inside try'); 52} 53 54# wantarray inside try 55{ 56 my $context; 57 sub whatcontext 58 { 59 try { 60 $context = wantarray ? "list" : 61 defined wantarray ? "scalar" : "void"; 62 } 63 catch ($e) { } 64 } 65 66 whatcontext(); 67 is($context, "void", 'sub {try} in void'); 68 69 my $scalar = whatcontext(); 70 is($context, "scalar", 'sub {try} in scalar'); 71 72 my @array = whatcontext(); 73 is($context, "list", 'sub {try} in list'); 74} 75 76# Loop controls inside try {} do not emit warnings 77{ 78 my $warnings = ""; 79 local $SIG{__WARN__} = sub { $warnings .= $_[0] }; 80 81 { 82 try { 83 last; 84 } 85 catch ($e) { } 86 } 87 88 { 89 try { 90 next; 91 } 92 catch ($e) { } 93 } 94 95 my $count = 0; 96 { 97 try { 98 $count++; 99 redo if $count < 2; 100 } 101 catch ($e) { } 102 } 103 104 is($warnings, "", 'No warnings emitted by next/last/redo inside try'); 105 106 $warnings = ""; 107 108 LOOP_L: { 109 try { 110 last LOOP_L; 111 } 112 catch ($e) { } 113 } 114 115 LOOP_N: { 116 try { 117 next LOOP_N; 118 } 119 catch ($e) { } 120 } 121 122 $count = 0; 123 LOOP_R: { 124 try { 125 $count++; 126 redo LOOP_R if $count < 2; 127 } 128 catch ($e) { } 129 } 130 131 is($warnings, "", 'No warnings emitted by next/last/redo LABEL inside try'); 132} 133 134# try/catch should localise $@ 135{ 136 eval { die "Value before\n"; }; 137 138 try { die "Localized value\n" } catch ($e) {} 139 140 is($@, "Value before\n", 'try/catch localized $@'); 141} 142 143# try/catch is not confused by false values 144{ 145 my $caught; 146 try { 147 die 0; 148 } 149 catch ($e) { 150 $caught++; 151 } 152 153 ok( $caught, 'catch{} sees a false exception' ); 154} 155 156# try/catch is not confused by always-false objects 157{ 158 my $caught; 159 try { 160 die FALSE->new; 161 } 162 catch ($e) { 163 $caught++; 164 } 165 166 ok( $caught, 'catch{} sees a false-overload exception object' ); 167 168 { 169 package FALSE; 170 use overload 'bool' => sub { 0 }; 171 sub new { bless [], shift } 172 } 173} 174 175# return from try is correct even for :lvalue subs 176# https://github.com/Perl/perl5/issues/18553 177{ 178 my $scalar; 179 sub fscalar :lvalue 180 { 181 try { return $scalar } 182 catch ($e) { } 183 } 184 185 fscalar = 123; 186 is($scalar, 123, 'try { return } in :lvalue sub in scalar context' ); 187 188 my @array; 189 sub flist :lvalue 190 { 191 try { return @array } 192 catch ($e) { } 193 } 194 195 (flist) = (4, 5, 6); 196 ok(eq_array(\@array, [4, 5, 6]), 'try { return } in :lvalue sub in list context' ); 197} 198 199# try as final expression yields correct value 200{ 201 my $scalar = do { 202 try { 123 } 203 catch ($e) { 456 } 204 }; 205 is($scalar, 123, 'do { try } in scalar context'); 206 207 my @list = do { 208 try { 1, 2, 3 } 209 catch ($e) { 4, 5, 6 } 210 }; 211 ok(eq_array(\@list, [1, 2, 3]), 'do { try } in list context'); 212 213 # Regression test related to 214 # https://github.com/Perl/perl5/issues/18855 215 $scalar = do { 216 try { my $x = 123; 456 } 217 catch ($e) { 789 } 218 }; 219 is($scalar, 456, 'do { try } with multiple statements'); 220} 221 222# catch as final expression yields correct value 223{ 224 my $scalar = do { 225 try { die "Oops" } 226 catch ($e) { 456 } 227 }; 228 is($scalar, 456, 'do { try/catch } in scalar context'); 229 230 my @list = do { 231 try { die "Oops" } 232 catch ($e) { 4, 5, 6 } 233 }; 234 ok(eq_array(\@list, [4, 5, 6]), 'do { try/catch } in list context'); 235 236 # Regression test 237 # https://github.com/Perl/perl5/issues/18855 238 $scalar = do { 239 try { die "Oops" } 240 catch ($e) { my $x = 123; "result" } 241 }; 242 is($scalar, "result", 'do { try/catch } with multiple statements'); 243} 244 245# try{} blocks should be invisible to caller() 246{ 247 my $caller; 248 sub A { $caller = sprintf "%s (%s line %d)", (caller 1)[3,1,2]; } 249 250 sub B { 251 try { A(); } 252 catch ($e) {} 253 } 254 255 my $LINE = __LINE__+1; 256 B(); 257 258 is($caller, "main::B ($0 line $LINE)", 'try {} block is invisible to caller()'); 259} 260 261# try/catch/finally 262 263# experimental warnings 264{ 265 my $warnings; 266 BEGIN { $SIG{__WARN__} = sub { $warnings .= shift; }; } 267 268 my ($lfinally) = (__LINE__+5); 269 try { 270 } 271 catch ($e) { 272 } 273 finally { 274 } 275 276 is($warnings, "try/catch/finally is experimental at $0 line $lfinally.\n", 277 'compiletime warnings'); 278 BEGIN { undef $SIG{__WARN__}; } 279} 280 281no warnings 'experimental::try'; 282 283{ 284 my $x; 285 try { 286 $x .= "try"; 287 } 288 catch ($e) { 289 $x .= "catch"; 290 } 291 finally { 292 $x .= "finally"; 293 } 294 is($x, "tryfinally", 'successful try/catch/finally runs try+finally but not catch'); 295} 296 297{ 298 my $x; 299 try { 300 $x .= "try"; 301 die "Oopsie\n"; 302 } 303 catch ($e) { 304 $x .= "catch"; 305 } 306 finally { 307 $x .= "finally"; 308 } 309 is($x, "trycatchfinally", 'try/catch/finally runs try+catch+finally on failure'); 310} 311 312{ 313 my $finally_invoked; 314 sub ff 315 { 316 try { 317 return "return inside try+finally"; 318 } 319 catch ($e) {} 320 finally { $finally_invoked++; "last value" } 321 return "return from func"; 322 } 323 is(ff(), "return inside try+finally", 'return inside try+finally'); 324 ok($finally_invoked, 'finally block still invoked for side-effects'); 325} 326 327# Nicer compiletime errors 328{ 329 my $e; 330 331 $e = defined eval 'try { A() } catch { B() }; 1;' ? undef : $@; 332 like($e, qr/^catch block requires a \(VAR\) at /, 333 'Parse error for catch without (VAR)'); 334} 335 336done_testing; 337