This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
add a couple missing LEAVEs in perlio_async_run()
[perl5.git] / mro.c
diff --git a/mro.c b/mro.c
index 08320b7..830bea8 100644 (file)
--- a/mro.c
+++ b/mro.c
@@ -216,7 +216,7 @@ S_mro_get_linear_isa_dfs(pTHX_ HV *stash, U32 level)
     assert(HvAUX(stash));
 
     stashhek
-     = HvAUX(stash)->xhv_name && HvENAME_HEK_NN(stash)
+     = HvAUX(stash)->xhv_name_u.xhvnameu_name && HvENAME_HEK_NN(stash)
         ? HvENAME_HEK_NN(stash)
         : HvNAME_HEK(stash);
 
@@ -379,10 +379,9 @@ S_mro_get_linear_isa_dfs(pTHX_ HV *stash, U32 level)
 /*
 =for apidoc mro_get_linear_isa
 
-Returns either C<mro_get_linear_isa_c3> or
-C<mro_get_linear_isa_dfs> for the given stash,
-dependant upon which MRO is in effect
-for that stash.  The return value is a
+Returns the mro linearisation for the given stash.  By default, this
+will be whatever C<mro_get_linear_isa_dfs> returns unless some
+other MRO is in effect for the stash.  The return value is a
 read-only AV*.
 
 You are responsible for C<SvREFCNT_inc()> on the
@@ -666,7 +665,7 @@ S_mro_clean_isarev(pTHX_ HV * const isa, const char * const name,
             if(svp) {
                 HV * const isarev = (HV *)*svp;
                 (void)hv_delete(isarev, name, len, G_DISCARD);
-                if(!HvARRAY(isarev) || !HvKEYS(isarev))
+                if(!HvARRAY(isarev) || !HvUSEDKEYS(isarev))
                     (void)hv_delete(PL_isarev, key, klen, G_DISCARD);
             }
         }
@@ -738,27 +737,31 @@ Perl_mro_package_moved(pTHX_ HV * const stash, HV * const oldstash,
        ) return;
     }
     assert(SvOOK(GvSTASH(gv)));
-    assert(GvNAMELEN(gv) > 1);
+    assert(GvNAMELEN(gv));
     assert(GvNAME(gv)[GvNAMELEN(gv) - 1] == ':');
-    assert(GvNAME(gv)[GvNAMELEN(gv) - 2] == ':');
+    assert(GvNAMELEN(gv) == 1 || GvNAME(gv)[GvNAMELEN(gv) - 2] == ':');
     name_count = HvAUX(GvSTASH(gv))->xhv_name_count;
     if (!name_count) {
        name_count = 1;
-       namep = &HvAUX(GvSTASH(gv))->xhv_name;
+       namep = &HvAUX(GvSTASH(gv))->xhv_name_u.xhvnameu_name;
     }
     else {
-       namep = (HEK **)HvAUX(GvSTASH(gv))->xhv_name;
+       namep = HvAUX(GvSTASH(gv))->xhv_name_u.xhvnameu_names;
        if (name_count < 0) ++namep, name_count = -name_count - 1;
     }
     if (name_count == 1) {
        if (HEK_LEN(*namep) == 4 && strnEQ(HEK_KEY(*namep), "main", 4)) {
-           namesv = sv_2mortal(newSVpvs(""));
+           namesv = GvNAMELEN(gv) == 1
+               ? newSVpvs_flags(":", SVs_TEMP)
+               : newSVpvs_flags("",  SVs_TEMP);
        }
        else {
            namesv = sv_2mortal(newSVhek(*namep));
-           sv_catpvs(namesv, "::");
+           if (GvNAMELEN(gv) == 1) sv_catpvs(namesv, ":");
+           else                    sv_catpvs(namesv, "::");
        }
-       sv_catpvn(namesv, GvNAME(gv), GvNAMELEN(gv) - 2);
+       if (GvNAMELEN(gv) != 1)
+           sv_catpvn(namesv, GvNAME(gv), GvNAMELEN(gv) - 2);
                                          /* skip trailing :: */
     }
     else {
@@ -766,13 +769,18 @@ Perl_mro_package_moved(pTHX_ HV * const stash, HV * const oldstash,
        namesv = sv_2mortal((SV *)newAV());
        while (name_count--) {
            if(HEK_LEN(*namep) == 4 && strnEQ(HEK_KEY(*namep), "main", 4)){
-               aname = newSVpvs(""); namep++;
+               aname = GvNAMELEN(gv) == 1
+                        ? newSVpvs(":")
+                        : newSVpvs("");
+               namep++;
            }
            else {
                aname = newSVhek(*namep++);
-               sv_catpvs(aname, "::");
+               if (GvNAMELEN(gv) == 1) sv_catpvs(aname, ":");
+               else                    sv_catpvs(aname, "::");
            }
-           sv_catpvn(aname, GvNAME(gv), GvNAMELEN(gv) - 2);
+           if (GvNAMELEN(gv) != 1)
+               sv_catpvn(aname, GvNAME(gv), GvNAMELEN(gv) - 2);
                                          /* skip trailing :: */
            av_push((AV *)namesv, aname);
        }
@@ -830,7 +838,7 @@ S_mro_gather_and_rename(pTHX_ HV * const stashes, HV * const seen_stashes,
     register XPVHV* xhv;
     register HE *entry;
     I32 riter = -1;
-    I32 items;
+    I32 items = 0;
     const bool stash_had_name = stash && HvENAME(stash);
     bool fetched_isarev = FALSE;
     HV *seen = NULL;
@@ -939,7 +947,7 @@ S_mro_gather_and_rename(pTHX_ HV * const stashes, HV * const seen_stashes,
        * mro_isa_changed_in called on it. That happens if it was
        * detached from the symbol table (so it had no HvENAME) before
        * being assigned to the spot named by the ‘name’ variable, because
-       * its cached isa linerisation is now stale (the effective name
+       * its cached isa linearisation is now stale (the effective name
        * having changed), and subclasses will then use that cache when
        * mro_package_moved calls mro_isa_changed_in. (See
        * [perl #77358].)
@@ -984,16 +992,20 @@ S_mro_gather_and_rename(pTHX_ HV * const stashes, HV * const seen_stashes,
     if(!fetched_isarev) {
        /* If oldstash is not null, then we can use its HvENAME to look up
           the isarev hash, since all its subclasses will be listed there.
+          It will always have an HvENAME. It the HvENAME was removed
+          above, then fetch_isarev will be true, and this code will not be
+          reached.
 
           If oldstash is null, then this is an empty spot with no stash in
           it, so subclasses could be listed in isarev hashes belonging to
-          any of the names, so we have to check all of them. */
-       if(oldstash) {
+          any of the names, so we have to check all of them.
+        */
+       assert(!oldstash || HvENAME(oldstash));
+       if (oldstash) {
+           /* Extra variable to avoid a compiler warning */
+           char * const hvename = HvENAME(oldstash);
            fetched_isarev = TRUE;
-           svp
-            = hv_fetch(
-                PL_isarev, HvENAME(oldstash), HvENAMELEN_get(oldstash), 0
-              );
+           svp = hv_fetch(PL_isarev, hvename, HvENAMELEN_get(oldstash), 0);
            if (svp) isarev = MUTABLE_HV(*svp);
        }
        else if(SvTYPE(namesv) == SVt_PVAV) {
@@ -1065,7 +1077,8 @@ S_mro_gather_and_rename(pTHX_ HV * const stashes, HV * const seen_stashes,
                if (!isGV(HeVAL(entry))) continue;
 
                key = hv_iterkey(entry, &len);
-               if(len > 1 && key[len-2] == ':' && key[len-1] == ':') {
+               if ((len > 1 && key[len-2] == ':' && key[len-1] == ':')
+                || (len == 1 && key[0] == ':')) {
                    HV * const oldsubstash = GvHV(HeVAL(entry));
                    SV ** const stashentry
                     = stash ? hv_fetch(stash, key, len, 0) : NULL;
@@ -1092,15 +1105,22 @@ S_mro_gather_and_rename(pTHX_ HV * const stashes, HV * const seen_stashes,
                            subname = sv_2mortal((SV *)newAV());
                            while (items--) {
                                aname = newSVsv(*svp++);
-                               sv_catpvs(aname, "::");
-                               sv_catpvn(aname, key, len-2);
+                               if (len == 1)
+                                   sv_catpvs(aname, ":");
+                               else {
+                                   sv_catpvs(aname, "::");
+                                   sv_catpvn(aname, key, len-2);
+                               }
                                av_push((AV *)subname, aname);
                            }
                        }
                        else {
                            subname = sv_2mortal(newSVsv(namesv));
-                           sv_catpvs(subname, "::");
-                           sv_catpvn(subname, key, len-2);
+                           if (len == 1) sv_catpvs(subname, ":");
+                           else {
+                               sv_catpvs(subname, "::");
+                               sv_catpvn(subname, key, len-2);
+                           }
                        }
                        mro_gather_and_rename(
                             stashes, seen_stashes,
@@ -1134,7 +1154,8 @@ S_mro_gather_and_rename(pTHX_ HV * const stashes, HV * const seen_stashes,
                if (!isGV(HeVAL(entry))) continue;
 
                key = hv_iterkey(entry, &len);
-               if(len > 1 && key[len-2] == ':' && key[len-1] == ':') {
+               if ((len > 1 && key[len-2] == ':' && key[len-1] == ':')
+                || (len == 1 && key[0] == ':')) {
                    HV *substash;
 
                    /* If this entry was seen when we iterated through the
@@ -1160,15 +1181,22 @@ S_mro_gather_and_rename(pTHX_ HV * const stashes, HV * const seen_stashes,
                            subname = sv_2mortal((SV *)newAV());
                            while (items--) {
                                aname = newSVsv(*svp++);
-                               sv_catpvs(aname, "::");
-                               sv_catpvn(aname, key, len-2);
+                               if (len == 1)
+                                   sv_catpvs(aname, ":");
+                               else {
+                                   sv_catpvs(aname, "::");
+                                   sv_catpvn(aname, key, len-2);
+                               }
                                av_push((AV *)subname, aname);
                            }
                        }
                        else {
                            subname = sv_2mortal(newSVsv(namesv));
-                           sv_catpvs(subname, "::");
-                           sv_catpvn(subname, key, len-2);
+                           if (len == 1) sv_catpvs(subname, ":");
+                           else {
+                               sv_catpvs(subname, "::");
+                               sv_catpvn(subname, key, len-2);
+                           }
                        }
                        mro_gather_and_rename(
                          stashes, seen_stashes,