This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Make ++ handle regexps and vstrings
authorFather Chrysostomos <sprout@cpan.org>
Sat, 10 Aug 2013 17:38:08 +0000 (10:38 -0700)
committerFather Chrysostomos <sprout@cpan.org>
Sun, 11 Aug 2013 17:53:34 +0000 (10:53 -0700)
$ ./perl -Ilib -e 'use Devel::Peek; $x = v97; ++$x; Dump $x'
SV = PVMG(0x7fbfa402b698) at 0x7fbfa402eed8
  REFCNT = 1
  FLAGS = (RMG,POK,pPOK)
  IV = 0
  NV = 0
  PV = 0x7fbfa3c066a8 "b"\0
  CUR = 1
  LEN = 24
  MAGIC = 0x7fbfa3c06348
    MG_VIRTUAL = 0
    MG_TYPE = PERL_MAGIC_vstring(V)
    MG_LEN = 3
    MG_PTR = 0x7fbfa3c13ee8 "v97"

The vstring magic is still attached (with something that does not
match the contents of the string), even after modifying it.  I
probably broke that in 5.18 after fixing it in 5.16, but I am too
lazy to check.

$ ./perl -le '$x = ${qr//}; $x++; print "$x"'
Assertion failed: (PL_valid_types_IVX[SvTYPE(_svivx) & SVt_MASK]), function Perl_sv_2pv_flags, file sv.c, line 2908.
Abort trap: 6

That I broke when I stopped regexps from being POK in perl 5.18.0.

It was creating a corrupt SV by setting the IOK flag on something of
type SVt_REGEXP.

sv.c
t/op/inc.t

diff --git a/sv.c b/sv.c
index c71c0f1..9ea3182 100644 (file)
--- a/sv.c
+++ b/sv.c
@@ -8268,8 +8268,6 @@ Perl_sv_inc_nomg(pTHX_ SV *const sv)
     if (!sv)
        return;
     if (SvTHINKFIRST(sv)) {
-       if (SvIsCOW(sv) || isGV_with_GP(sv))
-           sv_force_normal_flags(sv, 0);
        if (SvREADONLY(sv)) {
                Perl_croak_no_modify();
        }
@@ -8281,6 +8279,7 @@ Perl_sv_inc_nomg(pTHX_ SV *const sv)
            sv_unref(sv);
            sv_setiv(sv, i);
        }
+       else sv_force_normal_flags(sv, 0);
     }
     flags = SvFLAGS(sv);
     if ((flags & (SVp_NOK|SVp_IOK)) == SVp_NOK) {
index 2475b5e..8db0660 100644 (file)
@@ -274,5 +274,12 @@ isnt(scalar eval { my $pvbm = PVBM; --$pvbm }, undef, "predecrement defined");
 $_ = ${qr //};
 $_--;
 is($_, -1, 'regexp--');
+$_ = ${qr //};
+$_++;
+is($_, 1, 'regexp++');
+
+$_ = v97;
+$_++;
+isnt(ref\$_, 'VSTRING', '++ flattens vstrings');
 
 done_testing();