}
use OptreeCheck;
use Config;
-plan tests => 8;
+plan tests => 12;
SKIP: {
skip "no perlio in this build", 4 unless $Config::Config{useperlio};
# 9 <$> gv(*b) s ->a
EONT_EONT
+checkOptree ( name => 'padrange',
+ code => sub { my ($x,$y); @a = ($x,$y); ($x,$y) = @a },
+ strip_open_hints => 1,
+ skip => ($] < 5.017006),
+ expect => <<'EOT_EOT', expect_nt => <<'EONT_EONT');
+# f <1> leavesub[1 ref] K/REFC,1 ->(end)
+# - <@> lineseq KP ->f
+# 1 <;> nextstate(main 1 -e:1) v ->2
+# - <@> list vKP ->3
+# 2 <0> padrange[$x:1,2; $y:1,2] vM/LVINTRO,2 ->3
+# - <0> padsv[$x:1,2] vM/LVINTRO ->-
+# - <0> padsv[$y:1,2] vM/LVINTRO ->-
+# 3 <;> nextstate(main 2 -e:1) v ->4
+# 8 <2> aassign[t4] vKS ->9
+# - <1> ex-list lKP ->5
+# 4 <0> padrange[$x:1,2; $y:1,2] l/2 ->5
+# - <0> padsv[$x:1,2] l ->-
+# - <0> padsv[$y:1,2] l ->-
+# - <1> ex-list lK ->8
+# 5 <0> pushmark s ->6
+# 7 <1> rv2av[t3] lKRM*/1 ->8
+# 6 <#> gv[*a] s ->7
+# 9 <;> nextstate(main 2 -e:1) v:{ ->a
+# e <2> aassign[t6] KS ->f
+# - <1> ex-list lK ->d
+# a <0> pushmark s ->b
+# c <1> rv2av[t5] lK/1 ->d
+# b <#> gv[*a] s ->c
+# - <1> ex-list lKPRM* ->e
+# d <0> padrange[$x:1,2; $y:1,2] lRM/2 ->e
+# - <0> padsv[$x:1,2] lRM* ->-
+# - <0> padsv[$y:1,2] lRM* ->-
+EOT_EOT
+# f <1> leavesub[1 ref] K/REFC,1 ->(end)
+# - <@> lineseq KP ->f
+# 1 <;> nextstate(main 1 -e:1) v ->2
+# - <@> list vKP ->3
+# 2 <0> padrange[$x:1,2; $y:1,2] vM/LVINTRO,2 ->3
+# - <0> padsv[$x:1,2] vM/LVINTRO ->-
+# - <0> padsv[$y:1,2] vM/LVINTRO ->-
+# 3 <;> nextstate(main 2 -e:1) v ->4
+# 8 <2> aassign[t4] vKS ->9
+# - <1> ex-list lKP ->5
+# 4 <0> padrange[$x:1,2; $y:1,2] l/2 ->5
+# - <0> padsv[$x:1,2] l ->-
+# - <0> padsv[$y:1,2] l ->-
+# - <1> ex-list lK ->8
+# 5 <0> pushmark s ->6
+# 7 <1> rv2av[t3] lKRM*/1 ->8
+# 6 <$> gv(*a) s ->7
+# 9 <;> nextstate(main 2 -e:1) v:{ ->a
+# e <2> aassign[t6] KS ->f
+# - <1> ex-list lK ->d
+# a <0> pushmark s ->b
+# c <1> rv2av[t5] lK/1 ->d
+# b <$> gv(*a) s ->c
+# - <1> ex-list lKPRM* ->e
+# d <0> padrange[$x:1,2; $y:1,2] lRM/2 ->e
+# - <0> padsv[$x:1,2] lRM* ->-
+# - <0> padsv[$y:1,2] lRM* ->-
+EONT_EONT
+
+checkOptree ( name => 'padrange and @_',
+ code => sub { my ($a,$b) = @_;
+ my ($c,$d) = @X::_;
+ package Y;
+ my ($e,$f) = @_;
+ },
+ strip_open_hints => 1,
+ skip => ($] < 5.017006),
+ expect => <<'EOT_EOT', expect_nt => <<'EONT_EONT');
+# d <1> leavesub[1 ref] K/REFC,1 ->(end)
+# - <@> lineseq KP ->d
+# 1 <;> nextstate(main 1 p3:1) v ->2
+# 3 <2> aassign[t5] vKS ->4
+# - <1> ex-list lK ->-
+# 2 <0> padrange[$a:1,4; $b:1,4] l*/LVINTRO,2 ->3
+# - <1> rv2av[t4] lK/1 ->-
+# - <#> gv[*_] s ->-
+# - <1> ex-list lKPRM* ->3
+# - <0> pushmark sRM*/LVINTRO ->-
+# - <0> padsv[$a:1,4] lRM*/LVINTRO ->-
+# - <0> padsv[$b:1,4] lRM*/LVINTRO ->-
+# 4 <;> nextstate(main 2 p3:2) v ->5
+# 9 <2> aassign[t10] vKS ->a
+# - <1> ex-list lK ->8
+# 5 <0> pushmark s ->6
+# 7 <1> rv2av[t9] lK/1 ->8
+# 6 <#> gv[*X::_] s ->7
+# - <1> ex-list lKPRM* ->9
+# 8 <0> padrange[$c:2,4; $d:2,4] lRM/LVINTRO,2 ->9
+# - <0> padsv[$c:2,4] lRM*/LVINTRO ->-
+# - <0> padsv[$d:2,4] lRM*/LVINTRO ->-
+# a <;> nextstate(Y 3 p3:4) v:{ ->b
+# c <2> aassign[t15] KS ->d
+# - <1> ex-list lK ->-
+# b <0> padrange[$e:3,4; $f:3,4] l*/LVINTRO,2 ->c
+# - <1> rv2av[t14] lK/1 ->-
+# - <#> gv[*_] s ->-
+# - <1> ex-list lKPRM* ->c
+# - <0> pushmark sRM*/LVINTRO ->-
+# - <0> padsv[$e:3,4] lRM*/LVINTRO ->-
+# - <0> padsv[$f:3,4] lRM*/LVINTRO ->-
+EOT_EOT
+# d <1> leavesub[1 ref] K/REFC,1 ->(end)
+# - <@> lineseq KP ->d
+# 1 <;> nextstate(main 1 p3:1) v ->2
+# 3 <2> aassign[t5] vKS ->4
+# - <1> ex-list lK ->-
+# 2 <0> padrange[$a:1,4; $b:1,4] l*/LVINTRO,2 ->3
+# - <1> rv2av[t4] lK/1 ->-
+# - <$> gv(*_) s ->-
+# - <1> ex-list lKPRM* ->3
+# - <0> pushmark sRM*/LVINTRO ->-
+# - <0> padsv[$a:1,4] lRM*/LVINTRO ->-
+# - <0> padsv[$b:1,4] lRM*/LVINTRO ->-
+# 4 <;> nextstate(main 2 p3:2) v ->5
+# 9 <2> aassign[t10] vKS ->a
+# - <1> ex-list lK ->8
+# 5 <0> pushmark s ->6
+# 7 <1> rv2av[t9] lK/1 ->8
+# 6 <$> gv(*X::_) s ->7
+# - <1> ex-list lKPRM* ->9
+# 8 <0> padrange[$c:2,4; $d:2,4] lRM/LVINTRO,2 ->9
+# - <0> padsv[$c:2,4] lRM*/LVINTRO ->-
+# - <0> padsv[$d:2,4] lRM*/LVINTRO ->-
+# a <;> nextstate(Y 3 p3:4) v:{ ->b
+# c <2> aassign[t15] KS ->d
+# - <1> ex-list lK ->-
+# b <0> padrange[$e:3,4; $f:3,4] l*/LVINTRO,2 ->c
+# - <1> rv2av[t14] lK/1 ->-
+# - <$> gv(*_) s ->-
+# - <1> ex-list lKPRM* ->c
+# - <0> pushmark sRM*/LVINTRO ->-
+# - <0> padsv[$e:3,4] lRM*/LVINTRO ->-
+# - <0> padsv[$f:3,4] lRM*/LVINTRO ->-
+EONT_EONT
+
unlink $tmpfile;
U8 intro = 0;
PADOFFSET base = 0; /* init only to stop compiler whining */
U8 gimme = 0; /* init only to stop compiler whining */
-
- /* To allow Deparse to pessimise this, it needs to be able
- * to restore the pushmark's original op_next, which it
- * will assume to be the same as op_sibling. */
- if (o->op_next != o->op_sibling)
- break;
+ bool defav = 0; /* seen (...) = @_ */
+
+ /* look for a pushmark -> gv[_] -> rv2av */
+
+ {
+ GV *gv;
+ OP *rv2av, *q;
+ p = o->op_next;
+ if ( p->op_type == OP_GV
+ && (gv = cGVOPx_gv(p))
+ && GvNAMELEN_get(gv) == 1
+ && *GvNAME_get(gv) == '_'
+ && GvSTASH(gv) == PL_defstash
+ && (rv2av = p->op_next)
+ && rv2av->op_type == OP_RV2AV
+ && !(rv2av->op_flags & OPf_REF)
+ && !(rv2av->op_private & (OPpLVAL_INTRO|OPpMAYBE_LVSUB))
+ && ((rv2av->op_flags & OPf_WANT) == OPf_WANT_LIST)
+ && o->op_sibling == rv2av /* these two for Deparse */
+ && cUNOPx(rv2av)->op_first == p
+ ) {
+ q = rv2av->op_next;
+ if (q->op_type == OP_NULL)
+ q = q->op_next;
+ if (q->op_type == OP_PUSHMARK) {
+ defav = 1;
+ p = q;
+ }
+ }
+ }
+ if (!defav) {
+ /* To allow Deparse to pessimise this, it needs to be able
+ * to restore the pushmark's original op_next, which it
+ * will assume to be the same as op_sibling. */
+ if (o->op_next != o->op_sibling)
+ break;
+ p = o;
+ }
/* scan for PAD ops */
- for (p = o->op_next; p; p = p->op_next) {
+ for (p = p->op_next; p; p = p->op_next) {
if (p->op_type == OP_NULL)
continue;
o->op_targ = base;
/* bit 7: INTRO; bit 6..0: count */
o->op_private = (intro | count);
- o->op_flags = ((o->op_flags & ~OPf_WANT) | gimme);
+ o->op_flags = ((o->op_flags & ~(OPf_WANT|OPf_SPECIAL))
+ | gimme | (defav ? OPf_SPECIAL : 0));
break;
}
}
}
+/* push the elements of av onto the stack.
+ * XXX Note that padav has similar code but without the mg_get().
+ * I suspect that the mg_get is no longer needed, but while padav
+ * differs, it can't share this function */
+
+void
+S_pushav(pTHX_ AV* const av)
+{
+ dSP;
+ const I32 maxarg = AvFILL(av) + 1;
+ EXTEND(SP, maxarg);
+ if (SvRMAGICAL(av)) {
+ U32 i;
+ for (i=0; i < (U32)maxarg; i++) {
+ SV ** const svp = av_fetch(av, i, FALSE);
+ /* See note in pp_helem, and bug id #27839 */
+ SP[i+1] = svp
+ ? SvGMAGICAL(*svp) ? (mg_get(*svp), *svp) : *svp
+ : &PL_sv_undef;
+ }
+ }
+ else {
+ Copy(AvARRAY(av), SP+1, maxarg, SV*);
+ }
+ SP += maxarg;
+ PUTBACK;
+}
+
+
/* ($lex1,@lex2,...) or my ($lex1,@lex2,...) */
PP(pp_padrange)
PADOFFSET base = PL_op->op_targ;
int count = (int)(PL_op->op_private) & OPpPADRANGE_COUNTMASK;
int i;
+ if (PL_op->op_flags & OPf_SPECIAL) {
+ /* fake the RHS of my ($x,$y,..) = @_ */
+ PUSHMARK(SP);
+ S_pushav(aTHX_ GvAVn(PL_defgv));
+ SPAGAIN;
+ }
+
/* note, this is only skipped for compile-time-known void cxt */
if ((PL_op->op_flags & OPf_WANT) != OPf_WANT_VOID) {
EXTEND(SP, count);
(until such time as we get tools that can do blame annotation across
whitespace changes. */
if (gimme == G_ARRAY) {
- const I32 maxarg = AvFILL(av) + 1;
- (void)POPs; /* XXXX May be optimized away? */
- EXTEND(SP, maxarg);
- if (SvRMAGICAL(av)) {
- U32 i;
- for (i=0; i < (U32)maxarg; i++) {
- SV ** const svp = av_fetch(av, i, FALSE);
- /* See note in pp_helem, and bug id #27839 */
- SP[i+1] = svp
- ? SvGMAGICAL(*svp) ? (mg_get(*svp), *svp) : *svp
- : &PL_sv_undef;
- }
- }
- else {
- Copy(AvARRAY(av), SP+1, maxarg, SV*);
- }
- SP += maxarg;
+ SP--;
+ PUTBACK;
+ S_pushav(aTHX_ av);
+ SPAGAIN;
}
else if (gimme == G_SCALAR) {
dTARGET;