diff options
author | Zefram <zefram@fysh.org> | 2017-12-06 00:50:05 +0000 |
---|---|---|
committer | Zefram <zefram@fysh.org> | 2017-12-06 00:50:05 +0000 |
commit | 38a3df78b8fbbdf02988dd5fe691c23a8041334f (patch) | |
tree | 5044e75299a6b4f22641a0acff5d8bd6157bbb08 /op.c | |
parent | 557714184de18964b954b2c00fa13127fd3f216a (diff) | |
download | perl-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.c | 34 |
1 files changed, 17 insertions, 17 deletions
@@ -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) |