This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Define a PADNAMEf_TOMBSTONE for lexically deleting pad entries
authorPaul "LeoNerd" Evans <leonerd@leonerd.org.uk>
Fri, 25 Aug 2023 10:13:49 +0000 (11:13 +0100)
committerPaul Evans <leonerd@leonerd.org.uk>
Fri, 8 Sep 2023 11:48:25 +0000 (12:48 +0100)
A pad entry with this flag means that we should consider the name does
not exist. If we find that name on lookup, return NOT_IN_PAD instead.

This will be used for implementing the unexport version of lexical
imports used by `use builtin`, allowing `no builtin ...` to remove pad
entries again.

pad.c
pad.h

diff --git a/pad.c b/pad.c
index ecd4564..cbe5397 100644 (file)
--- a/pad.c
+++ b/pad.c
@@ -541,8 +541,8 @@ pad (via L<perlapi/pad_alloc>) and
 then stores a name for that entry.  C<name> is adopted and
 becomes the name entry; it must already contain the name
 string.  C<typestash> and C<ourstash> and the C<padadd_STATE>
-flag get added to C<name>.  None of the other
-processing of L<perlapi/pad_add_name_pvn>
+and C<padadd_TOMBSTONE> flags get added to C<name>.
+None of the other processing of L<perlapi/pad_add_name_pvn>
 is done.  Returns the offset of the allocated pad slot.
 
 =cut
@@ -575,6 +575,9 @@ S_pad_alloc_name(pTHX_ PADNAME *name, U32 flags, HV *typestash,
         assert(HvSTASH_IS_CLASS(PL_curstash));
         class_add_field(PL_curstash, name);
     }
+    if (flags & padadd_TOMBSTONE) {
+        PadnameFLAGS(name) |= PADNAMEf_TOMBSTONE;
+    }
 
     padnamelist_store(PL_comppad_name, offset, name);
     if (PadnameLEN(name) > 1)
@@ -600,6 +603,7 @@ flags can be OR'ed together:
  padadd_STATE        variable will retain value persistently
  padadd_NO_DUP_CHECK skip check for lexical shadowing
  padadd_FIELD        specifies that the lexical is a field for a class
+ padadd_TOMBSTONE    sets the PadnameIsTOMBSTONE flag on the new name
 
 =cut
 */
