This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Common vars check should account for OPpTARGET_MY
authorFather Chrysostomos <sprout@cpan.org>
Sat, 18 Oct 2014 23:37:41 +0000 (16:37 -0700)
committerFather Chrysostomos <sprout@cpan.org>
Sun, 19 Oct 2014 00:06:52 +0000 (17:06 -0700)
When checking for common vars on either side of a list assignment (to
see whether we need to make temporary copies), we need to account for
the OPpTARGET_MY optimisation which transforms ‘$lex = $foo . $bar’
into a simple ‘$foo . $bar’ that writes directly to $lex instead of
writing to a scratch variable and returning that.

This was printing foofoo instead of foobar:

$ ./perl -Ilib -le 'my ($a,$b); $foo="foo"; $bar="bar"; ($a,$b) = ($b=$foo."", $a=$bar.""); print $a,$b'

op.c
t/op/list.t

diff --git a/op.c b/op.c
index e142bec..2dcb389 100644 (file)
--- a/op.c
+++ b/op.c
@@ -5970,6 +5970,9 @@ S_aassign_common_vars(pTHX_ OP* o)
            else
                return TRUE;
        }
+       else if (PL_opargs[curop->op_type] & OA_TARGLEX
+             && curop->op_private & OPpTARGET_MY)
+           goto padcheck;
 
        if (curop->op_flags & OPf_KIDS) {
            if (aassign_common_vars(curop))
@@ -5991,7 +5994,9 @@ S_aassign_common_vars_aliases_only(pTHX_ OP *o)
             curop->op_type == OP_PADAV ||
             curop->op_type == OP_PADHV ||
             curop->op_type == OP_AELEMFAST_LEX ||
-            curop->op_type == OP_PADANY)
+            curop->op_type == OP_PADANY ||
+            (  PL_opargs[curop->op_type] & OA_TARGLEX
+            && curop->op_private & OPpTARGET_MY  ))
           && PAD_COMPNAME_GEN(curop->op_targ) == PERL_INT_MAX)
            return TRUE;
 
index 3f42e6d..2802e62 100644 (file)
@@ -6,7 +6,7 @@ BEGIN {
 }
 
 require "./test.pl";
-plan( tests => 65 );
+plan( tests => 66 );
 
 @foo = (1, 2, 3, 4);
 cmp_ok($foo[0], '==', 1, 'first elem');
@@ -194,3 +194,12 @@ sub {
 # [perl #122995] Hang when compiling while(1) in a sub-list
 # No ok() or is() necessary.
 sub foo { () = ($a, my $b, ($c, do { while(1) {} })) }
+
+# List assignment and OPpTARGET_MY
+{
+    my ($a,$b);
+    my $foo = "foo";
+    my $bar = "bar";
+    ($a,$b) = ($b = $foo."", $a = $bar . "");
+    is("$a,$b", "foo,bar", 'common vars check accounts for OPpTARGET_MY');
+}