summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarty Pauley <marty@martian.org>2010-10-24 18:02:40 +0900
committerFather Chrysostomos <sprout@cpan.org>2010-11-04 00:33:47 -0700
commit91e34d82e7dd2f0ba610299faa1af2efc8b404dc (patch)
tree6a53af64d2795a2a4ac46420bcc80b85fa1bdc39
parent8897dcaad14089c32e969309beb16112ec768eaf (diff)
downloadperl-91e34d82e7dd2f0ba610299faa1af2efc8b404dc.tar.gz
fix for #23790.
padav is leaving an arrayref on the stack when producing the return value for an lvalue sub. But when this is in an argument list it really should be a array, not a ref. So, in leavesublv I check for this case and expand the arrayref to an array.
-rw-r--r--pp_hot.c23
-rw-r--r--t/op/sub_lval.t12
2 files changed, 32 insertions, 3 deletions
diff --git a/pp_hot.c b/pp_hot.c
index 9beb604ea6..8c9c915ec5 100644
--- a/pp_hot.c
+++ b/pp_hot.c
@@ -2595,6 +2595,29 @@ PP(pp_leavesublv)
if (gimme == G_SCALAR)
goto temporise;
if (gimme == G_ARRAY) {
+ mark = newsp + 1;
+ /* We want an array here, but padav will have left us an arrayref for an lvalue,
+ * so we need to expand it */
+ if(SvTYPE(*mark) == SVt_PVAV) {
+ AV *const av = MUTABLE_AV(*mark);
+ const I32 maxarg = AvFILL(av) + 1;
+ (void)POPs; /* get rid of the array ref */
+ EXTEND(SP, maxarg);
+ if (SvRMAGICAL(av)) {
+ U32 i;
+ for (i=0; i < (U32)maxarg; i++) {
+ SV ** const svp = av_fetch(av, i, FALSE);
+ SP[i+1] = svp
+ ? SvGMAGICAL(*svp) ? (mg_get(*svp), *svp) : *svp
+ : &PL_sv_undef;
+ }
+ }
+ else {
+ Copy(AvARRAY(av), SP+1, maxarg, SV*);
+ }
+ SP += maxarg;
+ PUTBACK;
+ }
if (!CvLVALUE(cx->blk_sub.cv))
goto temporise_array;
EXTEND_MORTAL(SP - newsp);
diff --git a/t/op/sub_lval.t b/t/op/sub_lval.t
index aedaba05d1..d0ba84a043 100644
--- a/t/op/sub_lval.t
+++ b/t/op/sub_lval.t
@@ -3,7 +3,7 @@ BEGIN {
@INC = '../lib';
require './test.pl';
}
-plan tests=>74;
+plan tests=>76;
sub a : lvalue { my $a = 34; ${\(bless \$a)} } # Return a temporary
sub b : lvalue { ${\shift} }
@@ -527,8 +527,7 @@ TODO: {
is($blah, 8, "yada");
}
-TODO: {
- local $TODO = "bug #23790";
+{ # bug #23790
my @arr = qw /one two three/;
my $line = "zero";
sub lval_array () : lvalue {@arr}
@@ -538,6 +537,13 @@ TODO: {
}
is($line, "zeroonetwothree");
+
+ sub trythislval { scalar(@_)."x".join "", @_ }
+ is(trythislval(lval_array()), "3xonetwothree");
+
+ sub changeme { $_[2] = "free" }
+ changeme(lval_array);
+ is("@arr", "one two free");
}
{