X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=pp_hot.c;h=6fb53d49a4c303f56b0e43e120d41c02b6594312;hb=ce5e090c3cdc0df8112cc707442a0492b20b168b;hp=5cd758f6abfc53b70845d43c4fc9d65d4affa02d;hpb=62e7980d92132e301c6ee622ce9f1c56fd344af7;p=p5sagit%2Fp5-mst-13.2.git diff --git a/pp_hot.c b/pp_hot.c index 5cd758f..6fb53d4 100644 --- a/pp_hot.c +++ b/pp_hot.c @@ -168,18 +168,44 @@ PP(pp_sassign) if (!got_coderef) { /* We've been returned a constant rather than a full subroutine, but they expect a subroutine reference to apply. */ - ENTER; - SvREFCNT_inc_void(SvRV(cv)); - /* newCONSTSUB takes a reference count on the passed in SV - from us. We set the name to NULL, otherwise we get into - all sorts of fun as the reference to our new sub is - donated to the GV that we're about to assign to. - */ - SvRV_set(left, (SV *)newCONSTSUB(GvSTASH(right), NULL, + if (SvROK(cv)) { + ENTER; + SvREFCNT_inc_void(SvRV(cv)); + /* newCONSTSUB takes a reference count on the passed in SV + from us. We set the name to NULL, otherwise we get into + all sorts of fun as the reference to our new sub is + donated to the GV that we're about to assign to. + */ + SvRV_set(left, (SV *)newCONSTSUB(GvSTASH(right), NULL, SvRV(cv))); - SvREFCNT_dec(cv); - LEAVE; + SvREFCNT_dec(cv); + LEAVE; + } else { + /* What can happen for the corner case *{"BONK"} = \&{"BONK"}; + is that + First: ops for \&{"BONK"}; return us the constant in the + symbol table + Second: ops for *{"BONK"} cause that symbol table entry + (and our reference to it) to be upgraded from RV + to typeblob) + Thirdly: We get here. cv is actually PVGV now, and its + GvCV() is actually the subroutine we're looking for + + So change the reference so that it points to the subroutine + of that typeglob, as that's what they were after all along. + */ + GV *const upgraded = (GV *) cv; + CV *const source = GvCV(upgraded); + + assert(source); + assert(CvFLAGS(source) & CVf_CONST); + + SvREFCNT_inc_void(source); + SvREFCNT_dec(upgraded); + SvRV_set(left, (SV *)source); + } } + } SvSetMagicSV(right, left); SETs(right); @@ -1005,6 +1031,8 @@ PP(pp_aassign) } TAINT_NOT; } + if (PL_delaymagic & DM_ARRAY) + SvSETMAGIC((SV*)ary); break; case SVt_PVHV: { /* normal hash */ SV *tmpstr; @@ -1152,14 +1180,6 @@ PP(pp_aassign) *relem++ = (lelem <= lastlelem) ? *lelem++ : &PL_sv_undef; } - /* This is done at the bottom and in this order because - mro_isa_changed_in() can throw exceptions */ - if(PL_delayedisa) { - HV* stash = PL_delayedisa; - PL_delayedisa = NULL; - mro_isa_changed_in(stash); - } - RETURN; } @@ -3019,7 +3039,7 @@ S_method_common(pTHX_ SV* meth, U32* hashp) packsv = sv; else { SV* const ref = newSViv(PTR2IV(stash)); - hv_store(PL_stashcache, packname, packlen, ref, 0); + (void)hv_store(PL_stashcache, packname, packlen, ref, 0); } goto fetch; }