This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Stop constant inlining from countermanding ‘use subs’
authorFather Chrysostomos <sprout@cpan.org>
Sun, 2 Jun 2013 07:31:27 +0000 (00:31 -0700)
committerFather Chrysostomos <sprout@cpan.org>
Sun, 2 Jun 2013 07:38:06 +0000 (00:38 -0700)
Ever since

commit f7461760003db2ce68155c97ea6c1658e96fcd27
Author: Zefram <zefram@fysh.org>
Date:   Sun Nov 8 15:03:45 2009 +0100

    Bareword sub lookups
    ...

this has failed:

$ perl5.10 -le 'use subs "abs";  sub abs() {44}; print abs + abs'
88
$ perl5.12 -le 'use subs "abs";  sub abs() {44}; print abs + abs'
44

A GV holding a single constant is a candidate for downgrading after
it uhas been used.  The GV gets downgraded after the first ‘abs’ is
inlined.  In the process, the CV-imported flag, which is stored in the
GV, not the CV, is lost, preventing &abs from overriding the built-in
function on the second mention.

There is a special flag for RVs, namely SVprv_PCS_IMPORTED,
which indicates that, when expanded to GVs, they should have the
GVf_IMPORTED_CV flag set.  But gv_try_downgrade wasn‘t setting
that flag.

gv.c
t/op/override.t

diff --git a/gv.c b/gv.c
index 2325194..b89181e 100644 (file)
--- a/gv.c
+++ b/gv.c
@@ -3174,10 +3174,11 @@ Perl_gv_try_downgrade(pTHX_ GV *gv)
                        HEK_LEN(namehek)*(HEK_UTF8(namehek) ? -1 : 1), 0)) &&
            *gvp == (SV*)gv) {
        SV *value = SvREFCNT_inc(CvXSUBANY(cv).any_ptr);
+       const bool imported = !!GvIMPORTED_CV(gv);
        SvREFCNT(gv) = 0;
        sv_clear((SV*)gv);
        SvREFCNT(gv) = 1;
-       SvFLAGS(gv) = SVt_IV|SVf_ROK;
+       SvFLAGS(gv) = SVt_IV|SVf_ROK|SVprv_PCS_IMPORTED * imported;
        SvANY(gv) = (XPVGV*)((char*)&(gv->sv_u.svu_iv) -
                                STRUCT_OFFSET(XPVIV, xiv_iv));
        SvRV_set(gv, value);
index a3cb14a..90510dd 100644 (file)
@@ -6,7 +6,7 @@ BEGIN {
     require './test.pl';
 }
 
-plan tests => 28;
+plan tests => 29;
 
 #
 # This file tries to test builtin override using CORE::GLOBAL
@@ -144,3 +144,9 @@ BEGIN { *OverridenPop::pop = sub { ::is( $_[0][0], "ok" ) }; }
     };
     is $@, '';
 }
+
+# Constant inlining should not countermand "use subs" overrides
+BEGIN { package other; *::caller = \&::caller }
+sub caller() { 42 }
+caller; # inline the constant
+is caller, 42, 'constant inlining does not undo "use subs" on keywords';