summaryrefslogtreecommitdiff
path: root/op.c
diff options
context:
space:
mode:
authorZefram <zefram@fysh.org>2017-12-06 00:50:05 +0000
committerZefram <zefram@fysh.org>2017-12-06 00:50:05 +0000
commit38a3df78b8fbbdf02988dd5fe691c23a8041334f (patch)
tree5044e75299a6b4f22641a0acff5d8bd6157bbb08 /op.c
parent557714184de18964b954b2c00fa13127fd3f216a (diff)
downloadperl-38a3df78b8fbbdf02988dd5fe691c23a8041334f.tar.gz
don't mistake tr/// for assignable reference
For the lhs of an assignment to be an assignable srefgen, the srefgen must be its top-level op. ck_refassign() asserted that, but S_assignment_type() was delving inside a null op looking for the srefgen, the same way it looks for things that distinguish between scalar and list assignment. This showed up in a weird situation where a no-op transliteration could be applied to an srefgen, getting an srefgen inside a null op. Fixes [perl #130578].
Diffstat (limited to 'op.c')
-rw-r--r--op.c34
1 files changed, 17 insertions, 17 deletions
diff --git a/op.c b/op.c
index 072d3ceb53..a27e4b14db 100644
--- a/op.c
+++ b/op.c
@@ -7579,11 +7579,24 @@ S_assignment_type(pTHX_ const OP *o)
if (!o)
return TRUE;
- if ((o->op_type == OP_NULL) && (o->op_flags & OPf_KIDS))
- o = cUNOPo->op_first;
+ if (o->op_type == OP_SREFGEN)
+ {
+ OP * const kid = cUNOPx(cUNOPo->op_first)->op_first;
+ type = kid->op_type;
+ flags = o->op_flags | kid->op_flags;
+ if (!(flags & OPf_PARENS)
+ && (kid->op_type == OP_RV2AV || kid->op_type == OP_PADAV ||
+ kid->op_type == OP_RV2HV || kid->op_type == OP_PADHV ))
+ return ASSIGN_REF;
+ ret = ASSIGN_REF;
+ } else {
+ if ((o->op_type == OP_NULL) && (o->op_flags & OPf_KIDS))
+ o = cUNOPo->op_first;
+ flags = o->op_flags;
+ type = o->op_type;
+ ret = 0;
+ }
- flags = o->op_flags;
- type = o->op_type;
if (type == OP_COND_EXPR) {
OP * const sib = OpSIBLING(cLOGOPo->op_first);
const I32 t = assignment_type(sib);
@@ -7596,19 +7609,6 @@ S_assignment_type(pTHX_ const OP *o)
return FALSE;
}
- if (type == OP_SREFGEN)
- {
- OP * const kid = cUNOPx(cUNOPo->op_first)->op_first;
- type = kid->op_type;
- flags |= kid->op_flags;
- if (!(flags & OPf_PARENS)
- && (kid->op_type == OP_RV2AV || kid->op_type == OP_PADAV ||
- kid->op_type == OP_RV2HV || kid->op_type == OP_PADHV ))
- return ASSIGN_REF;
- ret = ASSIGN_REF;
- }
- else ret = 0;
-
if (type == OP_LIST &&
(flags & OPf_WANT) == OPf_WANT_SCALAR &&
o->op_private & OPpLVAL_INTRO)