Fix two local *ISA bugs
authorFather Chrysostomos <sprout@cpan.org>
Wed, 28 Nov 2012 21:46:07 +0000 (13:46 -0800)
committerFather Chrysostomos <sprout@cpan.org>
Thu, 29 Nov 2012 17:11:31 +0000 (09:11 -0800)
These are regressions from 5.8.

local *ISA was not updating isa caches. local *ISA = [] was updating
caches, but scope unwinding was not.

Both save_gp and leave_scope/SAVEt_GP need to check whether the glob
is named ISA and call mro_isa_changed_in if appropriate.

scope.c
t/mro/basic.t

diff --git a/scope.c b/scope.c
index c4a2222..31b990d 100644 (file)
--- a/scope.c
+++ b/scope.c
@@ -286,14 +286,21 @@ Perl_save_gp(pTHX_ GV *gv, I32 empty)
     if (empty) {
        GP *gp = Perl_newGP(aTHX_ gv);
        HV * const stash = GvSTASH(gv);
-
-       if (GvCVu(gv) && stash && HvENAME(stash))
-            mro_method_changed_in(GvSTASH(gv)); /* taking a method out of circulation ("local")*/
+       bool isa_changed = 0;
+
+       if (stash && HvENAME(stash)) {
+           if (GvNAMELEN(gv) == 3 && strnEQ(GvNAME(gv), "ISA", 3))
+               isa_changed = TRUE;
+           else if (GvCVu(gv))
+               /* taking a method out of circulation ("local")*/
+                mro_method_changed_in(stash);
+       }
        if (GvIOp(gv) && (IoFLAGS(GvIOp(gv)) & IOf_ARGV)) {
            gp->gp_io = newIO();
            IoFLAGS(gp->gp_io) |= IOf_ARGV|IOf_START;
        }
        GvGP_set(gv,gp);
+       if (isa_changed) mro_isa_changed_in(stash);
     }
     else {
        gp_ref(GvGP(gv));
@@ -860,9 +867,13 @@ Perl_leave_scope(pTHX_ I32 base)
            gv = MUTABLE_GV(SSPOPPTR);
            gp_free(gv);
            GvGP_set(gv, (GP*)ptr);
-            /* putting a method back into circulation ("local")*/
-           if (GvCVu(gv) && (hv=GvSTASH(gv)) && HvENAME_get(hv))
+           if ((hv=GvSTASH(gv)) && HvENAME_get(hv)) {
+             if (GvNAMELEN(gv) == 3 && strnEQ(GvNAME(gv), "ISA", 3))
+               mro_isa_changed_in(hv);
+             else if (GvCVu(gv))
+                /* putting a method back into circulation ("local")*/  
                 gv_method_changed(gv);
+           }
            SvREFCNT_dec(gv);
            break;
        case SAVEt_FREESV:
index cc1386c..ab34fc2 100644 (file)
@@ -3,7 +3,7 @@
 use strict;
 use warnings;
 
-BEGIN { require q(./test.pl); } plan(tests => 55);
+BEGIN { require q(./test.pl); } plan(tests => 59);
 
 require mro;
 
@@ -353,3 +353,20 @@ is(eval { MRO_N->testfunc() }, 123);
     eval { local *Detached::method };
     is $@, "", 'localising gv-with-cv belonging to detached package';
 }
+
+{
+    # *ISA localisation
+    @il::ISA = "ilsuper";
+    sub ilsuper::can { "puree" }
+    sub il::tomatoes;
+    {
+        local *il::ISA;
+        is +il->can("tomatoes"), \&il::tomatoes, 'local *ISA';
+    }
+    is "il"->can("tomatoes"), "puree", 'local *ISA unwinding';
+    {
+        local *il::ISA = [];
+        is +il->can("tomatoes"), \&il::tomatoes, 'local *ISA = []';
+    }
+    is "il"->can("tomatoes"), "puree", 'local *ISA=[] unwinding';
+}