summaryrefslogtreecommitdiff
path: root/pp_hot.c
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 /pp_hot.c
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.
Diffstat (limited to 'pp_hot.c')
-rw-r--r--pp_hot.c23
1 files changed, 23 insertions, 0 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);