From 38a3df78b8fbbdf02988dd5fe691c23a8041334f Mon Sep 17 00:00:00 2001 From: Zefram Date: Wed, 6 Dec 2017 00:50:05 +0000 Subject: 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]. --- op.c | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) (limited to 'op.c') 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) -- cgit v1.2.1