summaryrefslogtreecommitdiff
path: root/lib/B/Deparse.t
diff options
context:
space:
mode:
authorDavid Mitchell <davem@iabyn.com>2017-11-22 09:51:24 +0000
committerDavid Mitchell <davem@iabyn.com>2017-11-23 08:52:16 +0000
commit7d9a919c809c575ad530e1025df07f95fa492767 (patch)
tree50b856d48dcb2e2aa9043c000fe3a7a2bfd1c13f /lib/B/Deparse.t
parent4b75096ee07e668de3506087241f78f5ac6fd702 (diff)
downloadperl-7d9a919c809c575ad530e1025df07f95fa492767.tar.gz
Deparse: avoid upgrading RV to GV in stash entries
As well as being undesirable in its own right, it was causing some subs not to be deparsed. In something like package Foo; sub f { ... } *g = \&f; The stash entry $Foo::{f} is an RV pointing to the CV, while $Foo::{g} is a GV whose CV slot points to the same CV. That CV's CvNAME() will be 'f' and its CvSTASH() will point to %Foo::. If Deparse attempts to process $Foo::{g} before $Foo::{f}, it will get a GV and in that code path it does something like $cv = $gv->CV; next if $$gv != ${$cv->GV}; # Ignore imposters The trouble is that $cv->GV calls (at the C level) CvGV(cv), which tries to retrieve the GV stored in $Foo::{f}, and finding only an RV, upgrades it to a GV. This confuses Deparse, because it has already created objects for all the stash's entries, so when it comes to process $Foo::{f}, it already has a B::IV object for the RV (and so goes down the RV code path), but further introspection of that object (such as flags) sees a GV, Hence the 3 lines of code at the top of this text were being deparsed without 'sub f {}' being emitted. This has been a problem for a while, but only recently has the "RV->CV instead of GV->CV" optimisation been applied outside of package main::, and so become more noticeable.
Diffstat (limited to 'lib/B/Deparse.t')
-rw-r--r--lib/B/Deparse.t18
1 files changed, 17 insertions, 1 deletions
diff --git a/lib/B/Deparse.t b/lib/B/Deparse.t
index fe176e1a62..ca1bdb4384 100644
--- a/lib/B/Deparse.t
+++ b/lib/B/Deparse.t
@@ -13,7 +13,7 @@ BEGIN {
use warnings;
use strict;
-my $tests = 49; # not counting those in the __DATA__ section
+my $tests = 52; # not counting those in the __DATA__ section
use B::Deparse;
my $deparse = B::Deparse->new();
@@ -546,6 +546,22 @@ unlike runperl(stderr => 1, switches => [ '-MO=-qq,Deparse', $path, '-w' ],
qr'Use of uninitialized value',
'no warnings for undefined sub';
+is runperl(stderr => 1, switches => [ '-MO=-qq,Deparse', $path ],
+ prog => 'sub f { 1; } BEGIN { *g = \&f; }'),
+ "sub f {\n 1;\n}\nsub BEGIN {\n *g = \\&f;\n}\n",
+ "sub glob alias shouldn't impede emitting original sub";
+
+is runperl(stderr => 1, switches => [ '-MO=-qq,Deparse', $path ],
+ prog => 'package Foo; sub f { 1; } BEGIN { *g = \&f; }'),
+ "package Foo;\nsub f {\n 1;\n}\nsub BEGIN {\n *g = \\&f;\n}\n",
+ "sub glob alias outside main shouldn't impede emitting original sub";
+
+is runperl(stderr => 1, switches => [ '-MO=-qq,Deparse', $path ],
+ prog => 'package Foo; sub f { 1; } BEGIN { *Bar::f = \&f; }'),
+ "package Foo;\nsub f {\n 1;\n}\nsub BEGIN {\n *Bar::f = \\&f;\n}\n",
+ "sub glob alias in separate package shouldn't impede emitting original sub";
+
+
done_testing($tests);
__DATA__