From d806590792484020987549ec4683b175c90d6263 Mon Sep 17 00:00:00 2001 From: Father Chrysostomos Date: Mon, 18 Apr 2011 21:29:11 -0700 Subject: [PATCH] Make keys $scalar an lvalue This does a run-time check to see whether $scalar is a hash ref, and dies if it is not. This is to keep keys \@_ consistent with keys @_. I cannot simply use OPf_MOD, since that indicates *potential* lvalue context (including subroutine args). So, instead, I take advantage of the fact that OPf_SPECIAL is always set on the LHS of an assignment (usually to indicate that local() should not erase the value). --- op.c | 1 + pp.c | 6 ++++++ t/op/smartkve.t | 8 ++++++++ 3 files changed, 15 insertions(+) diff --git a/op.c b/op.c index f22f888..e21b9a4 100644 --- a/op.c +++ b/op.c @@ -1690,6 +1690,7 @@ Perl_op_lvalue(pTHX_ OP *o, I32 type) break; case OP_KEYS: + case OP_RKEYS: if (type != OP_SASSIGN) goto nomod; goto lvalue_func; diff --git a/pp.c b/pp.c index 5b32daf..4c88270 100644 --- a/pp.c +++ b/pp.c @@ -4850,6 +4850,12 @@ PP(pp_rkeys) PL_op_desc[PL_op->op_type] ); } + if (PL_op->op_flags & OPf_SPECIAL && SvTYPE(sv) == SVt_PVAV) + DIE(aTHX_ + "Can't modify %s in %s", + PL_op_desc[PL_op->op_type], PL_op_desc[PL_op->op_next->op_type] + ); + /* Delegate to correct function for op type */ PUSHs(sv); if (PL_op->op_type == OP_RKEYS || PL_op->op_type == OP_RVALUES) { diff --git a/t/op/smartkve.t b/t/op/smartkve.t index 7c57e7b..ad56e6a 100644 --- a/t/op/smartkve.t +++ b/t/op/smartkve.t @@ -131,6 +131,14 @@ ok(defined $empty, 'Vivify: $empty (after keys $empty->{hash}) is HASHREF'); ok(!defined $empty->{hash} , 'Vivify: $empty->{hash} is undef'); +# Keys -- lvalue +$_{foo} = "bar"; +keys \%_ = 65; +is scalar %_, '1/128', 'keys $hashref as lvalue'; +eval 'keys \@_ = 65'; +like $@, qr/Can't modify keys on reference in scalar assignment/, + 'keys $arrayref as lvalue dies'; + # Keys -- errors $errpat = qr/ (?-x:Type of argument to keys on reference must be unblessed hashref or) -- 2.7.4