On Mon Apr 13 18:56:12 2020, TEAM wrote:
Show quoted text> $ perl -le'use Object::Pad; class Parent { has $thing = 2; } package
> Child; Object::Pad->import_into("Child"); eval "package Child; class
> Child extends Parent;"; has $other = 3; method other { return $other }
> print Child->new->other'
A number of issues here in both Object::Pad and your example.
First problem is that the ->import_into and eval only happen at runtime, which is too late to influence the `has` and `method`. But due to a bug in the way compclassmeta is implemented the previous one from Parent has leaked out; so that is actually the one still in effect there.
With that bug fixed (see attached patch), the mistake in the example becomes clear:
$ cat rt132337.pl
#!/usr/bin/perl
use Object::Pad;
class Parent { has $thing = 2; }
package Child;
Object::Pad->import_into("Child");
eval "package Child; class Child extends Parent;";
has $other = 3;
method other { return $other }
print Child->new->other
$ perl -Mblib rt132337.pl
Cannot 'has' outside of 'class' at rt132337.pl line 10.
Could now fix that by BEGIN-wrapping these two lines, but currently that makes no difference. I suspect a better fix is to arrange for compclassmeta to be restored at "end of block" time in the open ("class Foo;") case, rather than rely on the save stack which would get unwound at the end of the BEGIN block.
--
Paul Evans
=== modified file 'lib/Object/Pad.xs'
--- old/lib/Object/Pad.xs 2020-04-12 12:53:01 +0000
+++ new/lib/Object/Pad.xs 2020-04-14 16:32:07 +0000
@@ -154,10 +154,30 @@
/* The metadata on the currently-compiling class */
#ifdef MULTIPLICITY
-# define compclassmeta \
- (*((ClassMeta **)hv_fetchs(PL_modglobal, "Object::Pad/compclassmeta", GV_ADD)))
-# define have_compclassmeta \
- (!!hv_fetchs(PL_modglobal, "Object::Pad/compclassmeta", 0))
+# define compclassmeta (*S_compclassmetaptr(aTHX))
+static ClassMeta **S_compclassmetaptr(pTHX)
+{
+ SV *sv = *hv_fetchs(PL_modglobal, "Object::Pad/compclassmeta", GV_ADD);
+ if(!SvOK(sv))
+ sv_setiv(sv, 0);
+ /* Abuse the IV field as a struct pointer; we know it should be OK because
+ * IV has to be big enough to store a pointer */
+ void *ivptr = &(SvIVX(sv));
+ return ivptr;
+}
+
+# define have_compclassmeta S_have_compclassmeta(aTHX)
+static bool S_have_compclassmeta(pTHX)
+{
+ SV **svp = hv_fetchs(PL_modglobal, "Object::Pad/compclassmeta", 0);
+ if(!svp || !*svp)
+ return false;
+
+ if(SvOK(*svp) && SvIV(*svp))
+ return true;
+
+ return false;
+}
#else
/* without MULTIPLICITY there's only one, so we might as well just store it
* in a static
@@ -771,9 +791,7 @@
import_pragma("experimental", "signatures");
#endif
- if(have_compclassmeta) {
- SAVEVPTR(compclassmeta);
- }
+ SAVEVPTR(compclassmeta);
ClassMeta *meta;
Newx(meta, 1, ClassMeta);