diff options
author | Father Chrysostomos <sprout@cpan.org> | 2011-12-31 18:18:57 -0800 |
---|---|---|
committer | Father Chrysostomos <sprout@cpan.org> | 2011-12-31 19:11:39 -0800 |
commit | 5743f2a37eb9fda061f42b2df6b4c8119b14eaf1 (patch) | |
tree | 5c7bbdc0d032bad525d8da489b732ae1d17b2784 /hv.c | |
parent | 4bb78d633325d95f788c504d75b0fcae3fbc9f46 (diff) | |
download | perl-5743f2a37eb9fda061f42b2df6b4c8119b14eaf1.tar.gz |
Update method caches for non-void stash elem deletions
Commit 71be2cb (inseparable changes from patch from perl5.003_13 to
perl5.003_14) added code to hv_free_ent to reset method caches if
necessary.
Later, a bug fix in the deletion code (f50383f5) made it necessary for
the value in the HE to be set to &PL_sv_placeholder, so it wouldn’t
free the sv just yet. So the method cache code (which by then had
changed from using PL_sub_generation to using mro_method_changed_in)
got repeated in S_hv_delete_common.
The only problem with all this is that hv_free_ent was the wrong place
to put it to begin with. If delete is called in non-void context,
the sv in it is not freed just yet, but returned; so hv_free_ent was
already being called with a HE pointing to &PL_sv_placeholder.
Commit f50383f5 only added the mro code for the void case, to avoid
changing existing behaviour when rearranging the code.
It turns out it needs to be done in S_hv_delete_common uncon-
ditionally.
Changing a test in t/op/method.t to use ()=delete instead of delete
makes it fail, because method caches end up going stale. See the test
in the diff.
Diffstat (limited to 'hv.c')
-rw-r--r-- | hv.c | 18 |
1 files changed, 10 insertions, 8 deletions
@@ -1052,19 +1052,21 @@ S_hv_delete_common(pTHX_ HV *hv, SV *keysv, const char *key, STRLEN klen, if (d_flags & G_DISCARD) { sv = HeVAL(entry); HeVAL(entry) = &PL_sv_placeholder; - if (sv) { - /* deletion of method from stash */ - if (isGV(sv) && isGV_with_GP(sv) && GvCVu(sv) - && HvENAME_get(hv)) - mro_method_changed_in(hv); - SvREFCNT_dec(sv); - sv = NULL; - } } else { sv = sv_2mortal(HeVAL(entry)); HeVAL(entry) = &PL_sv_placeholder; } + if (sv) { + /* deletion of method from stash */ + if (isGV(sv) && isGV_with_GP(sv) && GvCVu(sv) + && HvENAME_get(hv)) + mro_method_changed_in(hv); + if (d_flags & G_DISCARD) { + SvREFCNT_dec(sv); + sv = NULL; + } + } /* * If a restricted hash, rather than really deleting the entry, put |