Reputation: 3838
The following (much stripped-down) code has an obvious error.
#!/usr/bin/env perl
use strict;
use warnings FATAL=>"all";
my $err_phyle;
my $verb;
sub do_measure
{
print($error_phyle "xxx");
}
sub dye
{
}
dye "invalid verb \"$verb\"";
You'd expect the error message to be:
Global symbol "$error_phyle" requires explicit package name at example.pl line 11.
example.pl had compilation errors.
... but it's actually ...
String found where operator expected at example.pl line 19, near "dye "invalid verb \"$verb\"""
(Note that the second error message doesn't add "example.pl had compilation errors.".)
In the real program, the error message pointed to a line hundreds of lines of code away from the actual error. Incorrect error messages, pointing to the wrong line, can lead to much merriment trying to track down the syntax error.
I can "fix" this in the above program by surrounding the argument of the call to function dye
with parentheses, and I guess I'll go through the program and do this. But is this a bug in Perl, or (as is more likely the case) am I missing something about how Perl works?
Upvotes: 1
Views: 245
Reputation: 85757
The root cause of this issue is that perl's (yacc-based) parser tries to recover and continue after errors. The original idea behind this strategy is that running a compiler used to be a slow and expensive task, so you want it to catch as many errors as possible in a single run, not just the first error. This is why perl queues up errors encountered during parsing before giving up and printing them all at once.
However, there's an unfortunate interaction with fatal warnings. The compiler can emit warnings at compile time, and fatalizing a warning makes it throw an exception. So if the parser is in error recovery mode and encounters a fatal warning, an exception is thrown and all the queued actual errors are lost.
The String found where operator expected
message is a warning (category syntax
). By fatalizing all warnings you've turned it into an exception that immediately aborts parsing, losing all preceding errors. (By the way, fatalizing all warnings is a bad idea: See perldoc strictures
for which warning categories are unsafe to fatalize.)
You can see that something isn't quite right even without fatalizing warnings: The String found ...
message has a line number of 19, yet it appears before the syntax error in line 11. This is because warnings are emitted immediately, not queued like parse errors.
This problem was reported as bug #122966 and fixed in perl 5.22. Now fatal warnings thrown during parsing are treated like parse errors and queued the same way. (As a side effect, it also makes the error messages appear in the right order: The first error is reported first.)
So yes, this behavior is a bug in perl, but one that was already fixed in a later release.
Upvotes: 6
Reputation: 40718
You can use the diagnostics pragma to get more information about the errors.
The
diagnostics
PragmaThis module extends the terse diagnostics normally emitted by both the perl compiler and the perl interpreter (from running perl with a -w switch or use warnings ), augmenting them with the more explicative and endearing descriptions found in
perldiag
. Like the other pragmata, it affects the compilation phase of your program rather than merely the execution phase. To use in your program as a pragma, merely invokeuse diagnostics;
at the start (or near the start) of your program. (Note that this does enable perl's -w flag.) Your whole compilation will then be subject(ed :-) to the enhanced diagnostics. These still go out STDERR.
Based on your comments: this can also make older versions of perl show both error messages, which could save you some debugging effort to find the location of the real error.
Upvotes: 1