Don't localise array / hash slice ref assignment
authorDavid Mitchell <davem@iabyn.com>
Mon, 5 Nov 2018 12:29:27 +0000 (12:29 +0000)
committerDavid Mitchell <davem@iabyn.com>
Mon, 5 Nov 2018 12:29:27 +0000 (12:29 +0000)
RT #133538

The experimental ref assignment aliasing feature, when applied to
array or hash slices, was treating the slice as if it was always localized;
e.g.

    \(@a[3,5,7]) = \(....);

was being interpreted as

    local \(@a[3,5,7]) = \(....);

The fix is simple: check for the OPpLVAL_INTRO flag actually being set
on the op, rather than unconditionally localising the array/hash
elements.

pp.c
t/op/lvref.t

diff --git a/pp.c b/pp.c
index cfa343f..6d432ac 100644 (file)
--- a/pp.c
+++ b/pp.c
@@ -6599,10 +6599,12 @@ PP(pp_lvrefslice)
 
     while (++MARK <= SP) {
        SV * const elemsv = *MARK;
-       if (SvTYPE(av) == SVt_PVAV)
-           S_localise_aelem_lval(aTHX_ av, elemsv, can_preserve);
-       else
-           S_localise_helem_lval(aTHX_ (HV *)av, elemsv, can_preserve);
+        if (UNLIKELY(localizing)) {
+            if (SvTYPE(av) == SVt_PVAV)
+                S_localise_aelem_lval(aTHX_ av, elemsv, can_preserve);
+            else
+                S_localise_helem_lval(aTHX_ (HV *)av, elemsv, can_preserve);
+        }
        *MARK = sv_2mortal(newSV_type(SVt_PVMG));
        sv_magic(*MARK,(SV *)av,PERL_MAGIC_lvref,(char *)elemsv,HEf_SVKEY);
     }
index 28adc6a..3d5e952 100644 (file)
@@ -4,7 +4,7 @@ BEGIN {
     set_up_inc("../lib");
 }
 
-plan 156;
+plan 164;
 
 eval '\$x = \$y';
 like $@, qr/^Experimental aliasing via reference not enabled/,
@@ -603,3 +603,39 @@ pass("RT #123821");
     eval q{sub{\@0[0]=0};};
     pass("RT #128252");
 }
+
+# RT #133538 slices were inadvertently always localising
+
+{
+    use feature 'refaliasing';
+    no warnings 'experimental';
+
+    my @src = (100,200,300);
+
+    my @a = (1,2,3);
+    my %h = qw(one 10 two 20 three 30);
+
+    {
+        use feature 'declared_refs';
+        local \(@a[0,1,2]) = \(@src);
+        local \(@h{qw(one two three)}) = \(@src);
+        $src[0]++;
+        is("@a", "101 200 300", "rt #133538 \@a aliased");
+        is("$h{one} $h{two} $h{three}", "101 200 300", "rt #133538 %h aliased");
+    }
+    is("@a", "1 2 3", "rt #133538 \@a restored");
+    is("$h{one} $h{two} $h{three}", "10 20 30", "rt #133538 %h restored");
+
+    {
+        \(@a[0,1,2]) = \(@src);
+        \(@h{qw(one two three)}) = \(@src);
+        $src[0]++;
+        is("@a", "102 200 300", "rt #133538 \@a aliased try 2");
+        is("$h{one} $h{two} $h{three}", "102 200 300",
+                "rt #133538 %h aliased try 2");
+    }
+    $src[2]++;
+    is("@a", "102 200 301", "rt #133538 \@a still aliased");
+    is("$h{one} $h{two} $h{three}", "102 200 301", "rt #133538 %h still aliased");
+
+}