summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFather Chrysostomos <sprout@cpan.org>2018-01-19 13:47:53 -0800
committerFather Chrysostomos <sprout@cpan.org>2018-01-19 14:09:44 -0800
commitfd77b29b3be4108adb4a74b9c274599eaf228cb3 (patch)
tree07866df2d141cfba4bd6238eca517391d2a0420e
parentbcfce88b64155612fcd6af40e88805fe32c25b7f (diff)
downloadperl-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.c14
-rw-r--r--t/op/array.t33
2 files changed, 43 insertions, 4 deletions
diff --git a/pp_hot.c b/pp_hot.c
index d479ecf218..1bc453a457 100644
--- a/pp_hot.c
+++ b/pp_hot.c
@@ -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";