summaryrefslogtreecommitdiff
path: root/pp_hot.c
diff options
context:
space:
mode:
authorFather Chrysostomos <sprout@cpan.org>2014-09-29 22:21:21 -0700
committerFather Chrysostomos <sprout@cpan.org>2014-10-11 00:10:13 -0700
commitbdaf10a52f7152c8c7cb0a106489016892f093cd (patch)
tree7d5e9e54d99d5417965667ffac4a871e9f2db92b /pp_hot.c
parent4cb217963bb5dd7a847ee100592f6abd696c1f41 (diff)
downloadperl-bdaf10a52f7152c8c7cb0a106489016892f093cd.tar.gz
Assignment to \(@array)
This is a slurpy lvalue that gobbles up all the rhs elements, which are expected to be references. So \(@a)=\(@b) makes @a share the same elements as @b. We implement this by pushing a null on to the stack as a special marker that pp_aassign will recognise. I decided to change the wording for the \local(@a)=... error slightly, from what my to-do tests had. Some of the other to-do tests were badly written and had to be fixed up a bit.
Diffstat (limited to 'pp_hot.c')
-rw-r--r--pp_hot.c31
1 files changed, 27 insertions, 4 deletions
diff --git a/pp_hot.c b/pp_hot.c
index 1d67379b13..84e934e47a 100644
--- a/pp_hot.c
+++ b/pp_hot.c
@@ -886,6 +886,7 @@ PP(pp_print)
/* also used for: pp_rv2hv() */
+/* also called directly by pp_lvavref */
PP(pp_rv2av)
{
@@ -893,7 +894,8 @@ PP(pp_rv2av)
const I32 gimme = GIMME_V;
static const char an_array[] = "an ARRAY";
static const char a_hash[] = "a HASH";
- const bool is_pp_rv2av = PL_op->op_type == OP_RV2AV;
+ const bool is_pp_rv2av = PL_op->op_type == OP_RV2AV
+ || PL_op->op_type == OP_LVAVREF;
const svtype type = is_pp_rv2av ? SVt_PVAV : SVt_PVHV;
SvGETMAGIC(sv);
@@ -1071,8 +1073,14 @@ PP(pp_aassign)
hash = NULL;
while (LIKELY(lelem <= lastlelem)) {
+ bool alias = FALSE;
TAINT_NOT; /* Each item stands on its own, taintwise. */
sv = *lelem++;
+ if (UNLIKELY(!sv)) {
+ alias = TRUE;
+ sv = *lelem++;
+ ASSUME(SvTYPE(sv) == SVt_PVAV);
+ }
switch (SvTYPE(sv)) {
case SVt_PVAV:
ary = MUTABLE_AV(sv);
@@ -1086,9 +1094,24 @@ PP(pp_aassign)
SV **didstore;
if (LIKELY(*relem))
SvGETMAGIC(*relem); /* before newSV, in case it dies */
- sv = newSV(0);
- sv_setsv_nomg(sv, *relem);
- *(relem++) = sv;
+ if (LIKELY(!alias)) {
+ sv = newSV(0);
+ sv_setsv_nomg(sv, *relem);
+ *relem = sv;
+ }
+ else {
+ if (!SvROK(*relem))
+ DIE(aTHX_ "Assigned value is not a reference");
+ if (SvTYPE(SvRV(*relem)) > SVt_PVLV)
+ /* diag_listed_as: Assigned value is not %s reference */
+ DIE(aTHX_
+ "Assigned value is not a SCALAR reference");
+ if (lval)
+ *relem = sv_mortalcopy(*relem);
+ /* XXX else check for weak refs? */
+ sv = SvREFCNT_inc_simple_NN(SvRV(*relem));
+ }
+ relem++;
didstore = av_store(ary,i++,sv);
if (magic) {
if (!didstore)