/*
=for apidoc gv_try_downgrade
-If C<gv> is a typeglob containing only a constant sub, and is only
-referenced from its package, and both the typeglob and the sub are
-sufficiently ordinary, replace the typeglob (in the package) with a
-placeholder that more compactly represents the same thing. This is meant
-to be used when a placeholder has been upgraded, most likely because
-something wanted to look at a proper code object, and it has turned out
-to be a constant sub to which a proper reference is no longer required.
+If the typeglob C<gv> can be expressed more succinctly, by having
+something other than a real GV in its place in the stash, replace it
+with the optimised form. Basic requirements for this are that C<gv>
+is a real typeglob, is sufficiently ordinary, and is only referenced
+from its package. This function is meant to be used when a GV has been
+looked up in part to see what was there, causing upgrading, but based
+on what was found it turns out that the real GV isn't required after all.
+
+If C<gv> is a completely empty typeglob, it is deleted from the stash.
+
+If C<gv> is a typeglob containing only a sufficiently-ordinary constant
+sub, the typeglob is replaced with a scalar-reference placeholder that
+more compactly represents the same thing.
=cut
*/
HEK *namehek;
SV **gvp;
PERL_ARGS_ASSERT_GV_TRY_DOWNGRADE;
- if (SvREFCNT(gv) == 1 && SvTYPE(gv) == SVt_PVGV && !SvFAKE(gv) &&
+ if (!(SvREFCNT(gv) == 1 && SvTYPE(gv) == SVt_PVGV && !SvFAKE(gv) &&
!SvOBJECT(gv) && !SvMAGICAL(gv) && !SvREADONLY(gv) &&
isGV_with_GP(gv) && GvGP(gv) &&
- GvMULTI(gv) && !GvINTRO(gv) && GvREFCNT(gv) == 1 &&
+ !GvINTRO(gv) && GvREFCNT(gv) == 1 &&
!GvSV(gv) && !GvAV(gv) && !GvHV(gv) && !GvIOp(gv) && !GvFORM(gv) &&
- GvEGV(gv) == gv && (stash = GvSTASH(gv)) && (cv = GvCV(gv)) &&
+ GvEGV(gv) == gv && (stash = GvSTASH(gv))))
+ return;
+ cv = GvCV(gv);
+ if (!cv) {
+ HEK *gvnhek = GvNAME_HEK(gv);
+ (void)hv_delete(stash, HEK_KEY(gvnhek),
+ HEK_UTF8(gvnhek) ? -HEK_LEN(gvnhek) : HEK_LEN(gvnhek), G_DISCARD);
+ } else if (GvMULTI(gv) && cv &&
!SvOBJECT(cv) && !SvMAGICAL(cv) && !SvREADONLY(cv) &&
CvSTASH(cv) == stash && CvGV(cv) == gv &&
CvCONST(cv) && !CvMETHOD(cv) && !CvLVALUE(cv) && !CvUNIQUE(cv) &&
use warnings;
require './test.pl';
-plan( tests => 182 );
+plan( tests => 188 );
# type coersion on assignment
$foo = 'foo';
);
}
+# [perl #72740] - indirect object syntax, heuristically imputed due to
+# the non-existence of a function, should not cause a stash entry to be
+# created for the non-existent function.
+{
+ package RT72740a;
+ my $f = bless({}, RT72740b);
+ sub s1 { s2 $f; }
+ our $s4;
+ sub s3 { s4 $f; }
+}
+{
+ package RT72740b;
+ sub s2 { "RT72740b::s2" }
+ sub s4 { "RT72740b::s4" }
+}
+ok(exists($RT72740a::{s1}), "RT72740a::s1 exists");
+ok(!exists($RT72740a::{s2}), "RT72740a::s2 does not exist");
+ok(exists($RT72740a::{s3}), "RT72740a::s3 exists");
+ok(exists($RT72740a::{s4}), "RT72740a::s4 exists");
+is(RT72740a::s1(), "RT72740b::s2", "RT72740::s1 parsed correctly");
+is(RT72740a::s3(), "RT72740b::s4", "RT72740::s3 parsed correctly");
+
__END__
Perl
Rules