diff options
author | David Mitchell <davem@iabyn.com> | 2022-04-16 11:48:20 +0100 |
---|---|---|
committer | David Mitchell <davem@iabyn.com> | 2022-04-16 18:22:13 +0100 |
commit | f8245cd9653db9b3e3fef57c3913d9deb33972b2 (patch) | |
tree | 754659507371a9a12f8f2a20cbf2a8b814e281a2 /lib/B | |
parent | 55d95e1b172db3fff30c261b7b7ea9e0bca8328a (diff) | |
download | perl-f8245cd9653db9b3e3fef57c3913d9deb33972b2.tar.gz |
for my ($x) ...: fix handling of degenerate 1-var
The new
for my ($x,$y,...) (...) { ... }
syntax has a couple of problems in the degenerate case of a single
variable:
for my ($x) (...) { ... }
First, the loop variable is marked as lexical, but not as a variable
to be introduced. So it behaves roughly as if written like:
{ my $x; for $x (...) { ... } }
I can't think of any user-visible runtime change in behaviour this bug
causes, so I haven't included a test for it.
Second, it was being incorrectly deparsed as
for $x (...) { ... }
(i.e. without the 'my').
This commit fixes both of these issues.
The basic problem is that the parser, in the case of multiple vars,
passes a list subtree of PADSVs as the 'sv' argument of Perl_newFOROP,
but in the case of a single var, passes a single PADSV op instead.
This single PADSV doesn't have the LVINTRO flag set, so is
indistinguishable from plain
my $x; for $x ....
This commit makes the parser set the OPf_PARENS flag on the lone PADSV
to signal to newFOROP() that it's a degenerate 1-var list, and
newFOROP() sets the OPf_PARENS flag on the ENTERITER op to signal to the
deparser that this is "for my (...)" syntax, even if it only has a
single var.
Diffstat (limited to 'lib/B')
-rw-r--r-- | lib/B/Deparse.pm | 9 |
1 files changed, 6 insertions, 3 deletions
diff --git a/lib/B/Deparse.pm b/lib/B/Deparse.pm index b50608ca86..bdf3b3961f 100644 --- a/lib/B/Deparse.pm +++ b/lib/B/Deparse.pm @@ -3978,10 +3978,13 @@ sub loop_common { } else { $ary = $self->deparse($ary, 1); } - my $iter_targ = $kid->first->first->targ; - if ($iter_targ) { + + if ($enter->flags & OPf_PARENS) { + # for my ($x, $y, ...) ... # for my ($foo, $bar) () stores the count (less 1) in the targ of - # the ITER op. + # the ITER op. For the degenerate case of 1 var ($x), the + # TARG is zero, so it works anyway + my $iter_targ = $kid->first->first->targ; my @vars; my $targ = $enter->targ; while ($iter_targ-- >= 0) { |