@@ -613,13 +617,13 @@ Perl_pad_add_name_pvn(pTHX_ const char *namepv, STRLEN namelen,
 
     PERL_ARGS_ASSERT_PAD_ADD_NAME_PVN;
 
-    if (flags & ~(padadd_OUR|padadd_STATE|padadd_NO_DUP_CHECK|padadd_FIELD))
+    if (flags & ~(padadd_OUR|padadd_STATE|padadd_NO_DUP_CHECK|padadd_FIELD|padadd_TOMBSTONE))
         Perl_croak(aTHX_ "panic: pad_add_name_pvn illegal flag bits 0x%" UVxf,
                    (UV)flags);
 
     name = newPADNAMEpvn(namepv, namelen);
 
-    if ((flags & padadd_NO_DUP_CHECK) == 0) {
+    if ((flags & (padadd_NO_DUP_CHECK|padadd_TOMBSTONE)) == 0) {
         ENTER;
         SAVEFREEPADNAME(name); /* in case of fatal warnings */
         /* check for duplicate declaration */
@@ -894,6 +898,7 @@ S_pad_check_dup(pTHX_ PADNAME *name, U32 flags, const HV *ourstash)
         if (pn
             && PadnameLEN(pn) == PadnameLEN(name)
             && !PadnameOUTER(pn)
+            && !PadnameIsTOMBSTONE(pn)
             && (   COP_SEQ_RANGE_LOW(pn)  == PERL_PADSEQ_INTRO
                 || COP_SEQ_RANGE_HIGH(pn) == PERL_PADSEQ_INTRO)
             && memEQ(PadnamePV(pn), PadnamePV(name), PadnameLEN(name)))
@@ -1153,6 +1158,10 @@ S_pad_findlex(pTHX_ const char *namepv, STRLEN namelen, U32 flags, const CV* cv,
                 fake_offset = 0;
                 *out_name = name_p[offset]; /* return the name */
 
+                if (PadnameIsTOMBSTONE(*out_name))
+                    /* is this a lexical import that has been deleted? */
+                    return NOT_IN_PAD;
+
                 if (PadnameIsFIELD(*out_name) && !fieldok)
                     croak("Field %" SVf " is not accessible outside a method",
                             SVfARG(PadnameSV(*out_name)));
diff --git a/pad.h b/pad.h
index 8f339ae..4b984e8 100644 (file)
--- a/pad.h
+++ b/pad.h
@@ -150,6 +150,7 @@ typedef enum {
                                             * sub, but only one level up */
 #define padadd_FIELD            0x10       /* set PADNAMEt_FIELD */
 #define padfind_FIELD_OK        0x20       /* pad_findlex is permitted to see fields */
+#define padadd_TOMBSTONE        0x40       /* set PadnameIsTOMBSTONE on the new entry */
 
 /* ASSERT_CURPAD_LEGAL and ASSERT_CURPAD_ACTIVE respectively determine
  * whether PL_comppad and PL_curpad are consistent and whether they have
@@ -266,6 +267,11 @@ Whether this is a "state" variable.
 Whether this is a "field" variable.  PADNAMEs where this is true will
 have additional information available via C<PadnameFIELDINFO>.
 
+=for apidoc m|bool|PadnameIsTOMBSTONE|PADNAME * pn
+Whether this pad entry is a tombstone.  Such an entry indicates that a
+previously-valid pad entry has now been deleted within this scope, and
+should be ignored.
+
 =for apidoc m|HV *|PadnameTYPE|PADNAME * pn
 The stash associated with a typed lexical.  This returns the C<%Foo::> hash
 for C<my Foo $bar>.
@@ -358,16 +364,18 @@ Restore the old pad saved into the local variable C<opad> by C<PAD_SAVE_LOCAL()>
 #define PadnameIsSTATE(pn)     (PadnameFLAGS(pn) & PADNAMEf_STATE)
 #define PadnameLVALUE(pn)      (PadnameFLAGS(pn) & PADNAMEf_LVALUE)
 #define PadnameIsFIELD(pn)     (PadnameFLAGS(pn) & PADNAMEf_FIELD)
-
-#define PadnameLVALUE_on(pn)   (PadnameFLAGS(pn) |= PADNAMEf_LVALUE)
-#define PadnameIsSTATE_on(pn)  (PadnameFLAGS(pn) |= PADNAMEf_STATE)
-
-#define PADNAMEf_OUTER 0x01    /* outer lexical var */
-#define PADNAMEf_STATE 0x02    /* state var */
-#define PADNAMEf_LVALUE        0x04    /* used as lvalue */
-#define PADNAMEf_TYPED 0x08    /* for B; unused by core */
-#define PADNAMEf_OUR   0x10    /* for B; unused by core */
-#define PADNAMEf_FIELD  0x20    /* field var */
+#define PadnameIsTOMBSTONE(pn)  (PadnameFLAGS(pn) & PADNAMEf_TOMBSTONE)
+
+#define PadnameLVALUE_on(pn)    (PadnameFLAGS(pn) |= PADNAMEf_LVALUE)
+#define PadnameIsSTATE_on(pn)   (PadnameFLAGS(pn) |= PADNAMEf_STATE)
+
+#define PADNAMEf_OUTER      0x01    /* outer lexical var */
+#define PADNAMEf_STATE      0x02    /* state var */
+#define PADNAMEf_LVALUE     0x04    /* used as lvalue */
+#define PADNAMEf_TYPED      0x08    /* for B; unused by core */
+#define PADNAMEf_OUR        0x10    /* for B; unused by core */
+#define PADNAMEf_FIELD      0x20    /* field var */
+#define PADNAMEf_TOMBSTONE  0x40    /* padname has been deleted */
 
 /* backward compatibility */
 #ifndef PERL_CORE