summaryrefslogtreecommitdiff
path: root/ext/Errno
diff options
context:
space:
mode:
authorNicholas Clark <nick@ccl4.org>2011-03-07 10:27:17 +0000
committerNicholas Clark <nick@ccl4.org>2011-03-07 10:32:52 +0000
commit5d8ab95357a99a13e919b0e5c19f9a7abb06167d (patch)
tree14332a3aeadbad487ed2824253d20828aefc3287 /ext/Errno
parent7c579eed878fc49f1db8118b45c262d16571a5c1 (diff)
downloadperl-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/Errno')
-rw-r--r--ext/Errno/Errno_pm.PL13
-rw-r--r--ext/Errno/t/Errno.t19
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');
+}