diff options
author | Father Chrysostomos <sprout@cpan.org> | 2018-01-19 13:47:53 -0800 |
---|---|---|
committer | Father Chrysostomos <sprout@cpan.org> | 2018-01-19 14:09:44 -0800 |
commit | fd77b29b3be4108adb4a74b9c274599eaf228cb3 (patch) | |
tree | 07866df2d141cfba4bd6238eca517391d2a0420e | |
parent | bcfce88b64155612fcd6af40e88805fe32c25b7f (diff) | |
download | perl-fd77b29b3be4108adb4a74b9c274599eaf228cb3.tar.gz |
Don’t vivify elems when putting array on stack
6661956a2 was a little too powerful, and, in addition to fixing the
bug that @_ did not properly alias nonexistent elements, also broke
other uses of nonexistent array elements. (See the tests added.)
This commit changes it so that putting @a on the stack does not vivify
all ‘holes’ in @a, but creates defelem (deferred element) scalars, but
only in lvalue context.
-rw-r--r-- | pp_hot.c | 14 | ||||
-rw-r--r-- | t/op/array.t | 33 |
2 files changed, 43 insertions, 4 deletions
@@ -1163,8 +1163,12 @@ S_pushav(pTHX_ AV* const av) if (UNLIKELY(SvRMAGICAL(av))) { PADOFFSET i; for (i=0; i < (PADOFFSET)maxarg; i++) { - SV ** const svp = av_fetch(av, i, TRUE); - SP[i+1] = svp ? *svp : &PL_sv_undef; + SV ** const svp = av_fetch(av, i, FALSE); + SP[i+1] = LIKELY(svp) + ? *svp + : UNLIKELY(PL_op->op_flags & OPf_MOD) + ? newSVavdefelem(av,i,1) + : &PL_sv_undef; } } else { @@ -1173,7 +1177,11 @@ S_pushav(pTHX_ AV* const av) SV *sv = AvARRAY(av)[i]; if (!LIKELY(sv)) AvARRAY(av)[i] = sv = newSV(0); - SP[i+1] = sv; + SP[i+1] = LIKELY(sv) + ? sv + : UNLIKELY(PL_op->op_flags & OPf_MOD) + ? newSVavdefelem(av,i,1) + : &PL_sv_undef; } } SP += maxarg; diff --git a/t/op/array.t b/t/op/array.t index 3d9b9d7900..9d0bfad4ef 100644 --- a/t/op/array.t +++ b/t/op/array.t @@ -6,7 +6,7 @@ BEGIN { set_up_inc('.', '../lib'); } -plan (179); +plan (185); # # @foo, @bar, and @ary are also used from tie-stdarray after tie-ing them @@ -595,4 +595,35 @@ $#a = -1; $#a++; is join("", @r), "55", "lazy element creation with foreach"; } +{ # Some things broken by the initial fix for #8910 + (\my @a)->$#*++; + my @b = @a; + ok !exists $a[0], 'copying an array via = does not vivify elements'; + delete $a[0]; + @a[1..5] = 1..5; + $#a++; + my $count; + my @existing_elements = map { exists $a[$count++] ? $_ : () } @a; + is join(",", @existing_elements), "1,2,3,4,5", + 'map {} @a does not vivify elements'; + $#a = -1; + {local $a[3] = 12; my @foo=@a}; + is @a, 0,'unwinding localization of elem past end of array shrinks it'; + + # Again, but with a package array + package tmp; (\our @a)->$#*++; package main; + my @b = @a; + ok !exists $a[0], 'copying an array via = does not vivify elements'; + delete $a[0]; + @a[1..5] = 1..5; + $#a++; + my $count; + my @existing_elements = map { exists $a[$count++] ? $_ : () } @a; + is join(",", @existing_elements), "1,2,3,4,5", + 'map {} @a does not vivify elements'; + $#a = -1; + {local $a[3] = 12; my @foo=@a}; + is @a, 0, 'unwinding localization of elem past end of array shrinks it' +} + "We're included by lib/Tie/Array/std.t so we need to return something true"; |