diff options
author | Nicholas Clark <nick@ccl4.org> | 2011-03-07 10:27:17 +0000 |
---|---|---|
committer | Nicholas Clark <nick@ccl4.org> | 2011-03-07 10:32:52 +0000 |
commit | 5d8ab95357a99a13e919b0e5c19f9a7abb06167d (patch) | |
tree | 14332a3aeadbad487ed2824253d20828aefc3287 /ext | |
parent | 7c579eed878fc49f1db8118b45c262d16571a5c1 (diff) | |
download | perl-5d8ab95357a99a13e919b0e5c19f9a7abb06167d.tar.gz |
Ensure that the C<exists &Errno::EFOO> idiom continues to work as documented.
A change post-5.12 (probably 42607a60df6df19b) caused the documented idiom not
to work if Errno was loaded after the C<exists> code had been compiled, as
the compiler implicitly creates typeglobs in the Errno symbol table when it
builds the optree for the C<exists code>.
Diffstat (limited to 'ext')
-rw-r--r-- | ext/Errno/Errno_pm.PL | 13 | ||||
-rw-r--r-- | ext/Errno/t/Errno.t | 19 |
2 files changed, 29 insertions, 3 deletions
diff --git a/ext/Errno/Errno_pm.PL b/ext/Errno/Errno_pm.PL index 5725de86ee..c38f309c54 100644 --- a/ext/Errno/Errno_pm.PL +++ b/ext/Errno/Errno_pm.PL @@ -356,14 +356,23 @@ EDQ print <<'ESQ'; ); # Generate proxy constant subroutines for all the values. - # We assume at this point that our symbol table is empty. + # Well, almost all the values. Unfortunately we can't assume that at this + # point that our symbol table is empty, as code such as if the parser has + # seen code such as C<exists &Errno::EINVAL>, it will have created the + # typeglob. # Doing this before defining @EXPORT_OK etc means that even if a platform is # crazy enough to define EXPORT_OK as an error constant, everything will # still work, because the parser will upgrade the PCS to a real typeglob. # We rely on the subroutine definitions below to update the internal caches. # Don't use %each, as we don't want a copy of the value. foreach my $name (keys %err) { - $Errno::{$name} = \$err{$name}; + if ($Errno::{$name}) { + # We expect this to be reached fairly rarely, so take an approach + # which uses the least compile time effort in the common case: + eval "sub $name() { $err{$name} }; 1" or die $@; + } else { + $Errno::{$name} = \$err{$name}; + } } } diff --git a/ext/Errno/t/Errno.t b/ext/Errno/t/Errno.t index 302bd8ddd6..3baaf60c4c 100644 --- a/ext/Errno/t/Errno.t +++ b/ext/Errno/t/Errno.t @@ -1,6 +1,9 @@ #!./perl -w -use Test::More tests => 10; +use Test::More tests => 12; + +# Keep this before the use Errno. +my $has_einval = exists &Errno::EINVAL; BEGIN { use_ok("Errno"); @@ -34,3 +37,17 @@ like($@, qr/^ERRNO hash is read only!/); # through Acme::MetaSyntactic::batman is($!{EFLRBBB}, ""); ok(! exists($!{EFLRBBB})); + +SKIP: { + skip("Errno does not have EINVAL", 1) + unless grep {$_ eq 'EINVAL'} @Errno::EXPORT_OK; + is($has_einval, 1, + 'exists &Errno::EINVAL compiled before Errno is loaded works fine'); +} + +SKIP: { + skip("Errno does not have EBADF", 1) + unless grep {$_ eq 'EBADF'} @Errno::EXPORT_OK; + is(exists &Errno::EBADF, 1, + 'exists &Errno::EBADF compiled after Errno is loaded works fine'); +} |