summaryrefslogtreecommitdiff
path: root/op.c
diff options
context:
space:
mode:
authorFather Chrysostomos <sprout@cpan.org>2013-10-23 20:21:04 -0700
committerFather Chrysostomos <sprout@cpan.org>2013-10-23 20:21:04 -0700
commit2ec7f6f24289a5b511edf35181d0178b1e94b0f3 (patch)
tree432c4b46efdac9dd1f93ae3da73041d503df79f6 /op.c
parent4c3ed7418bcf4eae5235fb7bcae842820725bea8 (diff)
downloadperl-2ec7f6f24289a5b511edf35181d0178b1e94b0f3.tar.gz
[perl #119797] Fix if/else in lvalue sub
When if/else/unless is the last thing in an lvalue sub, the lvalue context is not always propagated properly and scope exit tries to copy things, including arrays, resulting in ‘Bizarre copy of ARRAY’. This commit fixes the bizarre copy by flagging any leave op that is part of an lvalue sub’s return sequence, using the OPpLEAVE flag added for this purpose in the previous commit. Then pp_leave uses that flag to avoid copying return values, but protects them via the mortals stack just like pp_leavesublv (actually pp_ctl.c:S_return_lvalues). For ‘if’ and ‘unless’ without ‘else’, the lvalue context was not being propagated, resulting in arrays’ getting flattened despite the lvalue context. op_lvalue_flags in op.c needed to handle AND and OR ops, which ‘if’ and ‘unless’ compile to, to make this work.
Diffstat (limited to 'op.c')
-rw-r--r--op.c11
1 files changed, 10 insertions, 1 deletions
diff --git a/op.c b/op.c
index c37f47b3db..942b4d67d5 100644
--- a/op.c
+++ b/op.c
@@ -2252,8 +2252,9 @@ Perl_op_lvalue_flags(pTHX_ OP *o, I32 type, U32 flags)
PL_modcount++;
break;
- case OP_SCOPE:
case OP_LEAVE:
+ o->op_private |= OPpLVALUE;
+ case OP_SCOPE:
case OP_ENTER:
case OP_LINESEQ:
localize = 0;
@@ -2288,6 +2289,14 @@ Perl_op_lvalue_flags(pTHX_ OP *o, I32 type, U32 flags)
case OP_COREARGS:
return o;
+
+ case OP_AND:
+ case OP_OR:
+ if (type == OP_LEAVESUBLV) {
+ op_lvalue(cLOGOPo->op_first, type);
+ op_lvalue(cLOGOPo->op_first->op_sibling, type);
+ }
+ goto nomod;
}
/* [20011101.069] File test operators interpret OPf_REF to mean that