This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
[perl #19078] wrong match order inside replacement
authorFather Chrysostomos <sprout@cpan.org>
Tue, 21 Sep 2010 04:24:02 +0000 (21:24 -0700)
committerFather Chrysostomos <sprout@cpan.org>
Tue, 21 Sep 2010 04:24:02 +0000 (21:24 -0700)
$ perl -le '$_="CCCGGG"; s!.!@a{print("[$&]"),/./}!g'
[C]
[C]
[C]
[C]
[C]
[C]

What’s happening is that the s/// does not reset PL_curpm for each
iteration, because it doesn’t usually have to.

The RHS’s scoping takes care of it most of the time. This happens with
the /e modifier and with @{...}.

In this example, though, we have a subscript, not a block. This sub-
script is in the same scope as the s/// itself.

The assumption that the substitution operator will never have to reset
PL_curpm itself appears to be incorrect. This fixes it.

pp_ctl.c
t/re/subst.t

index 099d2ae..0a9dcfe 100644 (file)
--- a/pp_ctl.c
+++ b/pp_ctl.c
@@ -377,6 +377,7 @@ PP(pp_substcont)
        (void)ReREFCNT_inc(rx);
     cx->sb_rxtainted |= RX_MATCH_TAINTED(rx);
     rxres_save(&cx->sb_rxres, rx);
+    PL_curpm = pm;
     RETURNOP(pm->op_pmstashstartu.op_pmreplstart);
 }
 
index 91c757a..9b5fd61 100644 (file)
@@ -7,7 +7,7 @@ BEGIN {
 }
 
 require './test.pl';
-plan( tests => 170 );
+plan( tests => 172 );
 
 # Stolen from re/ReTest.pl. Can't just use the file since it doesn't support
 # like() and it conflicts with test.pl
@@ -724,3 +724,25 @@ fresh_perl_is( '$_="abcef"; s/bc|(.)\G(.)/$1 ? "[$1-$2]" : "XX"/ge; print' => 'a
     $string =~ s/./\777/;
     is($string, chr 0x1FF, "Verify that handles s/foo/\\777/");
 }
+
+# Scoping of s//the RHS/ when there is no /e
+# Tests based on [perl #19078]
+{
+ local *_;
+ my $output = ''; my %a;
+ no warnings 'uninitialized';
+
+ $_="CCCGGG";
+ s!.!<@a{$output .= ("$&"),/[$&]/g}>!g;
+ $output .= $_;
+ is(
+   $output, "CCCGGG<   ><  >< ><   ><  >< >",
+  's/// sets PL_curpm for each iteration even when the RHS has set it'
+ );
+ s/C/$a{m\G\}/;
+ is(
+  "$&", G =>
+  'Match vars reflect the last match after s/pat/$a{m|pat|}/ without /e'
+ );
+}