correctly unlocalise exists on tied/%ENV
Dave Mitchell [Tue, 7 May 2002 23:13:10 +0000 (00:13 +0100)]
Message-ID: <20020507231310.B4118@fdgroup.com>

p4raw-id: //depot/perl@16455

pp_hot.c

index f2387b4..98229a2 100644 (file)
--- a/pp_hot.c
+++ b/pp_hot.c
@@ -1643,13 +1643,25 @@ PP(pp_helem)
     I32 preeminent = 0;
 
     if (SvTYPE(hv) == SVt_PVHV) {
-       if (PL_op->op_private & OPpLVAL_INTRO)
+       if (PL_op->op_private & OPpLVAL_INTRO) {
+           MAGIC *mg;
+           HV *stash;
+           /* does the element we're localizing already exist? */
            preeminent =  
-               ( SvRMAGICAL(hv)
-                 && !mg_find((SV*)hv, PERL_MAGIC_tied)
-                 && !mg_find((SV*)hv, PERL_MAGIC_env)
-               ) ? 1 : hv_exists_ent(hv, keysv, 0);
+               /* can we determine whether it exists? */
+               (    !SvRMAGICAL(hv)
+                 || mg_find((SV*)hv, PERL_MAGIC_env)
+                 || (     (mg = mg_find((SV*)hv, PERL_MAGIC_tied))
+                       /* Try to preserve the existenceness of a tied hash
+                        * element by using EXISTS and DELETE if possible.
+                        * Fallback to FETCH and STORE otherwise */
+                       && (stash = SvSTASH(SvRV(SvTIED_obj((SV*)hv, mg))))
+                       && gv_fetchmethod_autoload(stash, "EXISTS", TRUE)
+                       && gv_fetchmethod_autoload(stash, "DELETE", TRUE)
+                   )
+               ) ? hv_exists_ent(hv, keysv, 0) : 1;
 
+       }
        he = hv_fetch_ent(hv, keysv, lval && !defer, hash);
        svp = he ? &HeVAL(he) : 0;
     }