From 5d8ab95357a99a13e919b0e5c19f9a7abb06167d Mon Sep 17 00:00:00 2001 From: Nicholas Clark Date: Mon, 7 Mar 2011 10:27:17 +0000 Subject: [PATCH] Ensure that the C 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 code had been compiled, as the compiler implicitly creates typeglobs in the Errno symbol table when it builds the optree for the C. --- ext/Errno/Errno_pm.PL | 13 +++++++++++-- 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 5725de8..c38f309 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, 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 302bd8d..3baaf60 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'); +} -- 1.8.3.1