This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
[perl #119501] \(1+2) always referencing the same sv
authorFather Chrysostomos <sprout@cpan.org>
Tue, 17 Sep 2013 15:26:12 +0000 (08:26 -0700)
committerFather Chrysostomos <sprout@cpan.org>
Tue, 17 Sep 2013 15:32:09 +0000 (08:32 -0700)
2484f8dbbb hid the fact that constant folding happens by making 1+2
fold to  a PADTMP, an SV that is never used as an lvalue and gets cop-
ied if one tries to use it that way.

The PADTMP mechanism is what allows \"$x" to return a new value each
time, even though ops like "$x" actually reuse the same scalar repeat-
edly to return values.

Because \ copies PADTMPs, \(1+2) ends up folding 1+2 to 3 (marked
PADTMP), which is then copied by the \ at compile time.  (Constant
folding works by evaluating certain ops at compile time and then
inlining their returned value.)  The result is that we have a folded
\3 where 3 is *not* marked PADTMP (the reference is, instead); hence
\(1+2) gives the same scalar each time, producing a value that can be
modified, affecting future evaluations.

The solution is to skip folding \ if its argument is a PADTMP.

op.c
t/comp/fold.t

diff --git a/op.c b/op.c
index 2008cf1..f2a575c 100644 (file)
--- a/op.c
+++ b/op.c
@@ -3347,6 +3347,11 @@ S_fold_constants(pTHX_ OP *o)
        break;
     case OP_REPEAT:
        if (o->op_private & OPpREPEAT_DOLIST) goto nope;
+       break;
+    case OP_SREFGEN:
+       if (cUNOPx(cUNOPo->op_first)->op_first->op_type != OP_CONST
+        || SvPADTMP(cSVOPx_sv(cUNOPx(cUNOPo->op_first)->op_first)))
+           goto nope;
     }
 
     if (PL_parser && PL_parser->error_count)
index 64d4d23..844ee41 100644 (file)
@@ -4,7 +4,7 @@
 # we've not yet verified that use works.
 # use strict;
 
-print "1..28\n";
+print "1..29\n";
 my $test = 0;
 
 # Historically constant folding was performed by evaluating the ops, and if
@@ -165,3 +165,9 @@ for(1+2) {
 eval { ${\"hello\n"}++ };
 print "not " unless $@ =~ "Modification of a read-only value attempted at";
 print "ok ", ++$test, " - qq with no vars is a constant\n";
+
+# [perl #119501]
+my @values;
+for (1,2) { for (\(1+3)) { push @values, $$_; $$_++ } }
+is "@values", "4 4",
+   '\1+3 folding making modification affect future retvals';