It looks like some block statements report the line the block begins—dereferences, as in my OP, as well as calls to do and eval (block style only!)—but others, notably inline creation of an anonymous subroutine with sub { }, report the line after the block (???). I haven't messed around with the decompiler, but I assume this has to do with where the nextstate elements get placed.
#!/usr/bin/perl -w
use strict;
sub print_calling_line {
my $actual_line = shift;
my $caller_line = (caller)[2];
my $different = $actual_line != $caller_line ? "***" : "";
my $offset = " (+" . ($caller_line-$actual_line) . ")";
printf "%3s Called from %2d; caller() reports %2d%s [args: @_]\n",
$different, $actual_line, $caller_line, $offset;
}
print_calling_line( __LINE__,
1,
@{[
"DEREF"
]},
3
);
print_calling_line( __LINE__,
1,
do {
"DO"
},
3
);
print_calling_line( __LINE__,
1,
eval {
"EVAL"
},
3
);
print_calling_line( __LINE__,
1,
sub {
"SUB"
},
3,
4
);
outputs
*** Called from 13; caller() reports 15 (+2) [args: 1 DEREF 3]
*** Called from 21; caller() reports 23 (+2) [args: 1 DO 3]
*** Called from 29; caller() reports 31 (+2) [args: 1 EVAL 3]
*** Called from 37; caller() reports 42 (+5) [args: 1 CODE(0x9983be0)
+3]