summaryrefslogtreecommitdiff
path: root/hv.c
diff options
context:
space:
mode:
authorFather Chrysostomos <sprout@cpan.org>2011-12-31 18:18:57 -0800
committerFather Chrysostomos <sprout@cpan.org>2011-12-31 19:11:39 -0800
commit5743f2a37eb9fda061f42b2df6b4c8119b14eaf1 (patch)
tree5c7bbdc0d032bad525d8da489b732ae1d17b2784 /hv.c
parent4bb78d633325d95f788c504d75b0fcae3fbc9f46 (diff)
downloadperl-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.c18
1 files changed, 10 insertions, 8 deletions
diff --git a/hv.c b/hv.c
index 9a088a923a..e1f80400b5 100644
--- a/hv.c
+++ b/hv.c
@@ -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