diff options
author | Father Chrysostomos <sprout@cpan.org> | 2014-12-05 06:21:35 -0800 |
---|---|---|
committer | Father Chrysostomos <sprout@cpan.org> | 2014-12-05 15:51:38 -0800 |
commit | 67359f08ae288ccd943818bc458394bda2c8409f (patch) | |
tree | e7aace706ac6be8efd7f574fb0ef6a39920a3931 /lib | |
parent | b68eab22f47f27e55acb9cccd69e982cdd595f45 (diff) | |
download | perl-67359f08ae288ccd943818bc458394bda2c8409f.tar.gz |
Deparse predeclared prototyped subs
A predeclared sub without a prototype works fine:
$ ./perl -Ilib -MO=Deparse -e 'sub f; sub f{}; foo()'
sub f {
}
foo();
-e syntax OK
A prototyped sub with no predeclaration is fine:
$ ./perl -Ilib -MO=Deparse -e ' sub f($){}; foo()'
sub f ($) {
}
foo();
-e syntax OK
A prototyped stub is fine:
$ ./perl -Ilib -MO=Deparse -e 'sub f($); foo()'
sub f ($);
foo();
-e syntax OK
Only a predeclared prototyped sub seems to have trouble appear-
ing properly:
$ ./perl -Ilib -MO=Deparse -e 'sub f($); sub f($){}; foo()'
sub f;
foo();
-e syntax OK
The code that searches the stashes (stash_subs) was assuming that any-
thing of type B::PV was a prototype. In this case, the stash entry
started as a string and then got ‘downgraded’ to a reference, so
internally it is of type PV (which can hold a ref), which B represents
as B::PV, so the assumption that a PV is a prototyped stub is wrong.
Diffstat (limited to 'lib')
-rw-r--r-- | lib/B/Deparse.pm | 21 | ||||
-rw-r--r-- | lib/B/Deparse.t | 6 |
2 files changed, 16 insertions, 11 deletions
diff --git a/lib/B/Deparse.pm b/lib/B/Deparse.pm index dea21a9aa6..513e2d1ba5 100644 --- a/lib/B/Deparse.pm +++ b/lib/B/Deparse.pm @@ -699,7 +699,16 @@ sub stash_subs { my %stash = svref_2object($stash)->ARRAY; while (my ($key, $val) = each %stash) { my $class = class($val); - if ($class eq "PV") { + if ($val->FLAGS & SVf_ROK) { + # A reference. Dump this if it is a reference to a CV. + # But skip proxy constant subroutines, as some form of perl- + # space visible code must have created them, be it a use + # statement, or some direct symbol-table manipulation code that + # we will Deparse. + if (class(my $cv = $val->RV) eq "CV") { + $self->todo($cv, 0); + } + } elsif ($class eq "PV") { # Just a prototype. As an ugly but fairly effective way # to find out if it belongs here is to see if the AUTOLOAD # (if any) for the stash was defined in one of our files. @@ -710,11 +719,8 @@ sub stash_subs { next unless $AF eq $0 || exists $self->{'files'}{$AF}; } push @{$self->{'protos_todo'}}, [$pack . $key, $val->PV]; - } elsif ($class eq "IV" && !($val->FLAGS & SVf_ROK)) { + } elsif ($class eq "IV") { # Just a name. As above. - # But skip proxy constant subroutines, as some form of perl-space - # visible code must have created them, be it a use statement, or - # some direct symbol-table manipulation code that we will Deparse my $A = $stash{"AUTOLOAD"}; if (defined ($A) && class($A) eq "GV" && defined($A->CV) && class($A->CV) eq "CV") { @@ -722,11 +728,6 @@ sub stash_subs { next unless $AF eq $0 || exists $self->{'files'}{$AF}; } push @{$self->{'protos_todo'}}, [$pack . $key, undef]; - } elsif ($class eq "IV") { - # A reference. Dump this if it is a reference to a CV. - if (class(my $cv = $val->RV) eq "CV") { - $self->todo($cv, 0); - } } elsif ($class eq "GV") { if (class(my $cv = $val->CV) ne "SPECIAL") { next if $self->{'subs_done'}{$$val}++; diff --git a/lib/B/Deparse.t b/lib/B/Deparse.t index f39e1c8483..1f2efdd070 100644 --- a/lib/B/Deparse.t +++ b/lib/B/Deparse.t @@ -13,7 +13,7 @@ BEGIN { use warnings; use strict; -my $tests = 33; # not counting those in the __DATA__ section +my $tests = 34; # not counting those in the __DATA__ section use B::Deparse; my $deparse = B::Deparse->new(); @@ -343,6 +343,10 @@ like($a, qr/my sub __DATA__;\n.*\nCORE::__DATA__/s, # sub declarations $a = readpipe qq`$^X $path "-MO=Deparse" -e "sub foo{}" 2>&1`; like($a, qr/sub foo\s*\{\s+\}/, 'sub declarations'); +like runperl(stderr => 1, switches => [ '-MO=-qq,Deparse', $path ], + prog => 'sub f($); sub f($){}'), + qr/sub f\s*\(\$\)\s*\{\s*\}/, + 'predeclared prototyped subs'; # BEGIN blocks SKIP : { |