* Zefram <zefram@fysh.org> [2015-02-05 12:45]: > This is specific to the "for(Destroyer->new)" formulation; if that's > replaced with "my $x = Destroyer->new;" then $@ comes out correctly. > The inner eval{} does not need to be an eval: "$@ = 'wibble'" works > just as well to clobber $@. > > The output suggests that the localised $_ is being destroyed after the > outer eval thinks it's finished unwinding. I don't immediately see how > this happens, but then I wouldn't, because the outer eval's idea of > "finished unwinding" is the embodiment of mine. It was certainly my > intent, in coding the 5.14 change, that code like this should see the > "haha" exception in $@ immediately after the outer eval. With #!/usr/bin/env perl package Destroyer { sub new { bless {} } sub DESTROY { warn 'in destroy'; eval {} } } warn eval { for ( Destroyer->new() ) { die 'haha'; } }; warn 'after eval: ', $@; I get this output: $ perl t.pl haha at t.pl line 8. ...caught at t.pl line 6. in destroy at t.pl line 4. after eval: at t.pl line 11. Note how the `warn` around the `eval` actually picks up the inside exception. You can change this to the statement modifier form of `for` and you can change it to an explicitly loop iterator variable, both package global (`for our $x`) and lexical (`for my $x`) and reproduce the bug anyway. So I would guess the bug is due to `foreach` aliasing – specifically that the per-iteration aliasing is normally undone at the end of the iteration but that that is preempted by the `die` here, such that the unaliasing winds up delayed until all the way after the statement. So the `warn` *inside* that statement picks up the right exception (and would do so even without the anti-clobber fix if my guess is right), but then the unaliasing catches up so that by the *next* statement the exception is gone. This readily suggests a workaround for running under existing perls: if you change the `warn eval` line to eval { ... }, my $e = $@; and then add a line warn 'from same statement: ', $e; then this extra line appears in the output: from same statement: haha at t.pl line 8. So something like Try::Tiny can work around this issue already, at least. Regards, -- Aristotle Pagaltzis // <http://plasmasturm.org/>Thread Previous | Thread Next