*_HAS_SUBNAME = ($su || $sn) ? sub(){1} : sub(){0};
}
+our @_finally_guards;
+
# Need to prototype as @ not $$ because of the way Perl evaluates the prototype.
# Keeping it at $$ means you only ever get 1 sub because we need to eval in a list
# context & not a scalar one
_subname("${caller}::try {...} " => $try)
if _HAS_SUBNAME;
+ # set up scope guards to invoke the finally blocks at the end.
+ # this should really be a lexical variable instead of our/local but that
+ # causes issues with perls < 5.20 due to perl rt#119311
+ local @_finally_guards =
+ map { Try::Tiny::ScopeGuard->_new($_) }
+ @finally;
+
# save the value of $@ so we can set $@ back to it in the beginning of the eval
# and restore $@ after the eval finishes
my $prev_error = $@;
$error = $@;
$@ = $prev_error;
- # set up a scope guard to invoke the finally block at the end
- my @guards =
- map { Try::Tiny::ScopeGuard->_new($_, $failed ? $error : ()) }
- @finally;
-
# at this point $failed contains a true value if the eval died, even if some
# destructor overwrote $@ as the eval was unwinding.
if ( $failed ) {
+ # pass $error to the finally blocks
+ push @$_, $error for @_finally_guards;
+
# if we got an error, invoke the catch block.
if ( $catch ) {
# This works like given($error), but is backwards compatible and
use strict;
use warnings;
-use Test::More tests => 27;
+use Test::More tests => 30;
use Try::Tiny;
like $originals[1], qr/fin 3 at/, 'Second warning contains original exception';
}
-1;
+{
+ my $finally;
+ SKIP: {
+ try {
+ pass('before skip in try');
+ skip 'whee', 1;
+ fail('not reached');
+ } finally {
+ $finally = 1;
+ };
+ }
+ ok $finally, 'finally ran';
+}
package WithFinally;
use Try::Tiny;
+ our $_in_destroy;
sub DESTROY {
+ local $_in_destroy = 1;
try {}
finally {};
return;
}
}
-my $parent = $$;
-
try {
my $pid = fork;
unless ($pid) {
waitpid $pid, 0;
is $?, 0, 'nested try in cleanup after fork does not maintain outer finally block';
}
-finally { exit 1 if $parent != $$ };
+finally { exit 1 if $WithFinally::_in_destroy };
pass("Didn't just exit");