p |int |magic_setfm |NN SV* sv|NN MAGIC* mg
dp |int |magic_sethint |NN SV* sv|NN MAGIC* mg
p |int |magic_setisa |NN SV* sv|NN MAGIC* mg
+p |int |magic_freeisa |NN SV* sv|NN MAGIC* mg
p |int |magic_setglob |NN SV* sv|NN MAGIC* mg
p |int |magic_setmglob |NN SV* sv|NN MAGIC* mg
p |int |magic_setnkeys |NN SV* sv|NN MAGIC* mg
#define magic_setfm Perl_magic_setfm
#define magic_sethint Perl_magic_sethint
#define magic_setisa Perl_magic_setisa
+#define magic_freeisa Perl_magic_freeisa
#define magic_setglob Perl_magic_setglob
#define magic_setmglob Perl_magic_setmglob
#define magic_setnkeys Perl_magic_setnkeys
#define magic_setfm(a,b) Perl_magic_setfm(aTHX_ a,b)
#define magic_sethint(a,b) Perl_magic_sethint(aTHX_ a,b)
#define magic_setisa(a,b) Perl_magic_setisa(aTHX_ a,b)
+#define magic_freeisa(a,b) Perl_magic_freeisa(aTHX_ a,b)
#define magic_setglob(a,b) Perl_magic_setglob(aTHX_ a,b)
#define magic_setmglob(a,b) Perl_magic_setmglob(aTHX_ a,b)
#define magic_setnkeys(a,b) Perl_magic_setnkeys(aTHX_ a,b)
{
dVAR;
SV *val;
+ I32 isa_changing = 0;
if (!entry)
return;
val = HeVAL(entry);
- if (val && isGV(val) && GvCVu(val) && HvNAME_get(hv))
- mro_method_changed_in(hv); /* deletion of method from stash */
+
+ if(HvNAME_get(hv) && val && isGV(val)) {
+ if(GvCVu((GV*)val))
+ mro_method_changed_in(hv); /* deletion of method from stash */
+ else if(GvAV((GV*)val) && strEQ(GvNAME((GV*)val), "ISA"))
+ isa_changing = 1;
+ }
+
SvREFCNT_dec(val);
if (HeKLEN(entry) == HEf_SVKEY) {
SvREFCNT_dec(HeKEY_sv(entry));
else
Safefree(HeKEY_hek(entry));
del_HE(entry);
+
+ if(isa_changing) mro_isa_changed_in(hv); /* deletion of @ISA from stash */
}
void
DEBUG_A(Perl_hv_assert(aTHX_ hv));
xhv = (XPVHV*)SvANY(hv);
- if ((name = HvNAME_get(hv)) && !PL_dirty)
+ /* If it's a stash, undef the @ISA and call
+ mro_isa_changed_in before proceeding with
+ the rest of the destruction */
+ if ((name = HvNAME_get(hv)) && !PL_dirty) {
+ GV** gvp;
+ GV* gv;
+ AV* isa;
+
+ gvp = (GV**)hv_fetchs(hv, "ISA", FALSE);
+ gv = gvp ? *gvp : NULL;
+ isa = (gv && isGV_with_GP(gv)) ? GvAV(gv) : NULL;
+
+ if(isa) av_undef(isa);
mro_isa_changed_in(hv);
+ }
hfreeentries(hv);
if (name) {
return 0;
}
+int Perl_magic_freeisa(pTHX_ SV *sv, MAGIC *mg)
+{
+ dVAR;
+ GV** gvp;
+ GV* gv;
+ AV* isa;
+
+ PERL_UNUSED_ARG(sv);
+
+ if(PL_dirty) return 0;
+
+ gvp = (GV**)hv_fetchs(GvSTASH((GV*)mg->mg_obj), "ISA", FALSE);
+ gv = gvp ? *gvp : NULL;
+ isa = (gv && isGV_with_GP(gv)) ? GvAV(gv) : NULL;
+
+ if(isa) av_undef(isa);
+
+ return 0;
+}
+
int
Perl_magic_setamagic(pTHX_ SV *sv, MAGIC *mg)
{
bool is_universal;
struct mro_meta * meta;
- const char * const stashname = HvNAME_get(stash);
- const STRLEN stashname_len = HvNAMELEN_get(stash);
+ const char * const stashname = stash ? HvNAME_get(stash) : NULL;
+ const STRLEN stashname_len = stash ? HvNAMELEN_get(stash) : 0;
+
+ if(!stash) return;
if(!stashname)
Perl_croak(aTHX_ "Can't call mro_isa_changed_in() on anonymous symbol table");
MEMBER_TO_FPTR(Perl_magic_setisa),
0,
MEMBER_TO_FPTR(Perl_magic_setisa),
- 0,
+ MEMBER_TO_FPTR(Perl_magic_freeisa),
0,
0,
0
__attribute__nonnull__(pTHX_1)
__attribute__nonnull__(pTHX_2);
+PERL_CALLCONV int Perl_magic_freeisa(pTHX_ SV* sv, MAGIC* mg)
+ __attribute__nonnull__(pTHX_1)
+ __attribute__nonnull__(pTHX_2);
+
PERL_CALLCONV int Perl_magic_setglob(pTHX_ SV* sv, MAGIC* mg)
__attribute__nonnull__(pTHX_1)
__attribute__nonnull__(pTHX_2);
*/
if (!obj || obj == sv ||
how == PERL_MAGIC_arylen ||
+ how == PERL_MAGIC_isaelem ||
how == PERL_MAGIC_qr ||
how == PERL_MAGIC_symtab ||
(SvTYPE(obj) == SVt_PVGV &&
use strict;
use warnings;
-require q(./test.pl); plan(tests => 21);
+require q(./test.pl); plan(tests => 27);
{
package MRO_A;
}
# clearing @ISA in different ways
+# some are destructive to the package, hence the new
+# package name each time
{
no warnings 'uninitialized';
{
$ISACLEAR::ISA[1] = undef;
ok(eq_array(mro::get_linear_isa('ISACLEAR'),[qw/ISACLEAR XX main ZZ/]));
+ # undef the array itself
undef @ISACLEAR::ISA;
ok(eq_array(mro::get_linear_isa('ISACLEAR'),[qw/ISACLEAR/]));
}
+
+{
+ {
+ package ISACLEAR2;
+ our @ISA = qw/XX YY ZZ/;
+ }
+
+ # baseline
+ ok(eq_array(mro::get_linear_isa('ISACLEAR2'),[qw/ISACLEAR2 XX YY ZZ/]));
+
+ # delete @ISA
+ delete $ISACLEAR2::{ISA};
+ ok(eq_array(mro::get_linear_isa('ISACLEAR2'),[qw/ISACLEAR2/]));
+}
+
+# another destructive test, undef the ISA glob
+{
+ {
+ package ISACLEAR3;
+ our @ISA = qw/XX YY ZZ/;
+ }
+ # baseline
+ ok(eq_array(mro::get_linear_isa('ISACLEAR3'),[qw/ISACLEAR3 XX YY ZZ/]));
+
+ undef *ISACLEAR3::ISA;
+ ok(eq_array(mro::get_linear_isa('ISACLEAR3'),[qw/ISACLEAR3/]));
+}
+
+# This is how Class::Inner does it
+{
+ {
+ package ISACLEAR4;
+ our @ISA = qw/XX YY ZZ/;
+ }
+ # baseline
+ ok(eq_array(mro::get_linear_isa('ISACLEAR4'),[qw/ISACLEAR4 XX YY ZZ/]));
+
+ delete $ISACLEAR4::{ISA};
+ delete $::{ISACLEAR4::};
+ ok(eq_array(mro::get_linear_isa('ISACLEAR4'),[qw/ISACLEAR4/]));
+}