diff --git a/pp_ctl.c b/pp_ctl.c index 04f66a7b6f89..9c287f334011 100644 --- a/pp_ctl.c +++ b/pp_ctl.c @@ -2886,6 +2886,8 @@ PP(pp_return) if(CxTYPE(&cxstack[i]) == CXt_DEFER) /* diag_listed_as: Can't "%s" out of a "defer" block */ /* diag_listed_as: Can't "%s" out of a "finally" block */ + /* GH 23948: probably not reachable from test suite, but + * possibly from XS code; retain */ croak("Can't \"%s\" out of a \"%s\" block", "return", S_defer_blockname(&cxstack[i])); } diff --git a/t/op/defer.t b/t/op/defer.t index 58f2c71d0f78..1e71ae968b3f 100644 --- a/t/op/defer.t +++ b/t/op/defer.t @@ -6,7 +6,7 @@ BEGIN { set_up_inc('../lib'); } -plan 29; +plan 32; use feature 'defer'; no warnings 'experimental::defer'; @@ -300,3 +300,28 @@ no warnings 'experimental::defer'; is($ok, "ok", 'eval{die} inside defer does not stop runloop'); } + +# [GH #23948] +{ + use warnings; + no warnings 'experimental'; + + my @warnings; + local $SIG{__WARN__} = sub { push @warnings, "@_" }; + + my $err = ''; + for (1) { + defer { + eval 'last'; $err = $@; chomp $err; + } + } + is(scalar @warnings, 1, "Got exactly one warning"); + like($warnings[0], + qr/Exiting eval via last at/, + "Got expected warning: exiting eval via last"); + like( + $err, + qr/Can't "last" out of a "defer" block at \(eval \d+\) line 1\./, + "Got expected exception: last out of defer block"); +} +