Open p5pRT opened 8 years ago
The following statement gets successfully parsed and executed by perl. Note that at the end of line 3 there is a '.' instead of a ';'\, i.e. the author of the code made obviously an error (based on real bug).
1 my $x = 1; 2 my $y = 'a'; 3 warn "foobar $y " . "foo " . 4 $x = 0;
> 0 at x.pl line 3.
If the code is modified so that the first concationation is skipped the behavior is completly different but actually the expected behavior (i.e. error):
1 my $x = 1; 2 my $y = 'a'; 3 warn "foobar $y foo " . 4 $x = 0;
> Can't modify concatenation (.) or string in scalar assignment at x.pl line 4\, near "0;" > Execution of x.pl aborted due to compilation errors.
The same behavior can be seen with assignments\, i.e.
my $z = "foobar $y " . "foo " . $x = 0; # works\, $z is 0 my $z = "foobar $y foo " . $x = 0; # error
It also works if the variable is outside the quotes or even if no quotes at all are used but an additional variable.
my $z = $x = 0; # works as expected my $z = $y.$x = 0; # fails as expected my $z = "".$y.$x = 0; # works unexpectedly my $z = $y."".$x = 0; # works unexpectedly my $z = $v.$y.$x = 0; # works unexpectedly
This behavior exists in a wide range of perl versions. I found it in perl 5.8.1 and it is still in the current blead perl 5.25.5.
On Thu\, Sep 08\, 2016 at 12:24:52PM -0700\, sullr@cpan.org wrote:
The same behavior can be seen with assignments\, i.e.
my $z = "foobar $y " . "foo " . $x = 0; # works\, $z is 0 my $z = "foobar $y foo " . $x = 0; # error
It can be reduced to the following difference:
(($x . "a") . "b") = 0; # compiles (bug) (($x + 1 ) + 2 ) = 0; # error (correct behaviour)
-- "Strange women lying in ponds distributing swords is no basis for a system of government. Supreme executive power derives from a mandate from the masses\, not from some farcical aquatic ceremony." -- Dennis\, "Monty Python and the Holy Grail"
The RT System itself - Status changed from 'new' to 'open'
Dave Mitchell wrote:
It can be reduced to the following difference:
(($x . "a") . "b") = 0; # compiles (bug) (($x + 1 ) + 2 ) = 0; # error (correct behaviour)
Where a concat op has a lhs that is another concat op\, ck_concat sets the OPf_STACKED flag on the outer concat. Addition doesn't get that treatment. It seems that the flag is intended as a signal to the peephole optimiser\, where it suppresses an optimisation that I can't make sense of. But op_lvalue_flags() also looks at OPf_STACKED\, for concat\, add\, and many other non-lvalue op types\, and quite explicitly suppresses the "can't modify" error if it's set. Presumably there's something else that I haven't identified that sets the flag on these ops in some situation that makes them an acceptable lvalue. The two uses of the flag are interfering with each other. Neither is the standard meaning of the flag\, and neither is described in the comment in op.h that describes the flag.
-zefram
On Fri Sep 09 03:47:58 2016\, zefram@fysh.org wrote:
Dave Mitchell wrote:
It can be reduced to the following difference:
(($x . "a") . "b") = 0; # compiles (bug) (($x + 1 ) + 2 ) = 0; # error (correct behaviour)
Where a concat op has a lhs that is another concat op\, ck_concat sets the OPf_STACKED flag on the outer concat. Addition doesn't get that treatment.
$a.$b.$c is optimised to ($a.$b).=$c to avoid having to copy the value returned by $a.$b to a new temporary scalar to be returned by $c.
It seems that the flag is intended as a signal to the peephole optimiser\, where it suppresses an optimisation that I can't make sense of.
It seems that the ($a.$b).=$c optimisation can interfere in some cases with the removal of the stringify op in "$a$b$c" in some circumstances involving lexical scalar assignment. I don’t understand why though. That checking of the flag in the peephole optimizer is not directly related to this bug.
But op_lvalue_flags() also looks at OPf_STACKED\, for concat\, add\, and many other non-lvalue op types\, and quite explicitly suppresses the "can't modify" error if it's set. Presumably there's something else that I haven't identified that sets the flag on these ops in some situation that makes them an acceptable lvalue.
All the assignment versions of binary ops\, .= += -= etc.\, have the OPf_STACKED flag set.
--
Father Chrysostomos
Migrated from rt.perl.org#129233 (status was 'open')
Searchable as RT129233$