diff options
author | Father Chrysostomos <sprout@cpan.org> | 2010-10-09 18:42:01 -0700 |
---|---|---|
committer | Father Chrysostomos <sprout@cpan.org> | 2010-10-09 18:42:40 -0700 |
commit | c8bbf675c3e9277e1dd4b1185d91c1aef2cd2594 (patch) | |
tree | ac43f29d32d5dce5d6a0e58a2ce6bf91454604ce /hv.c | |
parent | 314655b3bf3a78f53857298857fbdc053e783117 (diff) | |
download | perl-c8bbf675c3e9277e1dd4b1185d91c1aef2cd2594.tar.gz |
Reset isa on stash manipulation
This only applies to glob-to-glob assignments and deletions of stash
elements. Other types of stash manipulation are dealt with by subse-
quent patches.
It adds mro_package_moved, a private function that iterates through
subpackages, calling mro_isa_changed_in on each.
This is related to [perl #75176], but is not the same bug. It simply
got in the way of fixing [perl #75176].
Diffstat (limited to 'hv.c')
-rw-r--r-- | hv.c | 38 |
1 files changed, 37 insertions, 1 deletions
@@ -692,8 +692,32 @@ Perl_hv_common(pTHX_ HV *hv, SV *keysv, const char *key, STRLEN klen, } HeVAL(entry) = val; } else if (action & HV_FETCH_ISSTORE) { - SvREFCNT_dec(HeVAL(entry)); + bool moving_package = FALSE; + SV *old_val = HeVAL(entry); + + /* If this is a stash and the key ends with ::, then some- + one is aliasing (or moving) a package. */ + if (HvNAME(hv)) { + if (keysv) key = SvPV(keysv, klen); + if (klen > 1 + && key[klen-2] == ':' && key[klen-1] == ':') { + if(SvTYPE(old_val) == SVt_PVGV) { + const HV * const old_stash + = GvHV((GV *)old_val); + if(old_stash && HvNAME(old_stash)) + mro_package_moved(old_stash); + } + moving_package = TRUE; + } + } + + SvREFCNT_dec(old_val); HeVAL(entry) = val; + + if (moving_package && SvTYPE(val) == SVt_PVGV) { + const HV * const stash = GvHV((GV *)val); + if (stash && HvNAME(stash)) mro_package_moved(stash); + } } } else if (HeVAL(entry) == &PL_sv_placeholder) { /* if we find a placeholder, we pretend we haven't found @@ -1036,6 +1060,18 @@ S_hv_delete_common(pTHX_ HV *hv, SV *keysv, const char *key, STRLEN klen, HvPLACEHOLDERS(hv)++; } else { *oentry = HeNEXT(entry); + + /* If this is a stash and the key ends with ::, then someone is + deleting a package. */ + if (sv && HvNAME(hv)) { + if (keysv) key = SvPV(keysv, klen); + if (klen > 1 && key[klen-2] == ':' && key[klen-1] == ':' + && SvTYPE(sv) == SVt_PVGV) { + const HV * const stash = GvHV((GV *)sv); + if (stash && HvNAME(stash)) mro_package_moved(stash); + } + } + if (SvOOK(hv) && entry == HvAUX(hv)->xhv_eiter /* HvEITER(hv) */) HvLAZYDEL_on(hv); else |